summaryrefslogtreecommitdiffstats
path: root/sys-kernel/boest-v5.0.15/raspberrypi/0037-Add-dwc_otg-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/boest-v5.0.15/raspberrypi/0037-Add-dwc_otg-driver.patch')
-rw-r--r--sys-kernel/boest-v5.0.15/raspberrypi/0037-Add-dwc_otg-driver.patch61396
1 files changed, 61396 insertions, 0 deletions
diff --git a/sys-kernel/boest-v5.0.15/raspberrypi/0037-Add-dwc_otg-driver.patch b/sys-kernel/boest-v5.0.15/raspberrypi/0037-Add-dwc_otg-driver.patch
new file mode 100644
index 00000000..5c284bd8
--- /dev/null
+++ b/sys-kernel/boest-v5.0.15/raspberrypi/0037-Add-dwc_otg-driver.patch
@@ -0,0 +1,61396 @@
+From 946e8b329df5034122e2f7103a2a6b7ad201edfb Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 1 May 2013 19:46:17 +0100
+Subject: [PATCH 037/194] Add dwc_otg driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+usb: dwc: fix lockdep false positive
+
+Signed-off-by: Kari Suvanto <karis79@gmail.com>
+
+usb: dwc: fix inconsistent lock state
+
+Signed-off-by: Kari Suvanto <karis79@gmail.com>
+
+Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance.
+Thanks to Gordon and Costas
+
+Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005.
+
+Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh
+
+Make sure we wait for the reset to finish
+
+dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel
+ memory corruption, escalating to OOPS under high USB load.
+
+dwc_otg: Fix unsafe access of QTD during URB enqueue
+
+In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the
+transaction could complete almost immediately after the qtd was assigned
+to a host channel during URB enqueue, which meant the qtd pointer was no
+longer valid having been completed and removed. Usually, this resulted in
+an OOPS during URB submission. By predetermining whether transactions
+need to be queued or not, this unsafe pointer access is avoided.
+
+This bug was only evident on the Pi model A where a device was attached
+that had no periodic endpoints (e.g. USB pendrive or some wlan devices).
+
+dwc_otg: Fix incorrect URB allocation error handling
+
+If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS
+because for some reason a member of the *unallocated* struct was set to
+zero. Error handling changed to fail correctly.
+
+dwc_otg: fix potential use-after-free case in interrupt handler
+
+If a transaction had previously aborted, certain interrupts are
+enabled to track error counts and reset where necessary. On IN
+endpoints the host generates an ACK interrupt near-simultaneously
+with completion of transfer. In the case where this transfer had
+previously had an error, this results in a use-after-free on
+the QTD memory space with a 1-byte length being overwritten to
+0x00.
+
+dwc_otg: add handling of SPLIT transaction data toggle errors
+
+Previously a data toggle error on packets from a USB1.1 device behind
+a TT would result in the Pi locking up as the driver never handled
+the associated interrupt. Patch adds basic retry mechanism and
+interrupt acknowledgement to cater for either a chance toggle error or
+for devices that have a broken initial toggle state (FT8U232/FT232BM).
+
+dwc_otg: implement tasklet for returning URBs to usbcore hcd layer
+
+The dwc_otg driver interrupt handler for transfer completion will spend
+a very long time with interrupts disabled when a URB is completed -
+this is because usb_hcd_giveback_urb is called from within the handler
+which for a USB device driver with complicated processing (e.g. webcam)
+will take an exorbitant amount of time to complete. This results in
+missed completion interrupts for other USB packets which lead to them
+being dropped due to microframe overruns.
+
+This patch splits returning the URB to the usb hcd layer into a
+high-priority tasklet. This will have most benefit for isochronous IN
+transfers but will also have incidental benefit where multiple periodic
+devices are active at once.
+
+dwc_otg: fix NAK holdoff and allow on split transactions only
+
+This corrects a bug where if a single active non-periodic endpoint
+had at least one transaction in its qh, on frnum == MAX_FRNUM the qh
+would get skipped and never get queued again. This would result in
+a silent device until error detection (automatic or otherwise) would
+either reset the device or flush and requeue the URBs.
+
+Additionally the NAK holdoff was enabled for all transactions - this
+would potentially stall a HS endpoint for 1ms if a previous error state
+enabled this interrupt and the next response was a NAK. Fix so that
+only split transactions get held off.
+
+dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler
+
+usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it
+asynchronously in the tasklet was not safe (regression in
+c4564d4a1a0a9b10d4419e48239f5d99e88d2667).
+
+This change unlinks it from the endpoint prior to queueing it for handling in
+the tasklet, and also adds a check to ensure the urb is OK to be unlinked
+before doing so.
+
+NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb
+when a USB device was unplugged/replugged during data transfer. This effect
+was reproduced using automated USB port power control, hundreds of replug
+events were performed during active transfers to confirm that the problem was
+eliminated.
+
+USB fix using a FIQ to implement split transactions
+
+This commit adds a FIQ implementaion that schedules
+the split transactions using a FIQ so we don't get
+held off by the interrupt latency of Linux
+
+dwc_otg: fix device attributes and avoid kernel warnings on boot
+
+dcw_otg: avoid logging function that can cause panics
+
+See: https://github.com/raspberrypi/firmware/issues/21
+Thanks to cleverca22 for fix
+
+dwc_otg: mask correct interrupts after transaction error recovery
+
+The dwc_otg driver will unmask certain interrupts on a transaction
+that previously halted in the error state in order to reset the
+QTD error count. The various fine-grained interrupt handlers do not
+consider that other interrupts besides themselves were unmasked.
+
+By disabling the two other interrupts only ever enabled in DMA mode
+for this purpose, we can avoid unnecessary function calls in the
+IRQ handler. This will also prevent an unneccesary FIQ interrupt
+from being generated if the FIQ is enabled.
+
+dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ
+
+In the case of a transaction to a device that had previously aborted
+due to an error, several interrupts are enabled to reset the error
+count when a device responds. This has the side-effect of making the
+FIQ thrash because the hardware will generate multiple instances of
+a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK
+on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the
+associated interrupts.
+
+Additionally, on non-split transactions make sure that only unmasked
+interrupts are cleared. This caused a hard-to-trigger but serious
+race condition when you had the combination of an endpoint awaiting
+error recovery and a transaction completed on an endpoint - due to
+the sequencing and timing of interrupts generated by the dwc_otg core,
+it was possible to confuse the IRQ handler.
+
+Fix function tracing
+
+dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue
+
+dwc_otg: prevent OOPSes during device disconnects
+
+The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
+access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
+friends does not occur within a critical section and so if a device
+was unplugged during activity there was a high chance that the
+usbcore hub_thread would try to disable the endpoint with partially-
+formed entries in the URB queue. This would result in BUG() or null
+pointer dereferences.
+
+Fix so that access of urb->hcpriv, enqueuing to the hardware and
+adding to usbcore endpoint URB lists is contained within a single
+critical section.
+
+dwc_otg: prevent BUG() in TT allocation if hub address is > 16
+
+A fixed-size array is used to track TT allocation. This was
+previously set to 16 which caused a crash because
+dwc_otg_hcd_allocate_port would read past the end of the array.
+
+This was hit if a hub was plugged in which enumerated as addr > 16,
+due to previous device resets or unplugs.
+
+Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows
+to a large size if 128 hub addresses are supported. This field is
+for debug only for tracking which frame an allocate happened in.
+
+dwc_otg: make channel halts with unknown state less damaging
+
+If the IRQ received a channel halt interrupt through the FIQ
+with no other bits set, the IRQ would not release the host
+channel and never complete the URB.
+
+Add catchall handling to treat as a transaction error and retry.
+
+dwc_otg: fiq_split: use TTs with more granularity
+
+This fixes certain issues with split transaction scheduling.
+
+- Isochronous multi-packet OUT transactions now hog the TT until
+ they are completed - this prevents hubs aborting transactions
+ if they get a periodic start-split out-of-order
+- Don't perform TT allocation on non-periodic endpoints - this
+ allows simultaneous use of the TT's bulk/control and periodic
+ transaction buffers
+
+This commit will mainly affect USB audio playback.
+
+dwc_otg: fix potential sleep while atomic during urb enqueue
+
+Fixes a regression introduced with eb1b482a. Kmalloc called from
+dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have
+the GPF_ATOMIC flag set. Force this flag when inside the larger
+critical section.
+
+dwc_otg: make fiq_split_enable imply fiq_fix_enable
+
+Failing to set up the FIQ correctly would result in
+"IRQ 32: nobody cared" errors in dmesg.
+
+dwc_otg: prevent crashes on host port disconnects
+
+Fix several issues resulting in crashes or inconsistent state
+if a Model A root port was disconnected.
+
+- Clean up queue heads properly in kill_urbs_in_qh_list by
+ removing the empty QHs from the schedule lists
+- Set the halt status properly to prevent IRQ handlers from
+ using freed memory
+- Add fiq_split related cleanup for saved registers
+- Make microframe scheduling reclaim host channels if
+ active during a disconnect
+- Abort URBs with -ESHUTDOWN status response, informing
+ device drivers so they respond in a more correct fashion
+ and don't try to resubmit URBs
+- Prevent IRQ handlers from attempting to handle channel
+ interrupts if the associated URB was dequeued (and the
+ driver state was cleared)
+
+dwc_otg: prevent leaking URBs during enqueue
+
+A dwc_otg_urb would get leaked if the HCD enqueue function
+failed for any reason. Free the URB at the appropriate points.
+
+dwc_otg: Enable NAK holdoff for control split transactions
+
+Certain low-speed devices take a very long time to complete a
+data or status stage of a control transaction, producing NAK
+responses until they complete internal processing - the USB2.0
+spec limit is up to 500mS. This causes the same type of interrupt
+storm as seen with USB-serial dongles prior to c8edb238.
+
+In certain circumstances, usually while booting, this interrupt
+storm could cause SD card timeouts.
+
+dwc_otg: Fix for occasional lockup on boot when doing a USB reset
+
+dwc_otg: Don't issue traffic to LS devices in FS mode
+
+Issuing low-speed packets when the root port is in full-speed mode
+causes the root port to stop responding. Explicitly fail when
+enqueuing URBs to a LS endpoint on a FS bus.
+
+Fix ARM architecture issue with local_irq_restore()
+
+If local_fiq_enable() is called before a local_irq_restore(flags) where
+the flags variable has the F bit set, the FIQ will be erroneously disabled.
+
+Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR.
+
+Also fix some of the hacks previously implemented for previous dwc_otg
+incarnations.
+
+dwc_otg: fiq_fsm: Base commit for driver rewrite
+
+This commit removes the previous FIQ fixes entirely and adds fiq_fsm.
+
+This rewrite features much more complete support for split transactions
+and takes into account several OTG hardware bugs. High-speed
+isochronous transactions are also capable of being performed by fiq_fsm.
+
+All driver options have been removed and replaced with:
+ - dwc_otg.fiq_enable (bool)
+ - dwc_otg.fiq_fsm_enable (bool)
+ - dwc_otg.fiq_fsm_mask (bitmask)
+ - dwc_otg.nak_holdoff (unsigned int)
+
+Defaults are specified such that fiq_fsm behaves similarly to the
+previously implemented FIQ fixes.
+
+fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used
+
+If the transfer associated with a QTD failed due to a bus error, the HCD
+would retry the transfer up to 3 times (implementing the USB2.0
+three-strikes retry in software).
+
+Due to the masking mechanism used by fiq_fsm, it is only possible to pass
+a single interrupt through to the HCD per-transfer.
+
+In this instance host channels would fall off the radar because the error
+reset would function, but the subsequent channel halt would be lost.
+
+Push the error count reset into the FIQ handler.
+
+fiq_fsm: Implement timeout mechanism
+
+For full-speed endpoints with a large packet size, interrupt latency
+runs the risk of the FIQ starting a transaction too late in a full-speed
+frame. If the device is still transmitting data when EOF2 for the
+downstream frame occurs, the hub will disable the port. This change is
+not reflected in the hub status endpoint and the device becomes
+unresponsive.
+
+Prevent high-bandwidth transactions from being started too late in a
+frame. The mechanism is not guaranteed: a combination of bit stuffing
+and hub latency may still result in a device overrunning.
+
+fiq_fsm: fix bounce buffer utilisation for Isochronous OUT
+
+Multi-packet isochronous OUT transactions were subject to a few bounday
+bugs. Fix them.
+
+Audio playback is now much more robust: however, an issue stands with
+devices that have adaptive sinks - ALSA plays samples too fast.
+
+dwc_otg: Return full-speed frame numbers in HS mode
+
+The frame counter increments on every *microframe* in high-speed mode.
+Most device drivers expect this number to be in full-speed frames - this
+caused considerable confusion to e.g. snd_usb_audio which uses the
+frame counter to estimate the number of samples played.
+
+fiq_fsm: save PID on completion of interrupt OUT transfers
+
+Also add edge case handling for interrupt transports.
+
+Note that for periodic split IN, data toggles are unimplemented in the
+OTG host hardware - it unconditionally accepts any PID.
+
+fiq_fsm: add missing case for fiq_fsm_tt_in_use()
+
+Certain combinations of bitrate and endpoint activity could
+result in a periodic transaction erroneously getting started
+while the previous Isochronous OUT was still active.
+
+fiq_fsm: clear hcintmsk for aborted transactions
+
+Prevents the FIQ from erroneously handling interrupts
+on a timed out channel.
+
+fiq_fsm: enable by default
+
+fiq_fsm: fix dequeues for non-periodic split transactions
+
+If a dequeue happened between the SSPLIT and CSPLIT phases of the
+transaction, the HCD would never receive an interrupt.
+
+fiq_fsm: Disable by default
+
+fiq_fsm: Handle HC babble errors
+
+The HCTSIZ transfer size field raises a babble interrupt if
+the counter wraps. Handle the resulting interrupt in this case.
+
+dwc_otg: fix interrupt registration for fiq_enable=0
+
+Additionally make the module parameter conditional for wherever
+hcd->fiq_state is touched.
+
+fiq_fsm: Enable by default
+
+dwc_otg: Fix various issues with root port and transaction errors
+
+Process the host port interrupts correctly (and don't trample them).
+Root port hotplug now functional again.
+
+Fix a few thinkos with the transaction error passthrough for fiq_fsm.
+
+fiq_fsm: Implement hack for Split Interrupt transactions
+
+Hubs aren't too picky about which endpoint we send Control type split
+transactions to. By treating Interrupt transfers as Control, it is
+possible to use the non-periodic queue in the OTG core as well as the
+non-periodic FIFOs in the hub itself. This massively reduces the
+microframe exclusivity/contention that periodic split transactions
+otherwise have to enforce.
+
+It goes without saying that this is a fairly egregious USB specification
+violation, but it works.
+
+Original idea by Hans Petter Selasky @ FreeBSD.org.
+
+dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only.
+
+dwc_otg: introduce fiq_fsm_spin(un|)lock()
+
+SMP safety for the FIQ relies on register read-modify write cycles being
+completed in the correct order. Several places in the DWC code modify
+registers also touched by the FIQ. Protect these by a bare-bones lock
+mechanism.
+
+This also makes it possible to run the FIQ and IRQ handlers on different
+cores.
+
+fiq_fsm: fix build on bcm2708 and bcm2709 platforms
+
+dwc_otg: put some barriers back where they should be for UP
+
+bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active
+
+dwc_otg: fixup read-modify-write in critical paths
+
+Be more careful about read-modify-write on registers that the FIQ
+also touches.
+
+Guard fiq_fsm_spin_lock with fiq_enable check
+
+fiq_fsm: Falling out of the state machine isn't fatal
+
+This edge case can be hit if the port is disabled while the FIQ is
+in the middle of a transaction. Make the effects less severe.
+
+Also get rid of the useless return value.
+
+squash: dwc_otg: Allow to build without SMP
+
+usb: core: make overcurrent messages more prominent
+
+Hub overcurrent messages are more serious than "debug". Increase loglevel.
+
+usb: dwc_otg: Don't use dma_to_virt()
+
+Commit 6ce0d20 changes dma_to_virt() which breaks this driver.
+Open code the old dma_to_virt() implementation to work around this.
+
+Limit the use of __bus_to_virt() to cases where transfer_buffer_length
+is set and transfer_buffer is not set. This is done to increase the
+chance that this driver will also work on ARCH_BCM2835.
+
+transfer_buffer should not be NULL if the length is set, but the
+comment in the code indicates that there are situations where this
+might happen. drivers/usb/isp1760/isp1760-hcd.c also has a similar
+comment pointing to a possible: 'usb storage / SCSI bug'.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Fix crash when fiq_enable=0
+
+dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly
+
+Certain low-bandwidth high-speed USB devices (specialist audio devices,
+compressed-frame webcams) have packet intervals > 1 microframe.
+
+Stride these transfers in the FIQ by using the start-of-frame interrupt
+to restart the channel at the right time.
+
+dwc_otg: Force host mode to fix incorrect compute module boards
+
+dwc_otg: Add ARCH_BCM2835 support
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Simplify FIQ irq number code
+
+Dropping ATAGS means we can simplify the FIQ irq number code.
+Also add error checking on the returned irq number.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Remove duplicate gadget probe/unregister function
+
+dwc_otg: Properly set the HFIR
+
+Douglas Anderson reported:
+
+According to the most up to date version of the dwc2 databook, the FRINT
+field of the HFIR register should be programmed to:
+* 125 us * (PHY clock freq for HS) - 1
+* 1000 us * (PHY clock freq for FS/LS) - 1
+
+This is opposed to older versions of the doc that claimed it should be:
+* 125 us * (PHY clock freq for HS)
+* 1000 us * (PHY clock freq for FS/LS)
+
+and reported lower timing jitter on a USB analyser
+
+dcw_otg: trim xfer length when buffer larger than allocated size is received
+
+dwc_otg: Don't free qh align buffers in atomic context
+
+dwc_otg: Enable the hack for Split Interrupt transactions by default
+
+dwc_otg.fiq_fsm_mask=0xF has long been a suggestion for users with audio stutters or other USB bandwidth issues.
+So far we are aware of many success stories but no failure caused by this setting.
+Make it a default to learn more.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=70437
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+dwc_otg: Use kzalloc when suitable
+
+dwc_otg: Pass struct device to dma_alloc*()
+
+This makes it possible to get the bus address from Device Tree.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: fix summarize urb->actual_length for isochronous transfers
+
+Kernel does not copy input data of ISO transfers to userspace
+if actual_length is set only in ISO transfers and not summarized
+in urb->actual_length. Fixes raspberrypi/linux#903
+
+fiq_fsm: Use correct states when starting isoc OUT transfers
+
+In fiq_fsm_start_next_periodic() if an isochronous OUT transfer
+was selected, no regard was given as to whether this was a single-packet
+transfer or a multi-packet staged transfer.
+
+For single-packet transfers, this had the effect of repeatedly sending
+OUT packets with bogus data and lengths.
+
+Eventually if the channel was repeatedly enabled enough times, this
+would lock up the OTG core and no further bus transfers would happen.
+
+Set the FSM state up properly if we select a single-packet transfer.
+
+Fixes https://github.com/raspberrypi/linux/issues/1842
+
+dwc_otg: make nak_holdoff work as intended with empty queues
+
+If URBs reading from non-periodic split endpoints were dequeued and
+the last transfer from the endpoint was a NAK handshake, the resulting
+qh->nak_frame value was stale which would result in unnecessarily long
+polling intervals for the first subsequent transfer with a fresh URB.
+
+Fixup qh->nak_frame in dwc_otg_hcd_urb_dequeue and also guard against
+a case where a single URB is submitted to the endpoint, a NAK was
+received on the transfer immediately prior to receiving data and the
+device subsequently resubmits another URB past the qh->nak_frame interval.
+
+Fixes https://github.com/raspberrypi/linux/issues/1709
+
+dwc_otg: fix split transaction data toggle handling around dequeues
+
+See https://github.com/raspberrypi/linux/issues/1709
+
+Fix several issues regarding endpoint state when URBs are dequeued
+- If the HCD is disconnected, flush FIQ-enabled channels properly
+- Save the data toggle state for bulk endpoints if the last transfer
+ from an endpoint where URBs were dequeued returned a data packet
+- Reset hc->start_pkt_count properly in assign_and_init_hc()
+
+dwc_otg: fix several potential crash sources
+
+On root port disconnect events, the host driver state is cleared and
+in-progress host channels are forcibly stopped. This doesn't play
+well with the FIQ running in the background, so:
+- Guard the disconnect callback with both the host spinlock and FIQ
+ spinlock
+- Move qtd dereference in dwc_otg_handle_hc_fsm() after the early-out
+ so we don't dereference a qtd that has gone away
+- Turn catch-all BUG()s in dwc_otg_handle_hc_fsm() into warnings.
+
+dwc_otg: delete hcd->channel_lock
+
+The lock serves no purpose as it is only held while the HCD spinlock
+is already being held.
+
+dwc_otg: remove unnecessary dma-mode channel halts on disconnect interrupt
+
+Host channels are already halted in kill_urbs_in_qh_list() with the
+subsequent interrupt processing behaving as if the URB was dequeued
+via HCD callback.
+
+There's no need to clobber the host channel registers a second time
+as this exposes races between the driver and host channel resulting
+in hcd->free_hc_list becoming corrupted.
+
+dwcotg: Allow to build without FIQ on ARM64
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+dwc_otg: make periodic scheduling behave properly for FS buses
+
+If the root port is in full-speed mode, transfer times at 12mbit/s
+would be calculated but matched against high-speed quotas.
+
+Reinitialise hcd->frame_usecs[i] on each port enable event so that
+full-speed bandwidth can be tracked sensibly.
+
+Also, don't bother using the FIQ for transfers when in full-speed
+mode - at the slower bus speed, interrupt frequency is reduced by
+an order of magnitude.
+
+Related issue: https://github.com/raspberrypi/linux/issues/2020
+
+dwc_otg: fiq_fsm: Make isochronous compatibility checks work properly
+
+Get rid of the spammy printk and local pointer mangling.
+Also, there is a nominal benefit for using fiq_fsm for isochronous
+transfers in FS mode (~1.1k IRQs per second vs 2.1k IRQs per second)
+so remove the root port speed check.
+
+dwc_otg: add module parameter int_ep_interval_min
+
+Add a module parameter (defaulting to ignored) that clamps the polling rate
+of high-speed Interrupt endpoints to a minimum microframe interval.
+
+The parameter is modifiable at runtime as it is used when activating new
+endpoints (such as on device connect).
+
+dwc_otg: fiq_fsm: Add non-periodic TT exclusivity constraints
+
+Certain hub types do not discriminate between pipe direction (IN or OUT)
+when considering non-periodic transfers. Therefore these hubs get confused
+if multiple transfers are issued in different directions with the same
+device address and endpoint number.
+
+Constrain queuing non-periodic split transactions so they are performed
+serially in such cases.
+
+Related: https://github.com/raspberrypi/linux/issues/2024
+
+dwc_otg: Fixup change to DRIVER_ATTR interface
+
+dwc_otg: Fix compilation warnings
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+
+USB_DWCOTG: Disable building dwc_otg as a module (#2265)
+
+When dwc_otg is built as a module, build will fail with the following
+error:
+
+ERROR: "DWC_TASK_HI_SCHEDULE" [drivers/usb/host/dwc_otg/dwc_otg.ko] undefined!
+scripts/Makefile.modpost:91: recipe for target '__modpost' failed
+make[1]: *** [__modpost] Error 1
+Makefile:1199: recipe for target 'modules' failed
+make: *** [modules] Error 2
+
+Even if the error is solved by including the missing
+DWC_TASK_HI_SCHEDULE function, the kernel will panic when loading
+dwc_otg.
+
+As a workaround, simply prevent user from building dwc_otg as a module
+as the current kernel does not support it.
+
+See: https://github.com/raspberrypi/linux/issues/2258
+
+Signed-off-by: Malik Olivier Boussejra <malik@boussejra.com>
+
+dwc_otg: New timer API
+
+dwc_otg: Fix removed ACCESS_ONCE->READ_ONCE
+
+dwc_otg: don't unconditionally force host mode in dwc_otg_cil_init()
+
+Add the ability to disable force_host_mode for those that want to use
+dwc_otg in both device and host modes.
+
+dwc_otg: Fix a regression when dequeueing isochronous transfers
+
+In 282bed95 (dwc_otg: make nak_holdoff work as intended with empty queues)
+the dequeue mechanism was changed to leave FIQ-enabled transfers to run
+to completion - to avoid leaving hub TT buffers with stale packets lying
+around.
+
+This broke FIQ-accelerated isochronous transfers, as this then meant that
+dozens of transfers were performed after the dequeue function returned.
+
+Restore the state machine fence for isochronous transfers.
+
+fiq_fsm: rewind DMA pointer for OUT transactions that fail (#2288)
+
+See: https://github.com/raspberrypi/linux/issues/2140
+
+dwc_otg: add smp_mb() to prevent driver state corruption on boot
+
+Occasional crashes have been seen where the FIQ code dereferences
+invalid/random pointers immediately after being set up, leading to
+panic on boot.
+
+The crash occurs as the FIQ code races against hcd_init_fiq() and
+the hcd_init_fiq() code races against the outstanding memory stores
+from dwc_otg_hcd_init(). Use explicit barriers after touching
+driver state.
+
+usb: dwc_otg: fix memory corruption in dwc_otg driver
+
+[Upstream commit 51b1b6491752ac066ee8d32cc66042fcc955fef6]
+
+The move from the staging tree to the main tree exposed a
+longstanding memory corruption bug in the dwc2 driver. The
+reordering of the driver initialization caused the dwc2 driver
+to corrupt the initialization data of the sdhci driver on the
+Raspberry Pi platform, which made the bug show up.
+
+The error is in calling to_usb_device(hsotg->dev), since ->dev
+is not a member of struct usb_device. The easiest fix is to
+just remove the offending code, since it is not really needed.
+
+Thanks to Stephen Warren for tracking down the cause of this.
+
+Reported-by: Andre Heider <a.heider@gmail.com>
+Tested-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Paul Zimmerman <paulz@synopsys.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[lukas: port from upstream dwc2 to out-of-tree dwc_otg driver]
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+
+usb: dwb_otg: Fix unreachable switch statement warning
+
+This warning appears with GCC 7.3.0 from toolchains.bootlin.com:
+
+../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c: In function ‘fiq_fsm_update_hs_isoc’:
+../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c:595:61: warning: statement will never be executed [-Wswitch-unreachable]
+ st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps;
+ ~~~~~~~~~~~~~~~~~^~~~
+
+Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
+
+dwc_otg: fiq_fsm: fix incorrect DMA register offset calculation
+
+Rationalise the offset and update all call sites.
+
+Fixes https://github.com/raspberrypi/linux/issues/2408
+
+dwc_otg: fix bug with port_addr assignment for single-TT hubs
+
+See https://github.com/raspberrypi/linux/issues/2734
+
+The "Hub Port" field in the split transaction packet was always set
+to 1 for single-TT hubs. The majority of single-TT hub products
+apparently ignore this field and broadcast to all downstream enabled
+ports, which masked the issue. A subset of hub devices apparently
+need the port number to be exact or split transactions will fail.
+
+usb: dwc_otg: Clean up build warnings on 64bit kernels
+
+No functional changes. Almost all are changes to logging lines.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+
+usb: dwc_otg: Use dma allocation for mphi dummy_send buffer
+
+The FIQ driver used a kzalloc'ed buffer for dummy_send,
+passing a kernel virtual address to the hardware block.
+The buffer is only ever used for a dummy read, so it
+should be harmless, but there is the chance that it will
+cause exceptions.
+
+Use a dma allocation so that we have a genuine bus address,
+and read from that.
+Free the allocation when done for good measure.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+
+dwc_otg: only do_split when we actually need to do a split
+
+The previous test would fail if the root port was in fullspeed mode
+and there was a hub between the FS device and the root port. While
+the transfer worked, the schedule mangling performed for high-speed
+split transfers would break leading to an 8ms polling interval.
+
+dwc_otg: fix locking around dequeueing and killing URBs
+
+kill_urbs_in_qh_list() is practically only ever called with the fiq lock
+already held, so don't spinlock twice in the case where we need to cancel
+an isochronous transfer.
+
+Also fix up a case where the global interrupt register could be read with
+the fiq lock not held.
+
+Fixes the deadlock seen in https://github.com/raspberrypi/linux/issues/2907
+---
+ arch/arm/include/asm/irqflags.h | 16 +-
+ arch/arm/kernel/fiqasm.S | 4 +
+ drivers/usb/Makefile | 1 +
+ drivers/usb/core/generic.c | 1 +
+ drivers/usb/core/hub.c | 2 +-
+ drivers/usb/core/message.c | 79 +
+ drivers/usb/core/otg_whitelist.h | 114 +-
+ drivers/usb/gadget/file_storage.c | 3676 +++++++++
+ drivers/usb/host/Kconfig | 10 +
+ drivers/usb/host/Makefile | 2 +
+ drivers/usb/host/dwc_common_port/Makefile | 58 +
+ .../usb/host/dwc_common_port/Makefile.fbsd | 17 +
+ .../usb/host/dwc_common_port/Makefile.linux | 49 +
+ drivers/usb/host/dwc_common_port/changes.txt | 174 +
+ .../usb/host/dwc_common_port/doc/doxygen.cfg | 270 +
+ drivers/usb/host/dwc_common_port/dwc_cc.c | 532 ++
+ drivers/usb/host/dwc_common_port/dwc_cc.h | 224 +
+ .../host/dwc_common_port/dwc_common_fbsd.c | 1308 +++
+ .../host/dwc_common_port/dwc_common_linux.c | 1409 ++++
+ .../host/dwc_common_port/dwc_common_nbsd.c | 1275 +++
+ drivers/usb/host/dwc_common_port/dwc_crypto.c | 308 +
+ drivers/usb/host/dwc_common_port/dwc_crypto.h | 111 +
+ drivers/usb/host/dwc_common_port/dwc_dh.c | 291 +
+ drivers/usb/host/dwc_common_port/dwc_dh.h | 106 +
+ drivers/usb/host/dwc_common_port/dwc_list.h | 594 ++
+ drivers/usb/host/dwc_common_port/dwc_mem.c | 245 +
+ drivers/usb/host/dwc_common_port/dwc_modpow.c | 636 ++
+ drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 +
+ .../usb/host/dwc_common_port/dwc_notifier.c | 319 +
+ .../usb/host/dwc_common_port/dwc_notifier.h | 122 +
+ drivers/usb/host/dwc_common_port/dwc_os.h | 1276 +++
+ drivers/usb/host/dwc_common_port/usb.h | 946 +++
+ drivers/usb/host/dwc_otg/Makefile | 82 +
+ drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 +
+ drivers/usb/host/dwc_otg/dummy_audio.c | 1574 ++++
+ drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 +
+ drivers/usb/host/dwc_otg/dwc_otg_adp.c | 854 ++
+ drivers/usb/host/dwc_otg/dwc_otg_adp.h | 80 +
+ drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1212 +++
+ drivers/usb/host/dwc_otg/dwc_otg_attr.h | 89 +
+ drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 320 +
+ drivers/usb/host/dwc_otg/dwc_otg_cil.c | 7146 +++++++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1464 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 1601 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 705 ++
+ drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 117 +
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1766 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1401 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 373 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 80 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4305 ++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 870 ++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1134 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 417 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2752 +++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 1000 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 970 +++
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 188 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2725 +++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 273 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 361 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 5148 ++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1280 +++
+ drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2550 ++++++
+ drivers/usb/host/dwc_otg/test/Makefile | 16 +
+ drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 +
+ .../usb/host/dwc_otg/test/test_mod_param.pl | 133 +
+ drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 +
+ 70 files changed, 60037 insertions(+), 16 deletions(-)
+
+diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
+index aeec7f24eb75..a3b186608c60 100644
+--- a/arch/arm/include/asm/irqflags.h
++++ b/arch/arm/include/asm/irqflags.h
+@@ -163,13 +163,23 @@ static inline unsigned long arch_local_save_flags(void)
+ }
+
+ /*
+- * restore saved IRQ & FIQ state
++ * restore saved IRQ state
+ */
+ #define arch_local_irq_restore arch_local_irq_restore
+ static inline void arch_local_irq_restore(unsigned long flags)
+ {
+- asm volatile(
+- " msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"
++ unsigned long temp = 0;
++ flags &= ~(1 << 6);
++ asm volatile (
++ " mrs %0, cpsr"
++ : "=r" (temp)
++ :
++ : "memory", "cc");
++ /* Preserve FIQ bit */
++ temp &= (1 << 6);
++ flags = flags | temp;
++ asm volatile (
++ " msr cpsr_c, %0 @ local_irq_restore"
+ :
+ : "r" (flags)
+ : "memory", "cc");
+diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S
+index 8dd26e1a9bd6..eef484756af2 100644
+--- a/arch/arm/kernel/fiqasm.S
++++ b/arch/arm/kernel/fiqasm.S
+@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs)
+ mov r0, r0 @ avoid hazard prior to ARMv4
+ ret lr
+ ENDPROC(__get_fiq_regs)
++
++ENTRY(__FIQ_Branch)
++ mov pc, r8
++ENDPROC(__FIQ_Branch)
+diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
+index 7d1b8c82b208..2810d7153f57 100644
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -8,6 +8,7 @@
+ obj-$(CONFIG_USB) += core/
+ obj-$(CONFIG_USB_SUPPORT) += phy/
+
++obj-$(CONFIG_USB_DWCOTG) += host/
+ obj-$(CONFIG_USB_DWC3) += dwc3/
+ obj-$(CONFIG_USB_DWC2) += dwc2/
+ obj-$(CONFIG_USB_ISP1760) += isp1760/
+diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
+index f713cecc1f41..72bf1da12a52 100644
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -184,6 +184,7 @@ int usb_choose_configuration(struct usb_device *udev)
+ dev_warn(&udev->dev,
+ "no configuration chosen from %d choice%s\n",
+ num_configs, plural(num_configs));
++ dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
+ }
+ return i;
+ }
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 55c87be5764c..55a7b7f7d613 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -5248,7 +5248,7 @@ static void port_event(struct usb_hub *hub, int port1)
+ port_dev->over_current_count++;
+ port_over_current_notify(port_dev);
+
+- dev_dbg(&port_dev->dev, "over-current change #%u\n",
++ dev_notice(&port_dev->dev, "over-current change #%u\n",
+ port_dev->over_current_count);
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
+index 4020ce8db6ce..9b5411635f96 100644
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -1993,6 +1993,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
+ if (cp->string == NULL &&
+ !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
+ cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
++/* Uncomment this define to enable the HS Electrical Test support */
++#define DWC_HS_ELECT_TST 1
++#ifdef DWC_HS_ELECT_TST
++ /* Here we implement the HS Electrical Test support. The
++ * tester uses a vendor ID of 0x1A0A to indicate we should
++ * run a special test sequence. The product ID tells us
++ * which sequence to run. We invoke the test sequence by
++ * sending a non-standard SetFeature command to our root
++ * hub port. Our dwc_otg_hcd_hub_control() routine will
++ * recognize the command and perform the desired test
++ * sequence.
++ */
++ if (dev->descriptor.idVendor == 0x1A0A) {
++ /* HSOTG Electrical Test */
++ dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
++
++ if (dev->bus && dev->bus->root_hub) {
++ struct usb_device *hdev = dev->bus->root_hub;
++ dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
++
++ switch (dev->descriptor.idProduct) {
++ case 0x0101: /* TEST_SE0_NAK */
++ dev_warn(&dev->dev, "TEST_SE0_NAK\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
++ break;
++
++ case 0x0102: /* TEST_J */
++ dev_warn(&dev->dev, "TEST_J\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
++ break;
++
++ case 0x0103: /* TEST_K */
++ dev_warn(&dev->dev, "TEST_K\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
++ break;
++
++ case 0x0104: /* TEST_PACKET */
++ dev_warn(&dev->dev, "TEST_PACKET\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
++ break;
++
++ case 0x0105: /* TEST_FORCE_ENABLE */
++ dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
++ break;
++
++ case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
++ dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
++ break;
++
++ case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
++ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
++ break;
++
++ case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
++ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
++ }
++ }
++ }
++#endif /* DWC_HS_ELECT_TST */
+
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
+index 2ae90158ded7..150d4fa1e09b 100644
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -15,33 +15,82 @@
+ static struct usb_device_id whitelist_table[] = {
+
+ /* hubs are optional in OTG, but very handy ... */
++#define CERT_WITHOUT_HUBS
++#if defined(CERT_WITHOUT_HUBS)
++{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
++#else
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
++{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
++#endif
+
+ #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
+ /* FIXME actually, printers are NOT supposed to use device classes;
+ * they're supposed to use interface classes...
+ */
+-{ USB_DEVICE_INFO(7, 1, 1) },
+-{ USB_DEVICE_INFO(7, 1, 2) },
+-{ USB_DEVICE_INFO(7, 1, 3) },
++//{ USB_DEVICE_INFO(7, 1, 1) },
++//{ USB_DEVICE_INFO(7, 1, 2) },
++//{ USB_DEVICE_INFO(7, 1, 3) },
+ #endif
+
+ #ifdef CONFIG_USB_NET_CDCETHER
+ /* Linux-USB CDC Ethernet gadget */
+-{ USB_DEVICE(0x0525, 0xa4a1), },
++//{ USB_DEVICE(0x0525, 0xa4a1), },
+ /* Linux-USB CDC Ethernet + RNDIS gadget */
+-{ USB_DEVICE(0x0525, 0xa4a2), },
++//{ USB_DEVICE(0x0525, 0xa4a2), },
+ #endif
+
+ #if IS_ENABLED(CONFIG_USB_TEST)
+ /* gadget zero, for testing */
+-{ USB_DEVICE(0x0525, 0xa4a0), },
++//{ USB_DEVICE(0x0525, 0xa4a0), },
+ #endif
+
++/* OPT Tester */
++{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
++{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
++{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
++{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
++{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
++{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
++{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
++{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
++
++/* Sony cameras */
++{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
++
++/* Memory Devices */
++//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
++//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
++//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
++//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
++{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
++//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
++
++/* HP Printers */
++//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
++//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
++
++/* Speakers */
++//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
++//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
++
+ { } /* Terminating entry */
+ };
+
++static inline void report_errors(struct usb_device *dev)
++{
++ /* OTG MESSAGE: report errors here, customize to match your product */
++ dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
++ le16_to_cpu(dev->descriptor.idVendor),
++ le16_to_cpu(dev->descriptor.idProduct));
++ if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
++ dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
++ } else {
++ dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
++ }
++}
++
++
+ static int is_targeted(struct usb_device *dev)
+ {
+ struct usb_device_id *id = whitelist_table;
+@@ -91,16 +140,57 @@ static int is_targeted(struct usb_device *dev)
+ continue;
+
+ return 1;
++ /* NOTE: can't use usb_match_id() since interface caches
++ * aren't set up yet. this is cut/paste from that code.
++ */
++ for (id = whitelist_table; id->match_flags; id++) {
++#ifdef DEBUG
++ dev_dbg(&dev->dev,
++ "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
++ id->idVendor,
++ id->idProduct,
++ id->bDeviceClass,
++ id->bDeviceSubClass,
++ id->bDeviceProtocol);
++#endif
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
++ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
++ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
++ continue;
++
++ /* No need to test id->bcdDevice_lo != 0, since 0 is never
++ greater than any unsigned number. */
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
++ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
++ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
++ (id->bDeviceClass != dev->descriptor.bDeviceClass))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
++ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
++ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
++ continue;
++
++ return 1;
++ }
+ }
+
+ /* add other match criteria here ... */
+
+-
+- /* OTG MESSAGE: report errors here, customize to match your product */
+- dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+- le16_to_cpu(dev->descriptor.idVendor),
+- le16_to_cpu(dev->descriptor.idProduct));
+-
++ report_errors(dev);
+ return 0;
+ }
+
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+new file mode 100644
+index 000000000000..a896d73f7a93
+--- /dev/null
++++ b/drivers/usb/gadget/file_storage.c
+@@ -0,0 +1,3676 @@
++/*
++ * file_storage.c -- File-backed USB Storage Gadget, for USB development
++ *
++ * Copyright (C) 2003-2008 Alan Stern
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/*
++ * The File-backed Storage Gadget acts as a USB Mass Storage device,
++ * appearing to the host as a disk drive or as a CD-ROM drive. In addition
++ * to providing an example of a genuinely useful gadget driver for a USB
++ * device, it also illustrates a technique of double-buffering for increased
++ * throughput. Last but not least, it gives an easy way to probe the
++ * behavior of the Mass Storage drivers in a USB host.
++ *
++ * Backing storage is provided by a regular file or a block device, specified
++ * by the "file" module parameter. Access can be limited to read-only by
++ * setting the optional "ro" module parameter. (For CD-ROM emulation,
++ * access is always read-only.) The gadget will indicate that it has
++ * removable media if the optional "removable" module parameter is set.
++ *
++ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
++ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
++ * by the optional "transport" module parameter. It also supports the
++ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
++ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
++ * the optional "protocol" module parameter. In addition, the default
++ * Vendor ID, Product ID, release number and serial number can be overridden.
++ *
++ * There is support for multiple logical units (LUNs), each of which has
++ * its own backing file. The number of LUNs can be set using the optional
++ * "luns" module parameter (anywhere from 1 to 8), and the corresponding
++ * files are specified using comma-separated lists for "file" and "ro".
++ * The default number of LUNs is taken from the number of "file" elements;
++ * it is 1 if "file" is not given. If "removable" is not set then a backing
++ * file must be specified for each LUN. If it is set, then an unspecified
++ * or empty backing filename means the LUN's medium is not loaded. Ideally
++ * each LUN would be settable independently as a disk drive or a CD-ROM
++ * drive, but currently all LUNs have to be the same type. The CD-ROM
++ * emulation includes a single data track and no audio tracks; hence there
++ * need be only one backing file per LUN.
++ *
++ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
++ * needed (an interrupt-out endpoint is also needed for CBI). The memory
++ * requirement amounts to two 16K buffers, size configurable by a parameter.
++ * Support is included for both full-speed and high-speed operation.
++ *
++ * Note that the driver is slightly non-portable in that it assumes a
++ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
++ * interrupt-in endpoints. With most device controllers this isn't an
++ * issue, but there may be some with hardware restrictions that prevent
++ * a buffer from being used by more than one endpoint.
++ *
++ * Module options:
++ *
++ * file=filename[,filename...]
++ * Required if "removable" is not set, names of
++ * the files or block devices used for
++ * backing storage
++ * serial=HHHH... Required serial number (string of hex chars)
++ * ro=b[,b...] Default false, booleans for read-only access
++ * removable Default false, boolean for removable media
++ * luns=N Default N = number of filenames, number of
++ * LUNs to support
++ * nofua=b[,b...] Default false, booleans for ignore FUA flag
++ * in SCSI WRITE(10,12) commands
++ * stall Default determined according to the type of
++ * USB device controller (usually true),
++ * boolean to permit the driver to halt
++ * bulk endpoints
++ * cdrom Default false, boolean for whether to emulate
++ * a CD-ROM drive
++ * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
++ * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
++ * ATAPI, QIC, UFI, 8070, or SCSI;
++ * also 1 - 6)
++ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
++ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
++ * release=0xRRRR Override the USB release number (bcdDevice)
++ * buflen=N Default N=16384, buffer size used (will be
++ * rounded down to a multiple of
++ * PAGE_CACHE_SIZE)
++ *
++ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
++ * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
++ * default values are used for everything else.
++ *
++ * The pathnames of the backing files and the ro settings are available in
++ * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
++ * the gadget's sysfs directory. If the "removable" option is set, writing to
++ * these files will simulate ejecting/loading the medium (writing an empty
++ * line means eject) and adjusting a write-enable tab. Changes to the ro
++ * setting are not allowed when the medium is loaded or if CD-ROM emulation
++ * is being used.
++ *
++ * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
++ * The driver's SCSI command interface was based on the "Information
++ * technology - Small Computer System Interface - 2" document from
++ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
++ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
++ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
++ * "Universal Serial Bus Mass Storage Class UFI Command Specification"
++ * document, Revision 1.0, December 14, 1998, available at
++ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
++ */
++
++
++/*
++ * Driver Design
++ *
++ * The FSG driver is fairly straightforward. There is a main kernel
++ * thread that handles most of the work. Interrupt routines field
++ * callbacks from the controller driver: bulk- and interrupt-request
++ * completion notifications, endpoint-0 events, and disconnect events.
++ * Completion events are passed to the main thread by wakeup calls. Many
++ * ep0 requests are handled at interrupt time, but SetInterface,
++ * SetConfiguration, and device reset requests are forwarded to the
++ * thread in the form of "exceptions" using SIGUSR1 signals (since they
++ * should interrupt any ongoing file I/O operations).
++ *
++ * The thread's main routine implements the standard command/data/status
++ * parts of a SCSI interaction. It and its subroutines are full of tests
++ * for pending signals/exceptions -- all this polling is necessary since
++ * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
++ * indication that the driver really wants to be running in userspace.)
++ * An important point is that so long as the thread is alive it keeps an
++ * open reference to the backing file. This will prevent unmounting
++ * the backing file's underlying filesystem and could cause problems
++ * during system shutdown, for example. To prevent such problems, the
++ * thread catches INT, TERM, and KILL signals and converts them into
++ * an EXIT exception.
++ *
++ * In normal operation the main thread is started during the gadget's
++ * fsg_bind() callback and stopped during fsg_unbind(). But it can also
++ * exit when it receives a signal, and there's no point leaving the
++ * gadget running when the thread is dead. So just before the thread
++ * exits, it deregisters the gadget driver. This makes things a little
++ * tricky: The driver is deregistered at two places, and the exiting
++ * thread can indirectly call fsg_unbind() which in turn can tell the
++ * thread to exit. The first problem is resolved through the use of the
++ * REGISTERED atomic bitflag; the driver will only be deregistered once.
++ * The second problem is resolved by having fsg_unbind() check
++ * fsg->state; it won't try to stop the thread if the state is already
++ * FSG_STATE_TERMINATED.
++ *
++ * To provide maximum throughput, the driver uses a circular pipeline of
++ * buffer heads (struct fsg_buffhd). In principle the pipeline can be
++ * arbitrarily long; in practice the benefits don't justify having more
++ * than 2 stages (i.e., double buffering). But it helps to think of the
++ * pipeline as being a long one. Each buffer head contains a bulk-in and
++ * a bulk-out request pointer (since the buffer can be used for both
++ * output and input -- directions always are given from the host's
++ * point of view) as well as a pointer to the buffer and various state
++ * variables.
++ *
++ * Use of the pipeline follows a simple protocol. There is a variable
++ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
++ * At any time that buffer head may still be in use from an earlier
++ * request, so each buffer head has a state variable indicating whether
++ * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
++ * buffer head to be EMPTY, filling the buffer either by file I/O or by
++ * USB I/O (during which the buffer head is BUSY), and marking the buffer
++ * head FULL when the I/O is complete. Then the buffer will be emptied
++ * (again possibly by USB I/O, during which it is marked BUSY) and
++ * finally marked EMPTY again (possibly by a completion routine).
++ *
++ * A module parameter tells the driver to avoid stalling the bulk
++ * endpoints wherever the transport specification allows. This is
++ * necessary for some UDCs like the SuperH, which cannot reliably clear a
++ * halt on a bulk endpoint. However, under certain circumstances the
++ * Bulk-only specification requires a stall. In such cases the driver
++ * will halt the endpoint and set a flag indicating that it should clear
++ * the halt in software during the next device reset. Hopefully this
++ * will permit everything to work correctly. Furthermore, although the
++ * specification allows the bulk-out endpoint to halt when the host sends
++ * too much data, implementing this would cause an unavoidable race.
++ * The driver will always use the "no-stall" approach for OUT transfers.
++ *
++ * One subtle point concerns sending status-stage responses for ep0
++ * requests. Some of these requests, such as device reset, can involve
++ * interrupting an ongoing file I/O operation, which might take an
++ * arbitrarily long time. During that delay the host might give up on
++ * the original ep0 request and issue a new one. When that happens the
++ * driver should not notify the host about completion of the original
++ * request, as the host will no longer be waiting for it. So the driver
++ * assigns to each ep0 request a unique tag, and it keeps track of the
++ * tag value of the request associated with a long-running exception
++ * (device-reset, interface-change, or configuration-change). When the
++ * exception handler is finished, the status-stage response is submitted
++ * only if the current ep0 request tag is equal to the exception request
++ * tag. Thus only the most recently received ep0 request will get a
++ * status-stage response.
++ *
++ * Warning: This driver source file is too long. It ought to be split up
++ * into a header file plus about 3 separate .c files, to handle the details
++ * of the Gadget, USB Mass Storage, and SCSI protocols.
++ */
++
++
++/* #define VERBOSE_DEBUG */
++/* #define DUMP_MSGS */
++
++
++#include <linux/blkdev.h>
++#include <linux/completion.h>
++#include <linux/dcache.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fcntl.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/kref.h>
++#include <linux/kthread.h>
++#include <linux/limits.h>
++#include <linux/module.h>
++#include <linux/rwsem.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/freezer.h>
++#include <linux/utsname.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "gadget_chips.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 "usbstring.c"
++#include "config.c"
++#include "epautoconf.c"
++
++/*-------------------------------------------------------------------------*/
++
++#define DRIVER_DESC "File-backed Storage Gadget"
++#define DRIVER_NAME "g_file_storage"
++#define DRIVER_VERSION "1 September 2010"
++
++static char fsg_string_manufacturer[64];
++static const char fsg_string_product[] = DRIVER_DESC;
++static const char fsg_string_config[] = "Self-powered";
++static const char fsg_string_interface[] = "Mass Storage";
++
++
++#include "storage_common.c"
++
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Alan Stern");
++MODULE_LICENSE("Dual BSD/GPL");
++
++/*
++ * This driver assumes self-powered hardware and has no way for users to
++ * trigger remote wakeup. It uses autoconfiguration to select endpoints
++ * and endpoint addresses.
++ */
++
++
++/*-------------------------------------------------------------------------*/
++
++
++/* Encapsulate the module parameter settings */
++
++static struct {
++ char *file[FSG_MAX_LUNS];
++ char *serial;
++ bool ro[FSG_MAX_LUNS];
++ bool nofua[FSG_MAX_LUNS];
++ unsigned int num_filenames;
++ unsigned int num_ros;
++ unsigned int num_nofuas;
++ unsigned int nluns;
++
++ bool removable;
++ bool can_stall;
++ bool cdrom;
++
++ char *transport_parm;
++ char *protocol_parm;
++ unsigned short vendor;
++ unsigned short product;
++ unsigned short release;
++ unsigned int buflen;
++
++ int transport_type;
++ char *transport_name;
++ int protocol_type;
++ char *protocol_name;
++
++} mod_data = { // Default values
++ .transport_parm = "BBB",
++ .protocol_parm = "SCSI",
++ .removable = 0,
++ .can_stall = 1,
++ .cdrom = 0,
++ .vendor = FSG_VENDOR_ID,
++ .product = FSG_PRODUCT_ID,
++ .release = 0xffff, // Use controller chip type
++ .buflen = 16384,
++ };
++
++
++module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
++ S_IRUGO);
++MODULE_PARM_DESC(file, "names of backing files or devices");
++
++module_param_named(serial, mod_data.serial, charp, S_IRUGO);
++MODULE_PARM_DESC(serial, "USB serial number");
++
++module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
++MODULE_PARM_DESC(ro, "true to force read-only");
++
++module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
++ S_IRUGO);
++MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
++
++module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
++MODULE_PARM_DESC(luns, "number of LUNs");
++
++module_param_named(removable, mod_data.removable, bool, S_IRUGO);
++MODULE_PARM_DESC(removable, "true to simulate removable media");
++
++module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
++MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
++
++module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
++MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
++
++/* In the non-TEST version, only the module parameters listed above
++ * are available. */
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++
++module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
++
++module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
++ "8070, or SCSI)");
++
++module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
++MODULE_PARM_DESC(vendor, "USB Vendor ID");
++
++module_param_named(product, mod_data.product, ushort, S_IRUGO);
++MODULE_PARM_DESC(product, "USB Product ID");
++
++module_param_named(release, mod_data.release, ushort, S_IRUGO);
++MODULE_PARM_DESC(release, "USB release number");
++
++module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
++MODULE_PARM_DESC(buflen, "I/O buffer size");
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*
++ * These definitions will permit the compiler to avoid generating code for
++ * parts of the driver that aren't used in the non-TEST version. Even gcc
++ * can recognize when a test of a constant expression yields a dead code
++ * path.
++ */
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++
++#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
++#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
++#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
++
++#else
++
++#define transport_is_bbb() 1
++#define transport_is_cbi() 0
++#define protocol_is_scsi() 1
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*-------------------------------------------------------------------------*/
++
++
++struct fsg_dev {
++ /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
++ spinlock_t lock;
++ struct usb_gadget *gadget;
++
++ /* filesem protects: backing files in use */
++ struct rw_semaphore filesem;
++
++ /* reference counting: wait until all LUNs are released */
++ struct kref ref;
++
++ struct usb_ep *ep0; // Handy copy of gadget->ep0
++ struct usb_request *ep0req; // For control responses
++ unsigned int ep0_req_tag;
++ const char *ep0req_name;
++
++ struct usb_request *intreq; // For interrupt responses
++ int intreq_busy;
++ struct fsg_buffhd *intr_buffhd;
++
++ unsigned int bulk_out_maxpacket;
++ enum fsg_state state; // For exception handling
++ unsigned int exception_req_tag;
++
++ u8 config, new_config;
++
++ unsigned int running : 1;
++ unsigned int bulk_in_enabled : 1;
++ unsigned int bulk_out_enabled : 1;
++ unsigned int intr_in_enabled : 1;
++ unsigned int phase_error : 1;
++ unsigned int short_packet_received : 1;
++ unsigned int bad_lun_okay : 1;
++
++ unsigned long atomic_bitflags;
++#define REGISTERED 0
++#define IGNORE_BULK_OUT 1
++#define SUSPENDED 2
++
++ struct usb_ep *bulk_in;
++ struct usb_ep *bulk_out;
++ struct usb_ep *intr_in;
++
++ struct fsg_buffhd *next_buffhd_to_fill;
++ struct fsg_buffhd *next_buffhd_to_drain;
++
++ int thread_wakeup_needed;
++ struct completion thread_notifier;
++ struct task_struct *thread_task;
++
++ int cmnd_size;
++ u8 cmnd[MAX_COMMAND_SIZE];
++ enum data_direction data_dir;
++ u32 data_size;
++ u32 data_size_from_cmnd;
++ u32 tag;
++ unsigned int lun;
++ u32 residue;
++ u32 usb_amount_left;
++
++ /* The CB protocol offers no way for a host to know when a command
++ * has completed. As a result the next command may arrive early,
++ * and we will still have to handle it. For that reason we need
++ * a buffer to store new commands when using CB (or CBI, which
++ * does not oblige a host to wait for command completion either). */
++ int cbbuf_cmnd_size;
++ u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
++
++ unsigned int nluns;
++ struct fsg_lun *luns;
++ struct fsg_lun *curlun;
++ /* Must be the last entry */
++ struct fsg_buffhd buffhds[];
++};
++
++typedef void (*fsg_routine_t)(struct fsg_dev *);
++
++static int exception_in_progress(struct fsg_dev *fsg)
++{
++ return (fsg->state > FSG_STATE_IDLE);
++}
++
++/* Make bulk-out requests be divisible by the maxpacket size */
++static void set_bulk_out_req_length(struct fsg_dev *fsg,
++ struct fsg_buffhd *bh, unsigned int length)
++{
++ unsigned int rem;
++
++ bh->bulk_out_intended_length = length;
++ rem = length % fsg->bulk_out_maxpacket;
++ if (rem > 0)
++ length += fsg->bulk_out_maxpacket - rem;
++ bh->outreq->length = length;
++}
++
++static struct fsg_dev *the_fsg;
++static struct usb_gadget_driver fsg_driver;
++
++
++/*-------------------------------------------------------------------------*/
++
++static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
++{
++ const char *name;
++
++ if (ep == fsg->bulk_in)
++ name = "bulk-in";
++ else if (ep == fsg->bulk_out)
++ name = "bulk-out";
++ else
++ name = ep->name;
++ DBG(fsg, "%s set halt\n", name);
++ return usb_ep_set_halt(ep);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full) configuration
++ * descriptors are built on demand. Also the (static) config and interface
++ * descriptors are adjusted during fsg_bind().
++ */
++
++/* There is only one configuration. */
++#define CONFIG_VALUE 1
++
++static struct usb_device_descriptor
++device_desc = {
++ .bLength = sizeof device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++
++ .bcdUSB = cpu_to_le16(0x0200),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++
++ /* The next three values can be overridden by module parameters */
++ .idVendor = cpu_to_le16(FSG_VENDOR_ID),
++ .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
++ .bcdDevice = cpu_to_le16(0xffff),
++
++ .iManufacturer = FSG_STRING_MANUFACTURER,
++ .iProduct = FSG_STRING_PRODUCT,
++ .iSerialNumber = FSG_STRING_SERIAL,
++ .bNumConfigurations = 1,
++};
++
++static struct usb_config_descriptor
++config_desc = {
++ .bLength = sizeof config_desc,
++ .bDescriptorType = USB_DT_CONFIG,
++
++ /* wTotalLength computed by usb_gadget_config_buf() */
++ .bNumInterfaces = 1,
++ .bConfigurationValue = CONFIG_VALUE,
++ .iConfiguration = FSG_STRING_CONFIG,
++ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
++ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
++};
++
++
++static struct usb_qualifier_descriptor
++dev_qualifier = {
++ .bLength = sizeof dev_qualifier,
++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
++
++ .bcdUSB = cpu_to_le16(0x0200),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++
++ .bNumConfigurations = 1,
++};
++
++static int populate_bos(struct fsg_dev *fsg, u8 *buf)
++{
++ memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
++ buf += USB_DT_BOS_SIZE;
++
++ memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
++ buf += USB_DT_USB_EXT_CAP_SIZE;
++
++ memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
++
++ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
++ + USB_DT_USB_EXT_CAP_SIZE;
++}
++
++/*
++ * Config descriptors must agree with the code that sets configurations
++ * and with code managing interfaces and their altsettings. They must
++ * also handle different speeds and other-speed requests.
++ */
++static int populate_config_buf(struct usb_gadget *gadget,
++ u8 *buf, u8 type, unsigned index)
++{
++ enum usb_device_speed speed = gadget->speed;
++ int len;
++ const struct usb_descriptor_header **function;
++
++ if (index > 0)
++ return -EINVAL;
++
++ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
++ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
++ function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
++ ? (const struct usb_descriptor_header **)fsg_hs_function
++ : (const struct usb_descriptor_header **)fsg_fs_function;
++
++ /* for now, don't advertise srp-only devices */
++ if (!gadget_is_otg(gadget))
++ function++;
++
++ len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
++ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
++ return len;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* These routines may be called in process context or in_irq */
++
++/* Caller must hold fsg->lock */
++static void wakeup_thread(struct fsg_dev *fsg)
++{
++ /* Tell the main thread that something has happened */
++ fsg->thread_wakeup_needed = 1;
++ if (fsg->thread_task)
++ wake_up_process(fsg->thread_task);
++}
++
++
++static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
++{
++ unsigned long flags;
++
++ /* Do nothing if a higher-priority exception is already in progress.
++ * If a lower-or-equal priority exception is in progress, preempt it
++ * and notify the main thread by sending it a signal. */
++ spin_lock_irqsave(&fsg->lock, flags);
++ if (fsg->state <= new_state) {
++ fsg->exception_req_tag = fsg->ep0_req_tag;
++ fsg->state = new_state;
++ if (fsg->thread_task)
++ send_sig_info(SIGUSR1, SEND_SIG_FORCED,
++ fsg->thread_task);
++ }
++ spin_unlock_irqrestore(&fsg->lock, flags);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* The disconnect callback and ep0 routines. These always run in_irq,
++ * except that ep0_queue() is called in the main thread to acknowledge
++ * completion of various requests: set config, set interface, and
++ * Bulk-only device reset. */
++
++static void fsg_disconnect(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++
++ DBG(fsg, "disconnect or port reset\n");
++ raise_exception(fsg, FSG_STATE_DISCONNECT);
++}
++
++
++static int ep0_queue(struct fsg_dev *fsg)
++{
++ int rc;
++
++ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
++ if (rc != 0 && rc != -ESHUTDOWN) {
++
++ /* We can't do much more than wait for a reset */
++ WARNING(fsg, "error in submission: %s --> %d\n",
++ fsg->ep0->name, rc);
++ }
++ return rc;
++}
++
++static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++
++ if (req->actual > 0)
++ dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
++ if (req->status || req->actual != req->length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual, req->length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ if (req->status == 0 && req->context)
++ ((fsg_routine_t) (req->context))(fsg);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Bulk and interrupt endpoint completion handlers.
++ * These always run in_irq. */
++
++static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_buffhd *bh = req->context;
++
++ if (req->status || req->actual != req->length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual, req->length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ /* Hold the lock while we update the request and buffer states */
++ smp_wmb();
++ spin_lock(&fsg->lock);
++ bh->inreq_busy = 0;
++ bh->state = BUF_STATE_EMPTY;
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_buffhd *bh = req->context;
++
++ dump_msg(fsg, "bulk-out", req->buf, req->actual);
++ if (req->status || req->actual != bh->bulk_out_intended_length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual,
++ bh->bulk_out_intended_length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ /* Hold the lock while we update the request and buffer states */
++ smp_wmb();
++ spin_lock(&fsg->lock);
++ bh->outreq_busy = 0;
++ bh->state = BUF_STATE_FULL;
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_buffhd *bh = req->context;
++
++ if (req->status || req->actual != req->length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual, req->length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ /* Hold the lock while we update the request and buffer states */
++ smp_wmb();
++ spin_lock(&fsg->lock);
++ fsg->intreq_busy = 0;
++ bh->state = BUF_STATE_EMPTY;
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++#else
++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
++{}
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Ep0 class-specific handlers. These always run in_irq. */
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct usb_request *req = fsg->ep0req;
++ static u8 cbi_reset_cmnd[6] = {
++ SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
++
++ /* Error in command transfer? */
++ if (req->status || req->length != req->actual ||
++ req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
++
++ /* Not all controllers allow a protocol stall after
++ * receiving control-out data, but we'll try anyway. */
++ fsg_set_halt(fsg, fsg->ep0);
++ return; // Wait for reset
++ }
++
++ /* Is it the special reset command? */
++ if (req->actual >= sizeof cbi_reset_cmnd &&
++ memcmp(req->buf, cbi_reset_cmnd,
++ sizeof cbi_reset_cmnd) == 0) {
++
++ /* Raise an exception to stop the current operation
++ * and reinitialize our state. */
++ DBG(fsg, "cbi reset request\n");
++ raise_exception(fsg, FSG_STATE_RESET);
++ return;
++ }
++
++ VDBG(fsg, "CB[I] accept device-specific command\n");
++ spin_lock(&fsg->lock);
++
++ /* Save the command for later */
++ if (fsg->cbbuf_cmnd_size)
++ WARNING(fsg, "CB[I] overwriting previous command\n");
++ fsg->cbbuf_cmnd_size = req->actual;
++ memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
++
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++#else
++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{}
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++static int class_setup_req(struct fsg_dev *fsg,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct usb_request *req = fsg->ep0req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ if (!fsg->config)
++ return value;
++
++ /* Handle Bulk-only class-specific requests */
++ if (transport_is_bbb()) {
++ switch (ctrl->bRequest) {
++
++ case US_BULK_RESET_REQUEST:
++ if (ctrl->bRequestType != (USB_DIR_OUT |
++ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++ break;
++ if (w_index != 0 || w_value != 0 || w_length != 0) {
++ value = -EDOM;
++ break;
++ }
++
++ /* Raise an exception to stop the current operation
++ * and reinitialize our state. */
++ DBG(fsg, "bulk reset request\n");
++ raise_exception(fsg, FSG_STATE_RESET);
++ value = DELAYED_STATUS;
++ break;
++
++ case US_BULK_GET_MAX_LUN:
++ if (ctrl->bRequestType != (USB_DIR_IN |
++ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++ break;
++ if (w_index != 0 || w_value != 0 || w_length != 1) {
++ value = -EDOM;
++ break;
++ }
++ VDBG(fsg, "get max LUN\n");
++ *(u8 *) req->buf = fsg->nluns - 1;
++ value = 1;
++ break;
++ }
++ }
++
++ /* Handle CBI class-specific requests */
++ else {
++ switch (ctrl->bRequest) {
++
++ case USB_CBI_ADSC_REQUEST:
++ if (ctrl->bRequestType != (USB_DIR_OUT |
++ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++ break;
++ if (w_index != 0 || w_value != 0) {
++ value = -EDOM;
++ break;
++ }
++ if (w_length > MAX_COMMAND_SIZE) {
++ value = -EOVERFLOW;
++ break;
++ }
++ value = w_length;
++ fsg->ep0req->context = received_cbi_adsc;
++ break;
++ }
++ }
++
++ if (value == -EOPNOTSUPP)
++ VDBG(fsg,
++ "unknown class-specific control req "
++ "%02x.%02x v%04x i%04x l%u\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ le16_to_cpu(ctrl->wValue), w_index, w_length);
++ return value;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Ep0 standard request handlers. These always run in_irq. */
++
++static int standard_setup_req(struct fsg_dev *fsg,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct usb_request *req = fsg->ep0req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++
++ /* Usually this just stores reply data in the pre-allocated ep0 buffer,
++ * but config change events will also reconfigure hardware. */
++ switch (ctrl->bRequest) {
++
++ case USB_REQ_GET_DESCRIPTOR:
++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++ USB_RECIP_DEVICE))
++ break;
++ switch (w_value >> 8) {
++
++ case USB_DT_DEVICE:
++ VDBG(fsg, "get device descriptor\n");
++ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
++ value = sizeof device_desc;
++ memcpy(req->buf, &device_desc, value);
++ break;
++ case USB_DT_DEVICE_QUALIFIER:
++ VDBG(fsg, "get device qualifier\n");
++ if (!gadget_is_dualspeed(fsg->gadget) ||
++ fsg->gadget->speed == USB_SPEED_SUPER)
++ break;
++ /*
++ * Assume ep0 uses the same maxpacket value for both
++ * speeds
++ */
++ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
++ value = sizeof dev_qualifier;
++ memcpy(req->buf, &dev_qualifier, value);
++ break;
++
++ case USB_DT_OTHER_SPEED_CONFIG:
++ VDBG(fsg, "get other-speed config descriptor\n");
++ if (!gadget_is_dualspeed(fsg->gadget) ||
++ fsg->gadget->speed == USB_SPEED_SUPER)
++ break;
++ goto get_config;
++ case USB_DT_CONFIG:
++ VDBG(fsg, "get configuration descriptor\n");
++get_config:
++ value = populate_config_buf(fsg->gadget,
++ req->buf,
++ w_value >> 8,
++ w_value & 0xff);
++ break;
++
++ case USB_DT_STRING:
++ VDBG(fsg, "get string descriptor\n");
++
++ /* wIndex == language code */
++ value = usb_gadget_get_string(&fsg_stringtab,
++ w_value & 0xff, req->buf);
++ break;
++
++ case USB_DT_BOS:
++ VDBG(fsg, "get bos descriptor\n");
++
++ if (gadget_is_superspeed(fsg->gadget))
++ value = populate_bos(fsg, req->buf);
++ break;
++ }
++
++ break;
++
++ /* One config, two speeds */
++ case USB_REQ_SET_CONFIGURATION:
++ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
++ USB_RECIP_DEVICE))
++ break;
++ VDBG(fsg, "set configuration\n");
++ if (w_value == CONFIG_VALUE || w_value == 0) {
++ fsg->new_config = w_value;
++
++ /* Raise an exception to wipe out previous transaction
++ * state (queued bufs, etc) and set the new config. */
++ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++ value = DELAYED_STATUS;
++ }
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++ USB_RECIP_DEVICE))
++ break;
++ VDBG(fsg, "get configuration\n");
++ *(u8 *) req->buf = fsg->config;
++ value = 1;
++ break;
++
++ case USB_REQ_SET_INTERFACE:
++ if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
++ USB_RECIP_INTERFACE))
++ break;
++ if (fsg->config && w_index == 0) {
++
++ /* Raise an exception to wipe out previous transaction
++ * state (queued bufs, etc) and install the new
++ * interface altsetting. */
++ raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
++ value = DELAYED_STATUS;
++ }
++ break;
++ case USB_REQ_GET_INTERFACE:
++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++ USB_RECIP_INTERFACE))
++ break;
++ if (!fsg->config)
++ break;
++ if (w_index != 0) {
++ value = -EDOM;
++ break;
++ }
++ VDBG(fsg, "get interface\n");
++ *(u8 *) req->buf = 0;
++ value = 1;
++ break;
++
++ default:
++ VDBG(fsg,
++ "unknown control req %02x.%02x v%04x i%04x l%u\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, le16_to_cpu(ctrl->wLength));
++ }
++
++ return value;
++}
++
++
++static int fsg_setup(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++ int rc;
++ int w_length = le16_to_cpu(ctrl->wLength);
++
++ ++fsg->ep0_req_tag; // Record arrival of a new request
++ fsg->ep0req->context = NULL;
++ fsg->ep0req->length = 0;
++ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
++
++ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
++ rc = class_setup_req(fsg, ctrl);
++ else
++ rc = standard_setup_req(fsg, ctrl);
++
++ /* Respond with data/status or defer until later? */
++ if (rc >= 0 && rc != DELAYED_STATUS) {
++ rc = min(rc, w_length);
++ fsg->ep0req->length = rc;
++ fsg->ep0req->zero = rc < w_length;
++ fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
++ "ep0-in" : "ep0-out");
++ rc = ep0_queue(fsg);
++ }
++
++ /* Device either stalls (rc < 0) or reports success */
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* All the following routines run in process context */
++
++
++/* Use this for bulk or interrupt transfers, not ep0 */
++static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
++ struct usb_request *req, int *pbusy,
++ enum fsg_buffer_state *state)
++{
++ int rc;
++
++ if (ep == fsg->bulk_in)
++ dump_msg(fsg, "bulk-in", req->buf, req->length);
++ else if (ep == fsg->intr_in)
++ dump_msg(fsg, "intr-in", req->buf, req->length);
++
++ spin_lock_irq(&fsg->lock);
++ *pbusy = 1;
++ *state = BUF_STATE_BUSY;
++ spin_unlock_irq(&fsg->lock);
++ rc = usb_ep_queue(ep, req, GFP_KERNEL);
++ if (rc != 0) {
++ *pbusy = 0;
++ *state = BUF_STATE_EMPTY;
++
++ /* We can't do much more than wait for a reset */
++
++ /* Note: currently the net2280 driver fails zero-length
++ * submissions if DMA is enabled. */
++ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
++ req->length == 0))
++ WARNING(fsg, "error in submission: %s --> %d\n",
++ ep->name, rc);
++ }
++}
++
++
++static int sleep_thread(struct fsg_dev *fsg)
++{
++ int rc = 0;
++
++ /* Wait until a signal arrives or we are woken up */
++ for (;;) {
++ try_to_freeze();
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (signal_pending(current)) {
++ rc = -EINTR;
++ break;
++ }
++ if (fsg->thread_wakeup_needed)
++ break;
++ schedule();
++ }
++ __set_current_state(TASK_RUNNING);
++ fsg->thread_wakeup_needed = 0;
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_read(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba;
++ struct fsg_buffhd *bh;
++ int rc;
++ u32 amount_left;
++ loff_t file_offset, file_offset_tmp;
++ unsigned int amount;
++ ssize_t nread;
++
++ /* Get the starting Logical Block Address and check that it's
++ * not too big */
++ if (fsg->cmnd[0] == READ_6)
++ lba = get_unaligned_be24(&fsg->cmnd[1]);
++ else {
++ lba = get_unaligned_be32(&fsg->cmnd[2]);
++
++ /* We allow DPO (Disable Page Out = don't save data in the
++ * cache) and FUA (Force Unit Access = don't read from the
++ * cache), but we don't implement them. */
++ if ((fsg->cmnd[1] & ~0x18) != 0) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ }
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++ file_offset = ((loff_t) lba) << curlun->blkbits;
++
++ /* Carry out the file reads */
++ amount_left = fsg->data_size_from_cmnd;
++ if (unlikely(amount_left == 0))
++ return -EIO; // No default reply
++
++ for (;;) {
++
++ /* Figure out how much we need to read:
++ * Try to read the remaining amount.
++ * But don't read more than the buffer size.
++ * And don't try to read past the end of the file.
++ */
++ amount = min((unsigned int) amount_left, mod_data.buflen);
++ amount = min((loff_t) amount,
++ curlun->file_length - file_offset);
++
++ /* Wait for the next buffer to become available */
++ bh = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ /* If we were asked to read past the end of file,
++ * end with an empty buffer. */
++ if (amount == 0) {
++ curlun->sense_data =
++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ bh->inreq->length = 0;
++ bh->state = BUF_STATE_FULL;
++ break;
++ }
++
++ /* Perform the read */
++ file_offset_tmp = file_offset;
++ nread = vfs_read(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
++ (unsigned long long) file_offset,
++ (int) nread);
++ if (signal_pending(current))
++ return -EINTR;
++
++ if (nread < 0) {
++ LDBG(curlun, "error in file read: %d\n",
++ (int) nread);
++ nread = 0;
++ } else if (nread < amount) {
++ LDBG(curlun, "partial file read: %d/%u\n",
++ (int) nread, amount);
++ nread = round_down(nread, curlun->blksize);
++ }
++ file_offset += nread;
++ amount_left -= nread;
++ fsg->residue -= nread;
++
++ /* Except at the end of the transfer, nread will be
++ * equal to the buffer size, which is divisible by the
++ * bulk-in maxpacket size.
++ */
++ bh->inreq->length = nread;
++ bh->state = BUF_STATE_FULL;
++
++ /* If an error occurred, report it and its position */
++ if (nread < amount) {
++ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ if (amount_left == 0)
++ break; // No more left to read
++
++ /* Send this buffer and go read some more */
++ bh->inreq->zero = 0;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ }
++
++ return -EIO; // No default reply
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_write(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba;
++ struct fsg_buffhd *bh;
++ int get_some_more;
++ u32 amount_left_to_req, amount_left_to_write;
++ loff_t usb_offset, file_offset, file_offset_tmp;
++ unsigned int amount;
++ ssize_t nwritten;
++ int rc;
++
++ if (curlun->ro) {
++ curlun->sense_data = SS_WRITE_PROTECTED;
++ return -EINVAL;
++ }
++ spin_lock(&curlun->filp->f_lock);
++ curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
++ spin_unlock(&curlun->filp->f_lock);
++
++ /* Get the starting Logical Block Address and check that it's
++ * not too big */
++ if (fsg->cmnd[0] == WRITE_6)
++ lba = get_unaligned_be24(&fsg->cmnd[1]);
++ else {
++ lba = get_unaligned_be32(&fsg->cmnd[2]);
++
++ /* We allow DPO (Disable Page Out = don't save data in the
++ * cache) and FUA (Force Unit Access = write directly to the
++ * medium). We don't implement DPO; we implement FUA by
++ * performing synchronous output. */
++ if ((fsg->cmnd[1] & ~0x18) != 0) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ /* FUA */
++ if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
++ spin_lock(&curlun->filp->f_lock);
++ curlun->filp->f_flags |= O_DSYNC;
++ spin_unlock(&curlun->filp->f_lock);
++ }
++ }
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++
++ /* Carry out the file writes */
++ get_some_more = 1;
++ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
++ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
++
++ while (amount_left_to_write > 0) {
++
++ /* Queue a request for more data from the host */
++ bh = fsg->next_buffhd_to_fill;
++ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
++
++ /* Figure out how much we want to get:
++ * Try to get the remaining amount,
++ * but not more than the buffer size.
++ */
++ amount = min(amount_left_to_req, mod_data.buflen);
++
++ /* Beyond the end of the backing file? */
++ if (usb_offset >= curlun->file_length) {
++ get_some_more = 0;
++ curlun->sense_data =
++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ curlun->sense_data_info = usb_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ continue;
++ }
++
++ /* Get the next buffer */
++ usb_offset += amount;
++ fsg->usb_amount_left -= amount;
++ amount_left_to_req -= amount;
++ if (amount_left_to_req == 0)
++ get_some_more = 0;
++
++ /* Except at the end of the transfer, amount will be
++ * equal to the buffer size, which is divisible by
++ * the bulk-out maxpacket size.
++ */
++ set_bulk_out_req_length(fsg, bh, amount);
++ start_transfer(fsg, fsg->bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ continue;
++ }
++
++ /* Write the received data to the backing file */
++ bh = fsg->next_buffhd_to_drain;
++ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
++ break; // We stopped early
++ if (bh->state == BUF_STATE_FULL) {
++ smp_rmb();
++ fsg->next_buffhd_to_drain = bh->next;
++ bh->state = BUF_STATE_EMPTY;
++
++ /* Did something go wrong with the transfer? */
++ if (bh->outreq->status != 0) {
++ curlun->sense_data = SS_COMMUNICATION_FAILURE;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ amount = bh->outreq->actual;
++ if (curlun->file_length - file_offset < amount) {
++ LERROR(curlun,
++ "write %u @ %llu beyond end %llu\n",
++ amount, (unsigned long long) file_offset,
++ (unsigned long long) curlun->file_length);
++ amount = curlun->file_length - file_offset;
++ }
++
++ /* Don't accept excess data. The spec doesn't say
++ * what to do in this case. We'll ignore the error.
++ */
++ amount = min(amount, bh->bulk_out_intended_length);
++
++ /* Don't write a partial block */
++ amount = round_down(amount, curlun->blksize);
++ if (amount == 0)
++ goto empty_write;
++
++ /* Perform the write */
++ file_offset_tmp = file_offset;
++ nwritten = vfs_write(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
++ (unsigned long long) file_offset,
++ (int) nwritten);
++ if (signal_pending(current))
++ return -EINTR; // Interrupted!
++
++ if (nwritten < 0) {
++ LDBG(curlun, "error in file write: %d\n",
++ (int) nwritten);
++ nwritten = 0;
++ } else if (nwritten < amount) {
++ LDBG(curlun, "partial file write: %d/%u\n",
++ (int) nwritten, amount);
++ nwritten = round_down(nwritten, curlun->blksize);
++ }
++ file_offset += nwritten;
++ amount_left_to_write -= nwritten;
++ fsg->residue -= nwritten;
++
++ /* If an error occurred, report it and its position */
++ if (nwritten < amount) {
++ curlun->sense_data = SS_WRITE_ERROR;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ empty_write:
++ /* Did the host decide to stop early? */
++ if (bh->outreq->actual < bh->bulk_out_intended_length) {
++ fsg->short_packet_received = 1;
++ break;
++ }
++ continue;
++ }
++
++ /* Wait for something to happen */
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ return -EIO; // No default reply
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_synchronize_cache(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int rc;
++
++ /* We ignore the requested LBA and write out all file's
++ * dirty data buffers. */
++ rc = fsg_lun_fsync_sub(curlun);
++ if (rc)
++ curlun->sense_data = SS_WRITE_ERROR;
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void invalidate_sub(struct fsg_lun *curlun)
++{
++ struct file *filp = curlun->filp;
++ struct inode *inode = filp->f_path.dentry->d_inode;
++ unsigned long rc;
++
++ rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
++ VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
++}
++
++static int do_verify(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba;
++ u32 verification_length;
++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
++ loff_t file_offset, file_offset_tmp;
++ u32 amount_left;
++ unsigned int amount;
++ ssize_t nread;
++
++ /* Get the starting Logical Block Address and check that it's
++ * not too big */
++ lba = get_unaligned_be32(&fsg->cmnd[2]);
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++
++ /* We allow DPO (Disable Page Out = don't save data in the
++ * cache) but we don't implement it. */
++ if ((fsg->cmnd[1] & ~0x10) != 0) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ verification_length = get_unaligned_be16(&fsg->cmnd[7]);
++ if (unlikely(verification_length == 0))
++ return -EIO; // No default reply
++
++ /* Prepare to carry out the file verify */
++ amount_left = verification_length << curlun->blkbits;
++ file_offset = ((loff_t) lba) << curlun->blkbits;
++
++ /* Write out all the dirty buffers before invalidating them */
++ fsg_lun_fsync_sub(curlun);
++ if (signal_pending(current))
++ return -EINTR;
++
++ invalidate_sub(curlun);
++ if (signal_pending(current))
++ return -EINTR;
++
++ /* Just try to read the requested blocks */
++ while (amount_left > 0) {
++
++ /* Figure out how much we need to read:
++ * Try to read the remaining amount, but not more than
++ * the buffer size.
++ * And don't try to read past the end of the file.
++ */
++ amount = min((unsigned int) amount_left, mod_data.buflen);
++ amount = min((loff_t) amount,
++ curlun->file_length - file_offset);
++ if (amount == 0) {
++ curlun->sense_data =
++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ /* Perform the read */
++ file_offset_tmp = file_offset;
++ nread = vfs_read(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
++ (unsigned long long) file_offset,
++ (int) nread);
++ if (signal_pending(current))
++ return -EINTR;
++
++ if (nread < 0) {
++ LDBG(curlun, "error in file verify: %d\n",
++ (int) nread);
++ nread = 0;
++ } else if (nread < amount) {
++ LDBG(curlun, "partial file verify: %d/%u\n",
++ (int) nread, amount);
++ nread = round_down(nread, curlun->blksize);
++ }
++ if (nread == 0) {
++ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++ file_offset += nread;
++ amount_left -= nread;
++ }
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ u8 *buf = (u8 *) bh->buf;
++
++ static char vendor_id[] = "Linux ";
++ static char product_disk_id[] = "File-Stor Gadget";
++ static char product_cdrom_id[] = "File-CD Gadget ";
++
++ if (!fsg->curlun) { // Unsupported LUNs are okay
++ fsg->bad_lun_okay = 1;
++ memset(buf, 0, 36);
++ buf[0] = 0x7f; // Unsupported, no device-type
++ buf[4] = 31; // Additional length
++ return 36;
++ }
++
++ memset(buf, 0, 8);
++ buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
++ if (mod_data.removable)
++ buf[1] = 0x80;
++ buf[2] = 2; // ANSI SCSI level 2
++ buf[3] = 2; // SCSI-2 INQUIRY data format
++ buf[4] = 31; // Additional length
++ // No special options
++ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
++ (mod_data.cdrom ? product_cdrom_id :
++ product_disk_id),
++ mod_data.release);
++ return 36;
++}
++
++
++static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u8 *buf = (u8 *) bh->buf;
++ u32 sd, sdinfo;
++ int valid;
++
++ /*
++ * From the SCSI-2 spec., section 7.9 (Unit attention condition):
++ *
++ * If a REQUEST SENSE command is received from an initiator
++ * with a pending unit attention condition (before the target
++ * generates the contingent allegiance condition), then the
++ * target shall either:
++ * a) report any pending sense data and preserve the unit
++ * attention condition on the logical unit, or,
++ * b) report the unit attention condition, may discard any
++ * pending sense data, and clear the unit attention
++ * condition on the logical unit for that initiator.
++ *
++ * FSG normally uses option a); enable this code to use option b).
++ */
++#if 0
++ if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
++ curlun->sense_data = curlun->unit_attention_data;
++ curlun->unit_attention_data = SS_NO_SENSE;
++ }
++#endif
++
++ if (!curlun) { // Unsupported LUNs are okay
++ fsg->bad_lun_okay = 1;
++ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
++ sdinfo = 0;
++ valid = 0;
++ } else {
++ sd = curlun->sense_data;
++ sdinfo = curlun->sense_data_info;
++ valid = curlun->info_valid << 7;
++ curlun->sense_data = SS_NO_SENSE;
++ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
++ }
++
++ memset(buf, 0, 18);
++ buf[0] = valid | 0x70; // Valid, current error
++ buf[2] = SK(sd);
++ put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
++ buf[7] = 18 - 8; // Additional sense length
++ buf[12] = ASC(sd);
++ buf[13] = ASCQ(sd);
++ return 18;
++}
++
++
++static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
++ int pmi = fsg->cmnd[8];
++ u8 *buf = (u8 *) bh->buf;
++
++ /* Check the PMI and LBA fields */
++ if (pmi > 1 || (pmi == 0 && lba != 0)) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
++ /* Max logical block */
++ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
++ return 8;
++}
++
++
++static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int msf = fsg->cmnd[1] & 0x02;
++ u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
++ u8 *buf = (u8 *) bh->buf;
++
++ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++
++ memset(buf, 0, 8);
++ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
++ store_cdrom_address(&buf[4], msf, lba);
++ return 8;
++}
++
++
++static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int msf = fsg->cmnd[1] & 0x02;
++ int start_track = fsg->cmnd[6];
++ u8 *buf = (u8 *) bh->buf;
++
++ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
++ start_track > 1) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ memset(buf, 0, 20);
++ buf[1] = (20-2); /* TOC data length */
++ buf[2] = 1; /* First track number */
++ buf[3] = 1; /* Last track number */
++ buf[5] = 0x16; /* Data track, copying allowed */
++ buf[6] = 0x01; /* Only track is number 1 */
++ store_cdrom_address(&buf[8], msf, 0);
++
++ buf[13] = 0x16; /* Lead-out track is data */
++ buf[14] = 0xAA; /* Lead-out track number */
++ store_cdrom_address(&buf[16], msf, curlun->num_sectors);
++ return 20;
++}
++
++
++static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int mscmnd = fsg->cmnd[0];
++ u8 *buf = (u8 *) bh->buf;
++ u8 *buf0 = buf;
++ int pc, page_code;
++ int changeable_values, all_pages;
++ int valid_page = 0;
++ int len, limit;
++
++ if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ pc = fsg->cmnd[2] >> 6;
++ page_code = fsg->cmnd[2] & 0x3f;
++ if (pc == 3) {
++ curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
++ return -EINVAL;
++ }
++ changeable_values = (pc == 1);
++ all_pages = (page_code == 0x3f);
++
++ /* Write the mode parameter header. Fixed values are: default
++ * medium type, no cache control (DPOFUA), and no block descriptors.
++ * The only variable value is the WriteProtect bit. We will fill in
++ * the mode data length later. */
++ memset(buf, 0, 8);
++ if (mscmnd == MODE_SENSE) {
++ buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
++ buf += 4;
++ limit = 255;
++ } else { // MODE_SENSE_10
++ buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
++ buf += 8;
++ limit = 65535; // Should really be mod_data.buflen
++ }
++
++ /* No block descriptors */
++
++ /* The mode pages, in numerical order. The only page we support
++ * is the Caching page. */
++ if (page_code == 0x08 || all_pages) {
++ valid_page = 1;
++ buf[0] = 0x08; // Page code
++ buf[1] = 10; // Page length
++ memset(buf+2, 0, 10); // None of the fields are changeable
++
++ if (!changeable_values) {
++ buf[2] = 0x04; // Write cache enable,
++ // Read cache not disabled
++ // No cache retention priorities
++ put_unaligned_be16(0xffff, &buf[4]);
++ /* Don't disable prefetch */
++ /* Minimum prefetch = 0 */
++ put_unaligned_be16(0xffff, &buf[8]);
++ /* Maximum prefetch */
++ put_unaligned_be16(0xffff, &buf[10]);
++ /* Maximum prefetch ceiling */
++ }
++ buf += 12;
++ }
++
++ /* Check that a valid page was requested and the mode data length
++ * isn't too long. */
++ len = buf - buf0;
++ if (!valid_page || len > limit) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ /* Store the mode data length */
++ if (mscmnd == MODE_SENSE)
++ buf0[0] = len - 1;
++ else
++ put_unaligned_be16(len - 2, buf0);
++ return len;
++}
++
++
++static int do_start_stop(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int loej, start;
++
++ if (!mod_data.removable) {
++ curlun->sense_data = SS_INVALID_COMMAND;
++ return -EINVAL;
++ }
++
++ // int immed = fsg->cmnd[1] & 0x01;
++ loej = fsg->cmnd[4] & 0x02;
++ start = fsg->cmnd[4] & 0x01;
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++ if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
++ (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ if (!start) {
++
++ /* Are we allowed to unload the media? */
++ if (curlun->prevent_medium_removal) {
++ LDBG(curlun, "unload attempt prevented\n");
++ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
++ return -EINVAL;
++ }
++ if (loej) { // Simulate an unload/eject
++ up_read(&fsg->filesem);
++ down_write(&fsg->filesem);
++ fsg_lun_close(curlun);
++ up_write(&fsg->filesem);
++ down_read(&fsg->filesem);
++ }
++ } else {
++
++ /* Our emulation doesn't support mounting; the medium is
++ * available for use as soon as it is loaded. */
++ if (!fsg_lun_is_open(curlun)) {
++ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
++ return -EINVAL;
++ }
++ }
++#endif
++ return 0;
++}
++
++
++static int do_prevent_allow(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int prevent;
++
++ if (!mod_data.removable) {
++ curlun->sense_data = SS_INVALID_COMMAND;
++ return -EINVAL;
++ }
++
++ prevent = fsg->cmnd[4] & 0x01;
++ if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ if (curlun->prevent_medium_removal && !prevent)
++ fsg_lun_fsync_sub(curlun);
++ curlun->prevent_medium_removal = prevent;
++ return 0;
++}
++
++
++static int do_read_format_capacities(struct fsg_dev *fsg,
++ struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u8 *buf = (u8 *) bh->buf;
++
++ buf[0] = buf[1] = buf[2] = 0;
++ buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
++ buf += 4;
++
++ put_unaligned_be32(curlun->num_sectors, &buf[0]);
++ /* Number of blocks */
++ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
++ buf[4] = 0x02; /* Current capacity */
++ return 12;
++}
++
++
++static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++
++ /* We don't support MODE SELECT */
++ curlun->sense_data = SS_INVALID_COMMAND;
++ return -EINVAL;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
++{
++ int rc;
++
++ rc = fsg_set_halt(fsg, fsg->bulk_in);
++ if (rc == -EAGAIN)
++ VDBG(fsg, "delayed bulk-in endpoint halt\n");
++ while (rc != 0) {
++ if (rc != -EAGAIN) {
++ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
++ rc = 0;
++ break;
++ }
++
++ /* Wait for a short time and then try again */
++ if (msleep_interruptible(100) != 0)
++ return -EINTR;
++ rc = usb_ep_set_halt(fsg->bulk_in);
++ }
++ return rc;
++}
++
++static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
++{
++ int rc;
++
++ DBG(fsg, "bulk-in set wedge\n");
++ rc = usb_ep_set_wedge(fsg->bulk_in);
++ if (rc == -EAGAIN)
++ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
++ while (rc != 0) {
++ if (rc != -EAGAIN) {
++ WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
++ rc = 0;
++ break;
++ }
++
++ /* Wait for a short time and then try again */
++ if (msleep_interruptible(100) != 0)
++ return -EINTR;
++ rc = usb_ep_set_wedge(fsg->bulk_in);
++ }
++ return rc;
++}
++
++static int throw_away_data(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh;
++ u32 amount;
++ int rc;
++
++ while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
++ fsg->usb_amount_left > 0) {
++
++ /* Throw away the data in a filled buffer */
++ if (bh->state == BUF_STATE_FULL) {
++ smp_rmb();
++ bh->state = BUF_STATE_EMPTY;
++ fsg->next_buffhd_to_drain = bh->next;
++
++ /* A short packet or an error ends everything */
++ if (bh->outreq->actual < bh->bulk_out_intended_length ||
++ bh->outreq->status != 0) {
++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ return -EINTR;
++ }
++ continue;
++ }
++
++ /* Try to submit another request if we need one */
++ bh = fsg->next_buffhd_to_fill;
++ if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
++ amount = min(fsg->usb_amount_left,
++ (u32) mod_data.buflen);
++
++ /* Except at the end of the transfer, amount will be
++ * equal to the buffer size, which is divisible by
++ * the bulk-out maxpacket size.
++ */
++ set_bulk_out_req_length(fsg, bh, amount);
++ start_transfer(fsg, fsg->bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ fsg->usb_amount_left -= amount;
++ continue;
++ }
++
++ /* Otherwise wait for something to happen */
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++ return 0;
++}
++
++
++static int finish_reply(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
++ int rc = 0;
++
++ switch (fsg->data_dir) {
++ case DATA_DIR_NONE:
++ break; // Nothing to send
++
++ /* If we don't know whether the host wants to read or write,
++ * this must be CB or CBI with an unknown command. We mustn't
++ * try to send or receive any data. So stall both bulk pipes
++ * if we can and wait for a reset. */
++ case DATA_DIR_UNKNOWN:
++ if (mod_data.can_stall) {
++ fsg_set_halt(fsg, fsg->bulk_out);
++ rc = halt_bulk_in_endpoint(fsg);
++ }
++ break;
++
++ /* All but the last buffer of data must have already been sent */
++ case DATA_DIR_TO_HOST:
++ if (fsg->data_size == 0)
++ ; // Nothing to send
++
++ /* If there's no residue, simply send the last buffer */
++ else if (fsg->residue == 0) {
++ bh->inreq->zero = 0;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ }
++
++ /* There is a residue. For CB and CBI, simply mark the end
++ * of the data with a short packet. However, if we are
++ * allowed to stall, there was no data at all (residue ==
++ * data_size), and the command failed (invalid LUN or
++ * sense data is set), then halt the bulk-in endpoint
++ * instead. */
++ else if (!transport_is_bbb()) {
++ if (mod_data.can_stall &&
++ fsg->residue == fsg->data_size &&
++ (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
++ bh->state = BUF_STATE_EMPTY;
++ rc = halt_bulk_in_endpoint(fsg);
++ } else {
++ bh->inreq->zero = 1;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ }
++ }
++
++ /*
++ * For Bulk-only, mark the end of the data with a short
++ * packet. If we are allowed to stall, halt the bulk-in
++ * endpoint. (Note: This violates the Bulk-Only Transport
++ * specification, which requires us to pad the data if we
++ * don't halt the endpoint. Presumably nobody will mind.)
++ */
++ else {
++ bh->inreq->zero = 1;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ if (mod_data.can_stall)
++ rc = halt_bulk_in_endpoint(fsg);
++ }
++ break;
++
++ /* We have processed all we want from the data the host has sent.
++ * There may still be outstanding bulk-out requests. */
++ case DATA_DIR_FROM_HOST:
++ if (fsg->residue == 0)
++ ; // Nothing to receive
++
++ /* Did the host stop sending unexpectedly early? */
++ else if (fsg->short_packet_received) {
++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ rc = -EINTR;
++ }
++
++ /* We haven't processed all the incoming data. Even though
++ * we may be allowed to stall, doing so would cause a race.
++ * The controller may already have ACK'ed all the remaining
++ * bulk-out packets, in which case the host wouldn't see a
++ * STALL. Not realizing the endpoint was halted, it wouldn't
++ * clear the halt -- leading to problems later on. */
++#if 0
++ else if (mod_data.can_stall) {
++ fsg_set_halt(fsg, fsg->bulk_out);
++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ rc = -EINTR;
++ }
++#endif
++
++ /* We can't stall. Read in the excess data and throw it
++ * all away. */
++ else
++ rc = throw_away_data(fsg);
++ break;
++ }
++ return rc;
++}
++
++
++static int send_status(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ struct fsg_buffhd *bh;
++ int rc;
++ u8 status = US_BULK_STAT_OK;
++ u32 sd, sdinfo = 0;
++
++ /* Wait for the next buffer to become available */
++ bh = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ if (curlun) {
++ sd = curlun->sense_data;
++ sdinfo = curlun->sense_data_info;
++ } else if (fsg->bad_lun_okay)
++ sd = SS_NO_SENSE;
++ else
++ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
++
++ if (fsg->phase_error) {
++ DBG(fsg, "sending phase-error status\n");
++ status = US_BULK_STAT_PHASE;
++ sd = SS_INVALID_COMMAND;
++ } else if (sd != SS_NO_SENSE) {
++ DBG(fsg, "sending command-failure status\n");
++ status = US_BULK_STAT_FAIL;
++ VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
++ " info x%x\n",
++ SK(sd), ASC(sd), ASCQ(sd), sdinfo);
++ }
++
++ if (transport_is_bbb()) {
++ struct bulk_cs_wrap *csw = bh->buf;
++
++ /* Store and send the Bulk-only CSW */
++ csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
++ csw->Tag = fsg->tag;
++ csw->Residue = cpu_to_le32(fsg->residue);
++ csw->Status = status;
++
++ bh->inreq->length = US_BULK_CS_WRAP_LEN;
++ bh->inreq->zero = 0;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++
++ } else if (mod_data.transport_type == USB_PR_CB) {
++
++ /* Control-Bulk transport has no status phase! */
++ return 0;
++
++ } else { // USB_PR_CBI
++ struct interrupt_data *buf = bh->buf;
++
++ /* Store and send the Interrupt data. UFI sends the ASC
++ * and ASCQ bytes. Everything else sends a Type (which
++ * is always 0) and the status Value. */
++ if (mod_data.protocol_type == USB_SC_UFI) {
++ buf->bType = ASC(sd);
++ buf->bValue = ASCQ(sd);
++ } else {
++ buf->bType = 0;
++ buf->bValue = status;
++ }
++ fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
++
++ fsg->intr_buffhd = bh; // Point to the right buffhd
++ fsg->intreq->buf = bh->inreq->buf;
++ fsg->intreq->context = bh;
++ start_transfer(fsg, fsg->intr_in, fsg->intreq,
++ &fsg->intreq_busy, &bh->state);
++ }
++
++ fsg->next_buffhd_to_fill = bh->next;
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Check whether the command is properly formed and whether its data size
++ * and direction agree with the values we already have. */
++static int check_command(struct fsg_dev *fsg, int cmnd_size,
++ enum data_direction data_dir, unsigned int mask,
++ int needs_medium, const char *name)
++{
++ int i;
++ int lun = fsg->cmnd[1] >> 5;
++ static const char dirletter[4] = {'u', 'o', 'i', 'n'};
++ char hdlen[20];
++ struct fsg_lun *curlun;
++
++ /* Adjust the expected cmnd_size for protocol encapsulation padding.
++ * Transparent SCSI doesn't pad. */
++ if (protocol_is_scsi())
++ ;
++
++ /* There's some disagreement as to whether RBC pads commands or not.
++ * We'll play it safe and accept either form. */
++ else if (mod_data.protocol_type == USB_SC_RBC) {
++ if (fsg->cmnd_size == 12)
++ cmnd_size = 12;
++
++ /* All the other protocols pad to 12 bytes */
++ } else
++ cmnd_size = 12;
++
++ hdlen[0] = 0;
++ if (fsg->data_dir != DATA_DIR_UNKNOWN)
++ sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
++ fsg->data_size);
++ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
++ name, cmnd_size, dirletter[(int) data_dir],
++ fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
++
++ /* We can't reply at all until we know the correct data direction
++ * and size. */
++ if (fsg->data_size_from_cmnd == 0)
++ data_dir = DATA_DIR_NONE;
++ if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
++ fsg->data_dir = data_dir;
++ fsg->data_size = fsg->data_size_from_cmnd;
++
++ } else { // Bulk-only
++ if (fsg->data_size < fsg->data_size_from_cmnd) {
++
++ /* Host data size < Device data size is a phase error.
++ * Carry out the command, but only transfer as much
++ * as we are allowed. */
++ fsg->data_size_from_cmnd = fsg->data_size;
++ fsg->phase_error = 1;
++ }
++ }
++ fsg->residue = fsg->usb_amount_left = fsg->data_size;
++
++ /* Conflicting data directions is a phase error */
++ if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
++ fsg->phase_error = 1;
++ return -EINVAL;
++ }
++
++ /* Verify the length of the command itself */
++ if (cmnd_size != fsg->cmnd_size) {
++
++ /* Special case workaround: There are plenty of buggy SCSI
++ * implementations. Many have issues with cbw->Length
++ * field passing a wrong command size. For those cases we
++ * always try to work around the problem by using the length
++ * sent by the host side provided it is at least as large
++ * as the correct command length.
++ * Examples of such cases would be MS-Windows, which issues
++ * REQUEST SENSE with cbw->Length == 12 where it should
++ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
++ * REQUEST SENSE with cbw->Length == 10 where it should
++ * be 6 as well.
++ */
++ if (cmnd_size <= fsg->cmnd_size) {
++ DBG(fsg, "%s is buggy! Expected length %d "
++ "but we got %d\n", name,
++ cmnd_size, fsg->cmnd_size);
++ cmnd_size = fsg->cmnd_size;
++ } else {
++ fsg->phase_error = 1;
++ return -EINVAL;
++ }
++ }
++
++ /* Check that the LUN values are consistent */
++ if (transport_is_bbb()) {
++ if (fsg->lun != lun)
++ DBG(fsg, "using LUN %d from CBW, "
++ "not LUN %d from CDB\n",
++ fsg->lun, lun);
++ }
++
++ /* Check the LUN */
++ curlun = fsg->curlun;
++ if (curlun) {
++ if (fsg->cmnd[0] != REQUEST_SENSE) {
++ curlun->sense_data = SS_NO_SENSE;
++ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
++ }
++ } else {
++ fsg->bad_lun_okay = 0;
++
++ /* INQUIRY and REQUEST SENSE commands are explicitly allowed
++ * to use unsupported LUNs; all others may not. */
++ if (fsg->cmnd[0] != INQUIRY &&
++ fsg->cmnd[0] != REQUEST_SENSE) {
++ DBG(fsg, "unsupported LUN %d\n", fsg->lun);
++ return -EINVAL;
++ }
++ }
++
++ /* If a unit attention condition exists, only INQUIRY and
++ * REQUEST SENSE commands are allowed; anything else must fail. */
++ if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
++ fsg->cmnd[0] != INQUIRY &&
++ fsg->cmnd[0] != REQUEST_SENSE) {
++ curlun->sense_data = curlun->unit_attention_data;
++ curlun->unit_attention_data = SS_NO_SENSE;
++ return -EINVAL;
++ }
++
++ /* Check that only command bytes listed in the mask are non-zero */
++ fsg->cmnd[1] &= 0x1f; // Mask away the LUN
++ for (i = 1; i < cmnd_size; ++i) {
++ if (fsg->cmnd[i] && !(mask & (1 << i))) {
++ if (curlun)
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ }
++
++ /* If the medium isn't mounted and the command needs to access
++ * it, return an error. */
++ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
++ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* wrapper of check_command for data size in blocks handling */
++static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
++ enum data_direction data_dir, unsigned int mask,
++ int needs_medium, const char *name)
++{
++ if (fsg->curlun)
++ fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
++ return check_command(fsg, cmnd_size, data_dir,
++ mask, needs_medium, name);
++}
++
++static int do_scsi_command(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh;
++ int rc;
++ int reply = -EINVAL;
++ int i;
++ static char unknown[16];
++
++ dump_cdb(fsg);
++
++ /* Wait for the next buffer to become available for data or status */
++ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++ fsg->phase_error = 0;
++ fsg->short_packet_received = 0;
++
++ down_read(&fsg->filesem); // We're using the backing file
++ switch (fsg->cmnd[0]) {
++
++ case INQUIRY:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<4), 0,
++ "INQUIRY")) == 0)
++ reply = do_inquiry(fsg, bh);
++ break;
++
++ case MODE_SELECT:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
++ (1<<1) | (1<<4), 0,
++ "MODE SELECT(6)")) == 0)
++ reply = do_mode_select(fsg, bh);
++ break;
++
++ case MODE_SELECT_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
++ (1<<1) | (3<<7), 0,
++ "MODE SELECT(10)")) == 0)
++ reply = do_mode_select(fsg, bh);
++ break;
++
++ case MODE_SENSE:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<1) | (1<<2) | (1<<4), 0,
++ "MODE SENSE(6)")) == 0)
++ reply = do_mode_sense(fsg, bh);
++ break;
++
++ case MODE_SENSE_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (1<<1) | (1<<2) | (3<<7), 0,
++ "MODE SENSE(10)")) == 0)
++ reply = do_mode_sense(fsg, bh);
++ break;
++
++ case ALLOW_MEDIUM_REMOVAL:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
++ (1<<4), 0,
++ "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
++ reply = do_prevent_allow(fsg);
++ break;
++
++ case READ_6:
++ i = fsg->cmnd[4];
++ fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
++ if ((reply = check_command_size_in_blocks(fsg, 6,
++ DATA_DIR_TO_HOST,
++ (7<<1) | (1<<4), 1,
++ "READ(6)")) == 0)
++ reply = do_read(fsg);
++ break;
++
++ case READ_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command_size_in_blocks(fsg, 10,
++ DATA_DIR_TO_HOST,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "READ(10)")) == 0)
++ reply = do_read(fsg);
++ break;
++
++ case READ_12:
++ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
++ if ((reply = check_command_size_in_blocks(fsg, 12,
++ DATA_DIR_TO_HOST,
++ (1<<1) | (0xf<<2) | (0xf<<6), 1,
++ "READ(12)")) == 0)
++ reply = do_read(fsg);
++ break;
++
++ case READ_CAPACITY:
++ fsg->data_size_from_cmnd = 8;
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (0xf<<2) | (1<<8), 1,
++ "READ CAPACITY")) == 0)
++ reply = do_read_capacity(fsg, bh);
++ break;
++
++ case READ_HEADER:
++ if (!mod_data.cdrom)
++ goto unknown_cmnd;
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (3<<7) | (0x1f<<1), 1,
++ "READ HEADER")) == 0)
++ reply = do_read_header(fsg, bh);
++ break;
++
++ case READ_TOC:
++ if (!mod_data.cdrom)
++ goto unknown_cmnd;
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (7<<6) | (1<<1), 1,
++ "READ TOC")) == 0)
++ reply = do_read_toc(fsg, bh);
++ break;
++
++ case READ_FORMAT_CAPACITIES:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (3<<7), 1,
++ "READ FORMAT CAPACITIES")) == 0)
++ reply = do_read_format_capacities(fsg, bh);
++ break;
++
++ case REQUEST_SENSE:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<4), 0,
++ "REQUEST SENSE")) == 0)
++ reply = do_request_sense(fsg, bh);
++ break;
++
++ case START_STOP:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
++ (1<<1) | (1<<4), 0,
++ "START-STOP UNIT")) == 0)
++ reply = do_start_stop(fsg);
++ break;
++
++ case SYNCHRONIZE_CACHE:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
++ (0xf<<2) | (3<<7), 1,
++ "SYNCHRONIZE CACHE")) == 0)
++ reply = do_synchronize_cache(fsg);
++ break;
++
++ case TEST_UNIT_READY:
++ fsg->data_size_from_cmnd = 0;
++ reply = check_command(fsg, 6, DATA_DIR_NONE,
++ 0, 1,
++ "TEST UNIT READY");
++ break;
++
++ /* Although optional, this command is used by MS-Windows. We
++ * support a minimal version: BytChk must be 0. */
++ case VERIFY:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "VERIFY")) == 0)
++ reply = do_verify(fsg);
++ break;
++
++ case WRITE_6:
++ i = fsg->cmnd[4];
++ fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
++ if ((reply = check_command_size_in_blocks(fsg, 6,
++ DATA_DIR_FROM_HOST,
++ (7<<1) | (1<<4), 1,
++ "WRITE(6)")) == 0)
++ reply = do_write(fsg);
++ break;
++
++ case WRITE_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command_size_in_blocks(fsg, 10,
++ DATA_DIR_FROM_HOST,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "WRITE(10)")) == 0)
++ reply = do_write(fsg);
++ break;
++
++ case WRITE_12:
++ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
++ if ((reply = check_command_size_in_blocks(fsg, 12,
++ DATA_DIR_FROM_HOST,
++ (1<<1) | (0xf<<2) | (0xf<<6), 1,
++ "WRITE(12)")) == 0)
++ reply = do_write(fsg);
++ break;
++
++ /* Some mandatory commands that we recognize but don't implement.
++ * They don't mean much in this setting. It's left as an exercise
++ * for anyone interested to implement RESERVE and RELEASE in terms
++ * of Posix locks. */
++ case FORMAT_UNIT:
++ case RELEASE:
++ case RESERVE:
++ case SEND_DIAGNOSTIC:
++ // Fall through
++
++ default:
++ unknown_cmnd:
++ fsg->data_size_from_cmnd = 0;
++ sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
++ if ((reply = check_command(fsg, fsg->cmnd_size,
++ DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
++ fsg->curlun->sense_data = SS_INVALID_COMMAND;
++ reply = -EINVAL;
++ }
++ break;
++ }
++ up_read(&fsg->filesem);
++
++ if (reply == -EINTR || signal_pending(current))
++ return -EINTR;
++
++ /* Set up the single reply buffer for finish_reply() */
++ if (reply == -EINVAL)
++ reply = 0; // Error reply length
++ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
++ reply = min((u32) reply, fsg->data_size_from_cmnd);
++ bh->inreq->length = reply;
++ bh->state = BUF_STATE_FULL;
++ fsg->residue -= reply;
++ } // Otherwise it's already set
++
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct usb_request *req = bh->outreq;
++ struct bulk_cb_wrap *cbw = req->buf;
++
++ /* Was this a real packet? Should it be ignored? */
++ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
++ return -EINVAL;
++
++ /* Is the CBW valid? */
++ if (req->actual != US_BULK_CB_WRAP_LEN ||
++ cbw->Signature != cpu_to_le32(
++ US_BULK_CB_SIGN)) {
++ DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
++ req->actual,
++ le32_to_cpu(cbw->Signature));
++
++ /* The Bulk-only spec says we MUST stall the IN endpoint
++ * (6.6.1), so it's unavoidable. It also says we must
++ * retain this state until the next reset, but there's
++ * no way to tell the controller driver it should ignore
++ * Clear-Feature(HALT) requests.
++ *
++ * We aren't required to halt the OUT endpoint; instead
++ * we can simply accept and discard any data received
++ * until the next reset. */
++ wedge_bulk_in_endpoint(fsg);
++ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
++ return -EINVAL;
++ }
++
++ /* Is the CBW meaningful? */
++ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
++ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
++ DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
++ "cmdlen %u\n",
++ cbw->Lun, cbw->Flags, cbw->Length);
++
++ /* We can do anything we want here, so let's stall the
++ * bulk pipes if we are allowed to. */
++ if (mod_data.can_stall) {
++ fsg_set_halt(fsg, fsg->bulk_out);
++ halt_bulk_in_endpoint(fsg);
++ }
++ return -EINVAL;
++ }
++
++ /* Save the command for later */
++ fsg->cmnd_size = cbw->Length;
++ memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
++ if (cbw->Flags & US_BULK_FLAG_IN)
++ fsg->data_dir = DATA_DIR_TO_HOST;
++ else
++ fsg->data_dir = DATA_DIR_FROM_HOST;
++ fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
++ if (fsg->data_size == 0)
++ fsg->data_dir = DATA_DIR_NONE;
++ fsg->lun = cbw->Lun;
++ fsg->tag = cbw->Tag;
++ return 0;
++}
++
++
++static int get_next_command(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh;
++ int rc = 0;
++
++ if (transport_is_bbb()) {
++
++ /* Wait for the next buffer to become available */
++ bh = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ /* Queue a request to read a Bulk-only CBW */
++ set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
++ start_transfer(fsg, fsg->bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state);
++
++ /* We will drain the buffer in software, which means we
++ * can reuse it for the next filling. No need to advance
++ * next_buffhd_to_fill. */
++
++ /* Wait for the CBW to arrive */
++ while (bh->state != BUF_STATE_FULL) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++ smp_rmb();
++ rc = received_cbw(fsg, bh);
++ bh->state = BUF_STATE_EMPTY;
++
++ } else { // USB_PR_CB or USB_PR_CBI
++
++ /* Wait for the next command to arrive */
++ while (fsg->cbbuf_cmnd_size == 0) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ /* Is the previous status interrupt request still busy?
++ * The host is allowed to skip reading the status,
++ * so we must cancel it. */
++ if (fsg->intreq_busy)
++ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
++
++ /* Copy the command and mark the buffer empty */
++ fsg->data_dir = DATA_DIR_UNKNOWN;
++ spin_lock_irq(&fsg->lock);
++ fsg->cmnd_size = fsg->cbbuf_cmnd_size;
++ memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
++ fsg->cbbuf_cmnd_size = 0;
++ spin_unlock_irq(&fsg->lock);
++
++ /* Use LUN from the command */
++ fsg->lun = fsg->cmnd[1] >> 5;
++ }
++
++ /* Update current lun */
++ if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
++ fsg->curlun = &fsg->luns[fsg->lun];
++ else
++ fsg->curlun = NULL;
++
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
++ const struct usb_endpoint_descriptor *d)
++{
++ int rc;
++
++ ep->driver_data = fsg;
++ ep->desc = d;
++ rc = usb_ep_enable(ep);
++ if (rc)
++ ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
++ return rc;
++}
++
++static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
++ struct usb_request **preq)
++{
++ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
++ if (*preq)
++ return 0;
++ ERROR(fsg, "can't allocate request for %s\n", ep->name);
++ return -ENOMEM;
++}
++
++/*
++ * Reset interface setting and re-init endpoint state (toggle etc).
++ * Call with altsetting < 0 to disable the interface. The only other
++ * available altsetting is 0, which enables the interface.
++ */
++static int do_set_interface(struct fsg_dev *fsg, int altsetting)
++{
++ int rc = 0;
++ int i;
++ const struct usb_endpoint_descriptor *d;
++
++ if (fsg->running)
++ DBG(fsg, "reset interface\n");
++
++reset:
++ /* Deallocate the requests */
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ struct fsg_buffhd *bh = &fsg->buffhds[i];
++
++ if (bh->inreq) {
++ usb_ep_free_request(fsg->bulk_in, bh->inreq);
++ bh->inreq = NULL;
++ }
++ if (bh->outreq) {
++ usb_ep_free_request(fsg->bulk_out, bh->outreq);
++ bh->outreq = NULL;
++ }
++ }
++ if (fsg->intreq) {
++ usb_ep_free_request(fsg->intr_in, fsg->intreq);
++ fsg->intreq = NULL;
++ }
++
++ /* Disable the endpoints */
++ if (fsg->bulk_in_enabled) {
++ usb_ep_disable(fsg->bulk_in);
++ fsg->bulk_in_enabled = 0;
++ }
++ if (fsg->bulk_out_enabled) {
++ usb_ep_disable(fsg->bulk_out);
++ fsg->bulk_out_enabled = 0;
++ }
++ if (fsg->intr_in_enabled) {
++ usb_ep_disable(fsg->intr_in);
++ fsg->intr_in_enabled = 0;
++ }
++
++ fsg->running = 0;
++ if (altsetting < 0 || rc != 0)
++ return rc;
++
++ DBG(fsg, "set interface %d\n", altsetting);
++
++ /* Enable the endpoints */
++ d = fsg_ep_desc(fsg->gadget,
++ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
++ &fsg_ss_bulk_in_desc);
++ if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
++ goto reset;
++ fsg->bulk_in_enabled = 1;
++
++ d = fsg_ep_desc(fsg->gadget,
++ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
++ &fsg_ss_bulk_out_desc);
++ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
++ goto reset;
++ fsg->bulk_out_enabled = 1;
++ fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
++ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
++
++ if (transport_is_cbi()) {
++ d = fsg_ep_desc(fsg->gadget,
++ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
++ &fsg_ss_intr_in_desc);
++ if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
++ goto reset;
++ fsg->intr_in_enabled = 1;
++ }
++
++ /* Allocate the requests */
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ struct fsg_buffhd *bh = &fsg->buffhds[i];
++
++ if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
++ goto reset;
++ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
++ goto reset;
++ bh->inreq->buf = bh->outreq->buf = bh->buf;
++ bh->inreq->context = bh->outreq->context = bh;
++ bh->inreq->complete = bulk_in_complete;
++ bh->outreq->complete = bulk_out_complete;
++ }
++ if (transport_is_cbi()) {
++ if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
++ goto reset;
++ fsg->intreq->complete = intr_in_complete;
++ }
++
++ fsg->running = 1;
++ for (i = 0; i < fsg->nluns; ++i)
++ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
++ return rc;
++}
++
++
++/*
++ * Change our operational configuration. This code must agree with the code
++ * that returns config descriptors, and with interface altsetting code.
++ *
++ * It's also responsible for power management interactions. Some
++ * configurations might not work with our current power sources.
++ * For now we just assume the gadget is always self-powered.
++ */
++static int do_set_config(struct fsg_dev *fsg, u8 new_config)
++{
++ int rc = 0;
++
++ /* Disable the single interface */
++ if (fsg->config != 0) {
++ DBG(fsg, "reset config\n");
++ fsg->config = 0;
++ rc = do_set_interface(fsg, -1);
++ }
++
++ /* Enable the interface */
++ if (new_config != 0) {
++ fsg->config = new_config;
++ if ((rc = do_set_interface(fsg, 0)) != 0)
++ fsg->config = 0; // Reset on errors
++ else
++ INFO(fsg, "%s config #%d\n",
++ usb_speed_string(fsg->gadget->speed),
++ fsg->config);
++ }
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void handle_exception(struct fsg_dev *fsg)
++{
++ siginfo_t info;
++ int sig;
++ int i;
++ int num_active;
++ struct fsg_buffhd *bh;
++ enum fsg_state old_state;
++ u8 new_config;
++ struct fsg_lun *curlun;
++ unsigned int exception_req_tag;
++ int rc;
++
++ /* Clear the existing signals. Anything but SIGUSR1 is converted
++ * into a high-priority EXIT exception. */
++ for (;;) {
++ sig = dequeue_signal_lock(current, &current->blocked, &info);
++ if (!sig)
++ break;
++ if (sig != SIGUSR1) {
++ if (fsg->state < FSG_STATE_EXIT)
++ DBG(fsg, "Main thread exiting on signal\n");
++ raise_exception(fsg, FSG_STATE_EXIT);
++ }
++ }
++
++ /* Cancel all the pending transfers */
++ if (fsg->intreq_busy)
++ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ bh = &fsg->buffhds[i];
++ if (bh->inreq_busy)
++ usb_ep_dequeue(fsg->bulk_in, bh->inreq);
++ if (bh->outreq_busy)
++ usb_ep_dequeue(fsg->bulk_out, bh->outreq);
++ }
++
++ /* Wait until everything is idle */
++ for (;;) {
++ num_active = fsg->intreq_busy;
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ bh = &fsg->buffhds[i];
++ num_active += bh->inreq_busy + bh->outreq_busy;
++ }
++ if (num_active == 0)
++ break;
++ if (sleep_thread(fsg))
++ return;
++ }
++
++ /* Clear out the controller's fifos */
++ if (fsg->bulk_in_enabled)
++ usb_ep_fifo_flush(fsg->bulk_in);
++ if (fsg->bulk_out_enabled)
++ usb_ep_fifo_flush(fsg->bulk_out);
++ if (fsg->intr_in_enabled)
++ usb_ep_fifo_flush(fsg->intr_in);
++
++ /* Reset the I/O buffer states and pointers, the SCSI
++ * state, and the exception. Then invoke the handler. */
++ spin_lock_irq(&fsg->lock);
++
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ bh = &fsg->buffhds[i];
++ bh->state = BUF_STATE_EMPTY;
++ }
++ fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
++ &fsg->buffhds[0];
++
++ exception_req_tag = fsg->exception_req_tag;
++ new_config = fsg->new_config;
++ old_state = fsg->state;
++
++ if (old_state == FSG_STATE_ABORT_BULK_OUT)
++ fsg->state = FSG_STATE_STATUS_PHASE;
++ else {
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ curlun->prevent_medium_removal = 0;
++ curlun->sense_data = curlun->unit_attention_data =
++ SS_NO_SENSE;
++ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
++ }
++ fsg->state = FSG_STATE_IDLE;
++ }
++ spin_unlock_irq(&fsg->lock);
++
++ /* Carry out any extra actions required for the exception */
++ switch (old_state) {
++ default:
++ break;
++
++ case FSG_STATE_ABORT_BULK_OUT:
++ send_status(fsg);
++ spin_lock_irq(&fsg->lock);
++ if (fsg->state == FSG_STATE_STATUS_PHASE)
++ fsg->state = FSG_STATE_IDLE;
++ spin_unlock_irq(&fsg->lock);
++ break;
++
++ case FSG_STATE_RESET:
++ /* In case we were forced against our will to halt a
++ * bulk endpoint, clear the halt now. (The SuperH UDC
++ * requires this.) */
++ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
++ usb_ep_clear_halt(fsg->bulk_in);
++
++ if (transport_is_bbb()) {
++ if (fsg->ep0_req_tag == exception_req_tag)
++ ep0_queue(fsg); // Complete the status stage
++
++ } else if (transport_is_cbi())
++ send_status(fsg); // Status by interrupt pipe
++
++ /* Technically this should go here, but it would only be
++ * a waste of time. Ditto for the INTERFACE_CHANGE and
++ * CONFIG_CHANGE cases. */
++ // for (i = 0; i < fsg->nluns; ++i)
++ // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
++ break;
++
++ case FSG_STATE_INTERFACE_CHANGE:
++ rc = do_set_interface(fsg, 0);
++ if (fsg->ep0_req_tag != exception_req_tag)
++ break;
++ if (rc != 0) // STALL on errors
++ fsg_set_halt(fsg, fsg->ep0);
++ else // Complete the status stage
++ ep0_queue(fsg);
++ break;
++
++ case FSG_STATE_CONFIG_CHANGE:
++ rc = do_set_config(fsg, new_config);
++ if (fsg->ep0_req_tag != exception_req_tag)
++ break;
++ if (rc != 0) // STALL on errors
++ fsg_set_halt(fsg, fsg->ep0);
++ else // Complete the status stage
++ ep0_queue(fsg);
++ break;
++
++ case FSG_STATE_DISCONNECT:
++ for (i = 0; i < fsg->nluns; ++i)
++ fsg_lun_fsync_sub(fsg->luns + i);
++ do_set_config(fsg, 0); // Unconfigured state
++ break;
++
++ case FSG_STATE_EXIT:
++ case FSG_STATE_TERMINATED:
++ do_set_config(fsg, 0); // Free resources
++ spin_lock_irq(&fsg->lock);
++ fsg->state = FSG_STATE_TERMINATED; // Stop the thread
++ spin_unlock_irq(&fsg->lock);
++ break;
++ }
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int fsg_main_thread(void *fsg_)
++{
++ struct fsg_dev *fsg = fsg_;
++
++ /* Allow the thread to be killed by a signal, but set the signal mask
++ * to block everything but INT, TERM, KILL, and USR1. */
++ allow_signal(SIGINT);
++ allow_signal(SIGTERM);
++ allow_signal(SIGKILL);
++ allow_signal(SIGUSR1);
++
++ /* Allow the thread to be frozen */
++ set_freezable();
++
++ /* Arrange for userspace references to be interpreted as kernel
++ * pointers. That way we can pass a kernel pointer to a routine
++ * that expects a __user pointer and it will work okay. */
++ set_fs(get_ds());
++
++ /* The main loop */
++ while (fsg->state != FSG_STATE_TERMINATED) {
++ if (exception_in_progress(fsg) || signal_pending(current)) {
++ handle_exception(fsg);
++ continue;
++ }
++
++ if (!fsg->running) {
++ sleep_thread(fsg);
++ continue;
++ }
++
++ if (get_next_command(fsg))
++ continue;
++
++ spin_lock_irq(&fsg->lock);
++ if (!exception_in_progress(fsg))
++ fsg->state = FSG_STATE_DATA_PHASE;
++ spin_unlock_irq(&fsg->lock);
++
++ if (do_scsi_command(fsg) || finish_reply(fsg))
++ continue;
++
++ spin_lock_irq(&fsg->lock);
++ if (!exception_in_progress(fsg))
++ fsg->state = FSG_STATE_STATUS_PHASE;
++ spin_unlock_irq(&fsg->lock);
++
++ if (send_status(fsg))
++ continue;
++
++ spin_lock_irq(&fsg->lock);
++ if (!exception_in_progress(fsg))
++ fsg->state = FSG_STATE_IDLE;
++ spin_unlock_irq(&fsg->lock);
++ }
++
++ spin_lock_irq(&fsg->lock);
++ fsg->thread_task = NULL;
++ spin_unlock_irq(&fsg->lock);
++
++ /* If we are exiting because of a signal, unregister the
++ * gadget driver. */
++ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
++ usb_gadget_unregister_driver(&fsg_driver);
++
++ /* Let the unbind and cleanup routines know the thread has exited */
++ complete_and_exit(&fsg->thread_notifier, 0);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++
++/* The write permissions and store_xxx pointers are set in fsg_bind() */
++static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
++static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
++static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
++
++
++/*-------------------------------------------------------------------------*/
++
++static void fsg_release(struct kref *ref)
++{
++ struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
++
++ kfree(fsg->luns);
++ kfree(fsg);
++}
++
++static void lun_release(struct device *dev)
++{
++ struct rw_semaphore *filesem = dev_get_drvdata(dev);
++ struct fsg_dev *fsg =
++ container_of(filesem, struct fsg_dev, filesem);
++
++ kref_put(&fsg->ref, fsg_release);
++}
++
++static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++ int i;
++ struct fsg_lun *curlun;
++ struct usb_request *req = fsg->ep0req;
++
++ DBG(fsg, "unbind\n");
++ clear_bit(REGISTERED, &fsg->atomic_bitflags);
++
++ /* If the thread isn't already dead, tell it to exit now */
++ if (fsg->state != FSG_STATE_TERMINATED) {
++ raise_exception(fsg, FSG_STATE_EXIT);
++ wait_for_completion(&fsg->thread_notifier);
++
++ /* The cleanup routine waits for this completion also */
++ complete(&fsg->thread_notifier);
++ }
++
++ /* Unregister the sysfs attribute files and the LUNs */
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ if (curlun->registered) {
++ device_remove_file(&curlun->dev, &dev_attr_nofua);
++ device_remove_file(&curlun->dev, &dev_attr_ro);
++ device_remove_file(&curlun->dev, &dev_attr_file);
++ fsg_lun_close(curlun);
++ device_unregister(&curlun->dev);
++ curlun->registered = 0;
++ }
++ }
++
++ /* Free the data buffers */
++ for (i = 0; i < fsg_num_buffers; ++i)
++ kfree(fsg->buffhds[i].buf);
++
++ /* Free the request and buffer for endpoint 0 */
++ if (req) {
++ kfree(req->buf);
++ usb_ep_free_request(fsg->ep0, req);
++ }
++
++ set_gadget_data(gadget, NULL);
++}
++
++
++static int __init check_parameters(struct fsg_dev *fsg)
++{
++ int prot;
++ int gcnum;
++
++ /* Store the default values */
++ mod_data.transport_type = USB_PR_BULK;
++ mod_data.transport_name = "Bulk-only";
++ mod_data.protocol_type = USB_SC_SCSI;
++ mod_data.protocol_name = "Transparent SCSI";
++
++ /* Some peripheral controllers are known not to be able to
++ * halt bulk endpoints correctly. If one of them is present,
++ * disable stalls.
++ */
++ if (gadget_is_at91(fsg->gadget))
++ mod_data.can_stall = 0;
++
++ if (mod_data.release == 0xffff) { // Parameter wasn't set
++ gcnum = usb_gadget_controller_number(fsg->gadget);
++ if (gcnum >= 0)
++ mod_data.release = 0x0300 + gcnum;
++ else {
++ WARNING(fsg, "controller '%s' not recognized\n",
++ fsg->gadget->name);
++ mod_data.release = 0x0399;
++ }
++ }
++
++ prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++ if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
++ ; // Use default setting
++ } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
++ mod_data.transport_type = USB_PR_CB;
++ mod_data.transport_name = "Control-Bulk";
++ } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
++ mod_data.transport_type = USB_PR_CBI;
++ mod_data.transport_name = "Control-Bulk-Interrupt";
++ } else {
++ ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
++ return -EINVAL;
++ }
++
++ if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
++ prot == USB_SC_SCSI) {
++ ; // Use default setting
++ } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
++ prot == USB_SC_RBC) {
++ mod_data.protocol_type = USB_SC_RBC;
++ mod_data.protocol_name = "RBC";
++ } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
++ strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
++ prot == USB_SC_8020) {
++ mod_data.protocol_type = USB_SC_8020;
++ mod_data.protocol_name = "8020i (ATAPI)";
++ } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
++ prot == USB_SC_QIC) {
++ mod_data.protocol_type = USB_SC_QIC;
++ mod_data.protocol_name = "QIC-157";
++ } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
++ prot == USB_SC_UFI) {
++ mod_data.protocol_type = USB_SC_UFI;
++ mod_data.protocol_name = "UFI";
++ } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
++ prot == USB_SC_8070) {
++ mod_data.protocol_type = USB_SC_8070;
++ mod_data.protocol_name = "8070i";
++ } else {
++ ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
++ return -EINVAL;
++ }
++
++ mod_data.buflen &= PAGE_CACHE_MASK;
++ if (mod_data.buflen <= 0) {
++ ERROR(fsg, "invalid buflen\n");
++ return -ETOOSMALL;
++ }
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++ /* Serial string handling.
++ * On a real device, the serial string would be loaded
++ * from permanent storage. */
++ if (mod_data.serial) {
++ const char *ch;
++ unsigned len = 0;
++
++ /* Sanity check :
++ * The CB[I] specification limits the serial string to
++ * 12 uppercase hexadecimal characters.
++ * BBB need at least 12 uppercase hexadecimal characters,
++ * with a maximum of 126. */
++ for (ch = mod_data.serial; *ch; ++ch) {
++ ++len;
++ if ((*ch < '0' || *ch > '9') &&
++ (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
++ WARNING(fsg,
++ "Invalid serial string character: %c\n",
++ *ch);
++ goto no_serial;
++ }
++ }
++ if (len > 126 ||
++ (mod_data.transport_type == USB_PR_BULK && len < 12) ||
++ (mod_data.transport_type != USB_PR_BULK && len > 12)) {
++ WARNING(fsg, "Invalid serial string length!\n");
++ goto no_serial;
++ }
++ fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
++ } else {
++ WARNING(fsg, "No serial-number string provided!\n");
++ no_serial:
++ device_desc.iSerialNumber = 0;
++ }
++
++ return 0;
++}
++
++
++static int __init fsg_bind(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = the_fsg;
++ int rc;
++ int i;
++ struct fsg_lun *curlun;
++ struct usb_ep *ep;
++ struct usb_request *req;
++ char *pathbuf, *p;
++
++ fsg->gadget = gadget;
++ set_gadget_data(gadget, fsg);
++ fsg->ep0 = gadget->ep0;
++ fsg->ep0->driver_data = fsg;
++
++ if ((rc = check_parameters(fsg)) != 0)
++ goto out;
++
++ if (mod_data.removable) { // Enable the store_xxx attributes
++ dev_attr_file.attr.mode = 0644;
++ dev_attr_file.store = fsg_store_file;
++ if (!mod_data.cdrom) {
++ dev_attr_ro.attr.mode = 0644;
++ dev_attr_ro.store = fsg_store_ro;
++ }
++ }
++
++ /* Only for removable media? */
++ dev_attr_nofua.attr.mode = 0644;
++ dev_attr_nofua.store = fsg_store_nofua;
++
++ /* Find out how many LUNs there should be */
++ i = mod_data.nluns;
++ if (i == 0)
++ i = max(mod_data.num_filenames, 1u);
++ if (i > FSG_MAX_LUNS) {
++ ERROR(fsg, "invalid number of LUNs: %d\n", i);
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* Create the LUNs, open their backing files, and register the
++ * LUN devices in sysfs. */
++ fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
++ if (!fsg->luns) {
++ rc = -ENOMEM;
++ goto out;
++ }
++ fsg->nluns = i;
++
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ curlun->cdrom = !!mod_data.cdrom;
++ curlun->ro = mod_data.cdrom || mod_data.ro[i];
++ curlun->initially_ro = curlun->ro;
++ curlun->removable = mod_data.removable;
++ curlun->nofua = mod_data.nofua[i];
++ curlun->dev.release = lun_release;
++ curlun->dev.parent = &gadget->dev;
++ curlun->dev.driver = &fsg_driver.driver;
++ dev_set_drvdata(&curlun->dev, &fsg->filesem);
++ dev_set_name(&curlun->dev,"%s-lun%d",
++ dev_name(&gadget->dev), i);
++
++ kref_get(&fsg->ref);
++ rc = device_register(&curlun->dev);
++ if (rc) {
++ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
++ put_device(&curlun->dev);
++ goto out;
++ }
++ curlun->registered = 1;
++
++ rc = device_create_file(&curlun->dev, &dev_attr_ro);
++ if (rc)
++ goto out;
++ rc = device_create_file(&curlun->dev, &dev_attr_nofua);
++ if (rc)
++ goto out;
++ rc = device_create_file(&curlun->dev, &dev_attr_file);
++ if (rc)
++ goto out;
++
++ if (mod_data.file[i] && *mod_data.file[i]) {
++ rc = fsg_lun_open(curlun, mod_data.file[i]);
++ if (rc)
++ goto out;
++ } else if (!mod_data.removable) {
++ ERROR(fsg, "no file given for LUN%d\n", i);
++ rc = -EINVAL;
++ goto out;
++ }
++ }
++
++ /* Find all the endpoints we will use */
++ usb_ep_autoconfig_reset(gadget);
++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
++ if (!ep)
++ goto autoconf_fail;
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->bulk_in = ep;
++
++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
++ if (!ep)
++ goto autoconf_fail;
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->bulk_out = ep;
++
++ if (transport_is_cbi()) {
++ ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
++ if (!ep)
++ goto autoconf_fail;
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->intr_in = ep;
++ }
++
++ /* Fix up the descriptors */
++ device_desc.idVendor = cpu_to_le16(mod_data.vendor);
++ device_desc.idProduct = cpu_to_le16(mod_data.product);
++ device_desc.bcdDevice = cpu_to_le16(mod_data.release);
++
++ i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
++ fsg_intf_desc.bNumEndpoints = i;
++ fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
++ fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
++ fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
++
++ if (gadget_is_dualspeed(gadget)) {
++ fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
++
++ /* Assume endpoint addresses are the same for both speeds */
++ fsg_hs_bulk_in_desc.bEndpointAddress =
++ fsg_fs_bulk_in_desc.bEndpointAddress;
++ fsg_hs_bulk_out_desc.bEndpointAddress =
++ fsg_fs_bulk_out_desc.bEndpointAddress;
++ fsg_hs_intr_in_desc.bEndpointAddress =
++ fsg_fs_intr_in_desc.bEndpointAddress;
++ }
++
++ if (gadget_is_superspeed(gadget)) {
++ unsigned max_burst;
++
++ fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
++
++ /* Calculate bMaxBurst, we know packet size is 1024 */
++ max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
++
++ /* Assume endpoint addresses are the same for both speeds */
++ fsg_ss_bulk_in_desc.bEndpointAddress =
++ fsg_fs_bulk_in_desc.bEndpointAddress;
++ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
++
++ fsg_ss_bulk_out_desc.bEndpointAddress =
++ fsg_fs_bulk_out_desc.bEndpointAddress;
++ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
++ }
++
++ if (gadget_is_otg(gadget))
++ fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
++
++ rc = -ENOMEM;
++
++ /* Allocate the request and buffer for endpoint 0 */
++ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
++ if (!req)
++ goto out;
++ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
++ if (!req->buf)
++ goto out;
++ req->complete = ep0_complete;
++
++ /* Allocate the data buffers */
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ struct fsg_buffhd *bh = &fsg->buffhds[i];
++
++ /* Allocate for the bulk-in endpoint. We assume that
++ * the buffer will also work with the bulk-out (and
++ * interrupt-in) endpoint. */
++ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
++ if (!bh->buf)
++ goto out;
++ bh->next = bh + 1;
++ }
++ fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
++
++ /* This should reflect the actual gadget power source */
++ usb_gadget_set_selfpowered(gadget);
++
++ snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
++ "%s %s with %s",
++ init_utsname()->sysname, init_utsname()->release,
++ gadget->name);
++
++ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
++ "file-storage-gadget");
++ if (IS_ERR(fsg->thread_task)) {
++ rc = PTR_ERR(fsg->thread_task);
++ goto out;
++ }
++
++ INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
++ INFO(fsg, "NOTE: This driver is deprecated. "
++ "Consider using g_mass_storage instead.\n");
++ INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
++
++ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ if (fsg_lun_is_open(curlun)) {
++ p = NULL;
++ if (pathbuf) {
++ p = d_path(&curlun->filp->f_path,
++ pathbuf, PATH_MAX);
++ if (IS_ERR(p))
++ p = NULL;
++ }
++ LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
++ curlun->ro, curlun->nofua, (p ? p : "(error)"));
++ }
++ }
++ kfree(pathbuf);
++
++ DBG(fsg, "transport=%s (x%02x)\n",
++ mod_data.transport_name, mod_data.transport_type);
++ DBG(fsg, "protocol=%s (x%02x)\n",
++ mod_data.protocol_name, mod_data.protocol_type);
++ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
++ mod_data.vendor, mod_data.product, mod_data.release);
++ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
++ mod_data.removable, mod_data.can_stall,
++ mod_data.cdrom, mod_data.buflen);
++ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
++
++ set_bit(REGISTERED, &fsg->atomic_bitflags);
++
++ /* Tell the thread to start working */
++ wake_up_process(fsg->thread_task);
++ return 0;
++
++autoconf_fail:
++ ERROR(fsg, "unable to autoconfigure all endpoints\n");
++ rc = -ENOTSUPP;
++
++out:
++ fsg->state = FSG_STATE_TERMINATED; // The thread is dead
++ fsg_unbind(gadget);
++ complete(&fsg->thread_notifier);
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void fsg_suspend(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++
++ DBG(fsg, "suspend\n");
++ set_bit(SUSPENDED, &fsg->atomic_bitflags);
++}
++
++static void fsg_resume(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++
++ DBG(fsg, "resume\n");
++ clear_bit(SUSPENDED, &fsg->atomic_bitflags);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver fsg_driver = {
++ .max_speed = USB_SPEED_SUPER,
++ .function = (char *) fsg_string_product,
++ .unbind = fsg_unbind,
++ .disconnect = fsg_disconnect,
++ .setup = fsg_setup,
++ .suspend = fsg_suspend,
++ .resume = fsg_resume,
++
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ // .release = ...
++ // .suspend = ...
++ // .resume = ...
++ },
++};
++
++
++static int __init fsg_alloc(void)
++{
++ struct fsg_dev *fsg;
++
++ fsg = kzalloc(sizeof *fsg +
++ fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
++
++ if (!fsg)
++ return -ENOMEM;
++ spin_lock_init(&fsg->lock);
++ init_rwsem(&fsg->filesem);
++ kref_init(&fsg->ref);
++ init_completion(&fsg->thread_notifier);
++
++ the_fsg = fsg;
++ return 0;
++}
++
++
++static int __init fsg_init(void)
++{
++ int rc;
++ struct fsg_dev *fsg;
++
++ rc = fsg_num_buffers_validate();
++ if (rc != 0)
++ return rc;
++
++ if ((rc = fsg_alloc()) != 0)
++ return rc;
++ fsg = the_fsg;
++ if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
++ kref_put(&fsg->ref, fsg_release);
++ return rc;
++}
++module_init(fsg_init);
++
++
++static void __exit fsg_cleanup(void)
++{
++ struct fsg_dev *fsg = the_fsg;
++
++ /* Unregister the driver iff the thread hasn't already done so */
++ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
++ usb_gadget_unregister_driver(&fsg_driver);
++
++ /* Wait for the thread to finish up */
++ wait_for_completion(&fsg->thread_notifier);
++
++ kref_put(&fsg->ref, fsg_release);
++}
++module_exit(fsg_cleanup);
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 16758b12a5e9..37a8bcf35ec2 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -748,6 +748,16 @@ config USB_HWA_HCD
+ To compile this driver a module, choose M here: the module
+ will be called "hwa-hc".
+
++config USB_DWCOTG
++ bool "Synopsis DWC host support"
++ depends on USB && (FIQ || ARM64)
++ help
++ The Synopsis DWC controller is a dual-role
++ host/peripheral/OTG ("On The Go") USB controllers.
++
++ Enable this option to support this IP in host controller mode.
++ If unsure, say N.
++
+ config USB_IMX21_HCD
+ tristate "i.MX21 HCD support"
+ depends on ARM && ARCH_MXC
+diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
+index 84514f71ae44..31bc2d78a4c3 100644
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -83,6 +83,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
+ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
+ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
++
++obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
+ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
+ obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
+ obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
+diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile
+new file mode 100644
+index 000000000000..f10d466d1aea
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/Makefile
+@@ -0,0 +1,58 @@
++#
++# Makefile for DWC_common library
++#
++
++ifneq ($(KERNELRELEASE),)
++
++ccflags-y += -DDWC_LINUX
++#ccflags-y += -DDEBUG
++#ccflags-y += -DDWC_DEBUG_REGS
++#ccflags-y += -DDWC_DEBUG_MEMORY
++
++ccflags-y += -DDWC_LIBMODULE
++ccflags-y += -DDWC_CCLIB
++#ccflags-y += -DDWC_CRYPTOLIB
++ccflags-y += -DDWC_NOTIFYLIB
++ccflags-y += -DDWC_UTFLIB
++
++obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
++dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
++ dwc_crypto.o dwc_notifier.o \
++ dwc_common_linux.o dwc_mem.o
++
++kernrelwd := $(subst ., ,$(KERNELRELEASE))
++kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
++
++ifneq ($(kernrel3),2.6.20)
++# grayg - I only know that we use ccflags-y in 2.6.31 actually
++ccflags-y += $(CPPFLAGS)
++endif
++
++else
++
++#ifeq ($(KDIR),)
++#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
++#endif
++
++ifeq ($(ARCH),)
++$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
++ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
++endif
++
++ifeq ($(DOXYGEN),)
++DOXYGEN := doxygen
++endif
++
++default:
++ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
++
++docs: $(wildcard *.[hc]) doc/doxygen.cfg
++ $(DOXYGEN) doc/doxygen.cfg
++
++tags: $(wildcard *.[hc])
++ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
++
++endif
++
++clean:
++ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
+diff --git a/drivers/usb/host/dwc_common_port/Makefile.fbsd b/drivers/usb/host/dwc_common_port/Makefile.fbsd
+new file mode 100644
+index 000000000000..45db9915b9d3
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
+@@ -0,0 +1,17 @@
++CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
++CFLAGS += -DDWC_FREEBSD
++CFLAGS += -DDEBUG
++#CFLAGS += -DDWC_DEBUG_REGS
++#CFLAGS += -DDWC_DEBUG_MEMORY
++
++#CFLAGS += -DDWC_LIBMODULE
++#CFLAGS += -DDWC_CCLIB
++#CFLAGS += -DDWC_CRYPTOLIB
++#CFLAGS += -DDWC_NOTIFYLIB
++#CFLAGS += -DDWC_UTFLIB
++
++KMOD = dwc_common_port_lib
++SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
++ dwc_common_fbsd.c dwc_mem.c
++
++.include <bsd.kmod.mk>
+diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux
+new file mode 100644
+index 000000000000..0cef7b461bd5
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/Makefile.linux
+@@ -0,0 +1,49 @@
++#
++# Makefile for DWC_common library
++#
++ifneq ($(KERNELRELEASE),)
++
++ccflags-y += -DDWC_LINUX
++#ccflags-y += -DDEBUG
++#ccflags-y += -DDWC_DEBUG_REGS
++#ccflags-y += -DDWC_DEBUG_MEMORY
++
++ccflags-y += -DDWC_LIBMODULE
++ccflags-y += -DDWC_CCLIB
++ccflags-y += -DDWC_CRYPTOLIB
++ccflags-y += -DDWC_NOTIFYLIB
++ccflags-y += -DDWC_UTFLIB
++
++obj-m := dwc_common_port_lib.o
++dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
++ dwc_crypto.o dwc_notifier.o \
++ dwc_common_linux.o dwc_mem.o
++
++else
++
++ifeq ($(KDIR),)
++$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
++endif
++
++ifeq ($(ARCH),)
++$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
++ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
++endif
++
++ifeq ($(DOXYGEN),)
++DOXYGEN := doxygen
++endif
++
++default:
++ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
++
++docs: $(wildcard *.[hc]) doc/doxygen.cfg
++ $(DOXYGEN) doc/doxygen.cfg
++
++tags: $(wildcard *.[hc])
++ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
++
++endif
++
++clean:
++ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
+diff --git a/drivers/usb/host/dwc_common_port/changes.txt b/drivers/usb/host/dwc_common_port/changes.txt
+new file mode 100644
+index 000000000000..f6839f92c276
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/changes.txt
+@@ -0,0 +1,174 @@
++
++dwc_read_reg32() and friends now take an additional parameter, a pointer to an
++IO context struct. The IO context struct should live in an os-dependent struct
++in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
++named 'os_dep' embedded in the main device struct. So there these calls look
++like this:
++
++ dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
++
++ dwc_write_reg32(&usb3_dev->os_dep.ioctx,
++ &pcd->dev_global_regs->dcfg, 0);
++
++Note that for the existing Linux driver ports, it is not necessary to actually
++define the 'ioctx' member in the os-dependent struct. Since Linux does not
++require an IO context, its macros for dwc_read_reg32() and friends do not
++use the context pointer, so it is optimized away by the compiler. But it is
++necessary to add the pointer parameter to all of the call sites, to be ready
++for any future ports (such as FreeBSD) which do require an IO context.
++
++
++Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
++take an additional parameter, a pointer to a memory context. Examples:
++
++ addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
++
++ dwc_free(&usb3_dev->os_dep.memctx, addr);
++
++Again, for the Linux ports, it is not necessary to actually define the memctx
++member, but it is necessary to add the pointer parameter to all of the call
++sites.
++
++
++Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
++
++ virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
++
++ dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
++
++
++Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
++
++ mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
++
++ dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
++
++
++Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
++
++ lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
++
++ dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
++
++
++Same for dwc_timer_alloc(). Example:
++
++ timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
++ cb_func, cb_data);
++
++
++Same for dwc_waitq_alloc(). Example:
++
++ waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
++
++
++Same for dwc_thread_run(). Example:
++
++ thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
++ "dwc_usb3_thd1", data);
++
++
++Same for dwc_workq_alloc(). Example:
++
++ workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
++
++
++Same for dwc_task_alloc(). Example:
++
++ task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
++ cb_func, cb_data);
++
++
++In addition to the context pointer additions, a few core functions have had
++other changes made to their parameters:
++
++The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
++has been changed from a uint64_t to a dwc_irqflags_t.
++
++dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
++FreeBSD equivalent of that function requires it.
++
++And, in addition to the context pointer, dwc_task_alloc() also adds a
++'char *name' parameter, to be consistent with dwc_thread_run() and
++dwc_workq_alloc(), and because the FreeBSD equivalent of that function
++requires a unique name.
++
++
++Here is a complete list of the core functions that now take a pointer to a
++context as their first parameter:
++
++ dwc_read_reg32
++ dwc_read_reg64
++ dwc_write_reg32
++ dwc_write_reg64
++ dwc_modify_reg32
++ dwc_modify_reg64
++ dwc_alloc
++ dwc_alloc_atomic
++ dwc_strdup
++ dwc_free
++ dwc_dma_alloc
++ dwc_dma_free
++ dwc_mutex_alloc
++ dwc_mutex_free
++ dwc_spinlock_alloc
++ dwc_spinlock_free
++ dwc_timer_alloc
++ dwc_waitq_alloc
++ dwc_thread_run
++ dwc_workq_alloc
++ dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
++
++And here are the core functions that have other changes to their parameters:
++
++ dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
++ dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
++ dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
++
++
++
++The changes to the core functions also require some of the other library
++functions to change:
++
++ dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
++ (for memory allocation) as the 1st param and a 'void *mtxctx'
++ (for mutex allocation) as the 2nd param.
++
++ dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
++ dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
++ 'void *memctx' as the 1st param.
++
++ dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
++ 'void *memctx' as the 1st param.
++
++ dwc_modpow() now takes a 'void *memctx' as the 1st param.
++
++ dwc_alloc_notification_manager() now takes a 'void *memctx' as the
++ 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
++ param, and also now returns an integer value that is non-zero if
++ allocation of its data structures or work queue fails.
++
++ dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
++
++ dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
++ param, and also now returns an integer value that is non-zero if
++ allocation of its data structures fails.
++
++
++
++Other miscellaneous changes:
++
++The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
++DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
++
++The following #define's have been added to allow selectively compiling library
++features:
++
++ DWC_CCLIB
++ DWC_CRYPTOLIB
++ DWC_NOTIFYLIB
++ DWC_UTFLIB
++
++A DWC_LIBMODULE #define has also been added. If this is not defined, then the
++module code in dwc_common_linux.c is not compiled in. This allows linking the
++library code directly into a driver module, instead of as a standalone module.
+diff --git a/drivers/usb/host/dwc_common_port/doc/doxygen.cfg b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
+new file mode 100644
+index 000000000000..89aa887af29d
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
+@@ -0,0 +1,270 @@
++# Doxyfile 1.4.5
++
++#---------------------------------------------------------------------------
++# Project related configuration options
++#---------------------------------------------------------------------------
++PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
++PROJECT_NUMBER =
++OUTPUT_DIRECTORY = doc
++CREATE_SUBDIRS = NO
++OUTPUT_LANGUAGE = English
++BRIEF_MEMBER_DESC = YES
++REPEAT_BRIEF = YES
++ABBREVIATE_BRIEF = "The $name class" \
++ "The $name widget" \
++ "The $name file" \
++ is \
++ provides \
++ specifies \
++ contains \
++ represents \
++ a \
++ an \
++ the
++ALWAYS_DETAILED_SEC = YES
++INLINE_INHERITED_MEMB = NO
++FULL_PATH_NAMES = NO
++STRIP_FROM_PATH = ..
++STRIP_FROM_INC_PATH =
++SHORT_NAMES = NO
++JAVADOC_AUTOBRIEF = YES
++MULTILINE_CPP_IS_BRIEF = NO
++DETAILS_AT_TOP = YES
++INHERIT_DOCS = YES
++SEPARATE_MEMBER_PAGES = NO
++TAB_SIZE = 8
++ALIASES =
++OPTIMIZE_OUTPUT_FOR_C = YES
++OPTIMIZE_OUTPUT_JAVA = NO
++BUILTIN_STL_SUPPORT = NO
++DISTRIBUTE_GROUP_DOC = NO
++SUBGROUPING = NO
++#---------------------------------------------------------------------------
++# Build related configuration options
++#---------------------------------------------------------------------------
++EXTRACT_ALL = NO
++EXTRACT_PRIVATE = NO
++EXTRACT_STATIC = YES
++EXTRACT_LOCAL_CLASSES = NO
++EXTRACT_LOCAL_METHODS = NO
++HIDE_UNDOC_MEMBERS = NO
++HIDE_UNDOC_CLASSES = NO
++HIDE_FRIEND_COMPOUNDS = NO
++HIDE_IN_BODY_DOCS = NO
++INTERNAL_DOCS = NO
++CASE_SENSE_NAMES = YES
++HIDE_SCOPE_NAMES = NO
++SHOW_INCLUDE_FILES = NO
++INLINE_INFO = YES
++SORT_MEMBER_DOCS = NO
++SORT_BRIEF_DOCS = NO
++SORT_BY_SCOPE_NAME = NO
++GENERATE_TODOLIST = YES
++GENERATE_TESTLIST = YES
++GENERATE_BUGLIST = YES
++GENERATE_DEPRECATEDLIST= YES
++ENABLED_SECTIONS =
++MAX_INITIALIZER_LINES = 30
++SHOW_USED_FILES = YES
++SHOW_DIRECTORIES = YES
++FILE_VERSION_FILTER =
++#---------------------------------------------------------------------------
++# configuration options related to warning and progress messages
++#---------------------------------------------------------------------------
++QUIET = YES
++WARNINGS = YES
++WARN_IF_UNDOCUMENTED = NO
++WARN_IF_DOC_ERROR = YES
++WARN_NO_PARAMDOC = YES
++WARN_FORMAT = "$file:$line: $text"
++WARN_LOGFILE =
++#---------------------------------------------------------------------------
++# configuration options related to the input files
++#---------------------------------------------------------------------------
++INPUT = .
++FILE_PATTERNS = *.c \
++ *.cc \
++ *.cxx \
++ *.cpp \
++ *.c++ \
++ *.d \
++ *.java \
++ *.ii \
++ *.ixx \
++ *.ipp \
++ *.i++ \
++ *.inl \
++ *.h \
++ *.hh \
++ *.hxx \
++ *.hpp \
++ *.h++ \
++ *.idl \
++ *.odl \
++ *.cs \
++ *.php \
++ *.php3 \
++ *.inc \
++ *.m \
++ *.mm \
++ *.dox \
++ *.py \
++ *.C \
++ *.CC \
++ *.C++ \
++ *.II \
++ *.I++ \
++ *.H \
++ *.HH \
++ *.H++ \
++ *.CS \
++ *.PHP \
++ *.PHP3 \
++ *.M \
++ *.MM \
++ *.PY
++RECURSIVE = NO
++EXCLUDE =
++EXCLUDE_SYMLINKS = NO
++EXCLUDE_PATTERNS =
++EXAMPLE_PATH =
++EXAMPLE_PATTERNS = *
++EXAMPLE_RECURSIVE = NO
++IMAGE_PATH =
++INPUT_FILTER =
++FILTER_PATTERNS =
++FILTER_SOURCE_FILES = NO
++#---------------------------------------------------------------------------
++# configuration options related to source browsing
++#---------------------------------------------------------------------------
++SOURCE_BROWSER = NO
++INLINE_SOURCES = NO
++STRIP_CODE_COMMENTS = YES
++REFERENCED_BY_RELATION = YES
++REFERENCES_RELATION = YES
++USE_HTAGS = NO
++VERBATIM_HEADERS = NO
++#---------------------------------------------------------------------------
++# configuration options related to the alphabetical class index
++#---------------------------------------------------------------------------
++ALPHABETICAL_INDEX = NO
++COLS_IN_ALPHA_INDEX = 5
++IGNORE_PREFIX =
++#---------------------------------------------------------------------------
++# configuration options related to the HTML output
++#---------------------------------------------------------------------------
++GENERATE_HTML = YES
++HTML_OUTPUT = html
++HTML_FILE_EXTENSION = .html
++HTML_HEADER =
++HTML_FOOTER =
++HTML_STYLESHEET =
++HTML_ALIGN_MEMBERS = YES
++GENERATE_HTMLHELP = NO
++CHM_FILE =
++HHC_LOCATION =
++GENERATE_CHI = NO
++BINARY_TOC = NO
++TOC_EXPAND = NO
++DISABLE_INDEX = NO
++ENUM_VALUES_PER_LINE = 4
++GENERATE_TREEVIEW = YES
++TREEVIEW_WIDTH = 250
++#---------------------------------------------------------------------------
++# configuration options related to the LaTeX output
++#---------------------------------------------------------------------------
++GENERATE_LATEX = NO
++LATEX_OUTPUT = latex
++LATEX_CMD_NAME = latex
++MAKEINDEX_CMD_NAME = makeindex
++COMPACT_LATEX = NO
++PAPER_TYPE = a4wide
++EXTRA_PACKAGES =
++LATEX_HEADER =
++PDF_HYPERLINKS = NO
++USE_PDFLATEX = NO
++LATEX_BATCHMODE = NO
++LATEX_HIDE_INDICES = NO
++#---------------------------------------------------------------------------
++# configuration options related to the RTF output
++#---------------------------------------------------------------------------
++GENERATE_RTF = NO
++RTF_OUTPUT = rtf
++COMPACT_RTF = NO
++RTF_HYPERLINKS = NO
++RTF_STYLESHEET_FILE =
++RTF_EXTENSIONS_FILE =
++#---------------------------------------------------------------------------
++# configuration options related to the man page output
++#---------------------------------------------------------------------------
++GENERATE_MAN = NO
++MAN_OUTPUT = man
++MAN_EXTENSION = .3
++MAN_LINKS = NO
++#---------------------------------------------------------------------------
++# configuration options related to the XML output
++#---------------------------------------------------------------------------
++GENERATE_XML = NO
++XML_OUTPUT = xml
++XML_SCHEMA =
++XML_DTD =
++XML_PROGRAMLISTING = YES
++#---------------------------------------------------------------------------
++# configuration options for the AutoGen Definitions output
++#---------------------------------------------------------------------------
++GENERATE_AUTOGEN_DEF = NO
++#---------------------------------------------------------------------------
++# configuration options related to the Perl module output
++#---------------------------------------------------------------------------
++GENERATE_PERLMOD = NO
++PERLMOD_LATEX = NO
++PERLMOD_PRETTY = YES
++PERLMOD_MAKEVAR_PREFIX =
++#---------------------------------------------------------------------------
++# Configuration options related to the preprocessor
++#---------------------------------------------------------------------------
++ENABLE_PREPROCESSING = YES
++MACRO_EXPANSION = NO
++EXPAND_ONLY_PREDEF = NO
++SEARCH_INCLUDES = YES
++INCLUDE_PATH =
++INCLUDE_FILE_PATTERNS =
++PREDEFINED = DEBUG DEBUG_MEMORY
++EXPAND_AS_DEFINED =
++SKIP_FUNCTION_MACROS = YES
++#---------------------------------------------------------------------------
++# Configuration::additions related to external references
++#---------------------------------------------------------------------------
++TAGFILES =
++GENERATE_TAGFILE =
++ALLEXTERNALS = NO
++EXTERNAL_GROUPS = YES
++PERL_PATH = /usr/bin/perl
++#---------------------------------------------------------------------------
++# Configuration options related to the dot tool
++#---------------------------------------------------------------------------
++CLASS_DIAGRAMS = YES
++HIDE_UNDOC_RELATIONS = YES
++HAVE_DOT = NO
++CLASS_GRAPH = YES
++COLLABORATION_GRAPH = YES
++GROUP_GRAPHS = YES
++UML_LOOK = NO
++TEMPLATE_RELATIONS = NO
++INCLUDE_GRAPH = NO
++INCLUDED_BY_GRAPH = YES
++CALL_GRAPH = NO
++GRAPHICAL_HIERARCHY = YES
++DIRECTORY_GRAPH = YES
++DOT_IMAGE_FORMAT = png
++DOT_PATH =
++DOTFILE_DIRS =
++MAX_DOT_GRAPH_DEPTH = 1000
++DOT_TRANSPARENT = NO
++DOT_MULTI_TARGETS = NO
++GENERATE_LEGEND = YES
++DOT_CLEANUP = YES
++#---------------------------------------------------------------------------
++# Configuration::additions related to the search engine
++#---------------------------------------------------------------------------
++SEARCHENGINE = NO
+diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.c b/drivers/usb/host/dwc_common_port/dwc_cc.c
+new file mode 100644
+index 000000000000..5ec2ae28698c
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
+@@ -0,0 +1,532 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
++ * $Revision: #4 $
++ * $Date: 2010/11/04 $
++ * $Change: 1621692 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifdef DWC_CCLIB
++
++#include "dwc_cc.h"
++
++typedef struct dwc_cc
++{
++ uint32_t uid;
++ uint8_t chid[16];
++ uint8_t cdid[16];
++ uint8_t ck[16];
++ uint8_t *name;
++ uint8_t length;
++ DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
++} dwc_cc_t;
++
++DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
++
++/** The main structure for CC management. */
++struct dwc_cc_if
++{
++ dwc_mutex_t *mutex;
++ char *filename;
++
++ unsigned is_host:1;
++
++ dwc_notifier_t *notifier;
++
++ struct context_list list;
++};
++
++#ifdef DEBUG
++static inline void dump_bytes(char *name, uint8_t *bytes, int len)
++{
++ int i;
++ DWC_PRINTF("%s: ", name);
++ for (i=0; i<len; i++) {
++ DWC_PRINTF("%02x ", bytes[i]);
++ }
++ DWC_PRINTF("\n");
++}
++#else
++#define dump_bytes(x...)
++#endif
++
++static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
++{
++ dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
++ if (!cc) {
++ return NULL;
++ }
++ DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
++
++ if (name) {
++ cc->length = length;
++ cc->name = dwc_alloc(mem_ctx, length);
++ if (!cc->name) {
++ dwc_free(mem_ctx, cc);
++ return NULL;
++ }
++
++ DWC_MEMCPY(cc->name, name, length);
++ }
++
++ return cc;
++}
++
++static void free_cc(void *mem_ctx, dwc_cc_t *cc)
++{
++ if (cc->name) {
++ dwc_free(mem_ctx, cc->name);
++ }
++ dwc_free(mem_ctx, cc);
++}
++
++static uint32_t next_uid(dwc_cc_if_t *cc_if)
++{
++ uint32_t uid = 0;
++ dwc_cc_t *cc;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (cc->uid > uid) {
++ uid = cc->uid;
++ }
++ }
++
++ if (uid == 0) {
++ uid = 255;
++ }
++
++ return uid + 1;
++}
++
++static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
++{
++ dwc_cc_t *cc;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (cc->uid == uid) {
++ return cc;
++ }
++ }
++ return NULL;
++}
++
++static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
++{
++ unsigned int size = 0;
++ dwc_cc_t *cc;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ size += (48 + 1);
++ if (cc->name) {
++ size += cc->length;
++ }
++ }
++ return size;
++}
++
++static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
++{
++ uint32_t uid = 0;
++ dwc_cc_t *cc;
++
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
++ uid = cc->uid;
++ break;
++ }
++ }
++ return uid;
++}
++static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
++{
++ uint32_t uid = 0;
++ dwc_cc_t *cc;
++
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
++ uid = cc->uid;
++ break;
++ }
++ }
++ return uid;
++}
++
++/* Internal cc_add */
++static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++ dwc_cc_t *cc;
++ uint32_t uid;
++
++ if (cc_if->is_host) {
++ uid = cc_match_cdid(cc_if, cdid);
++ }
++ else {
++ uid = cc_match_chid(cc_if, chid);
++ }
++
++ if (uid) {
++ DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
++ cc = cc_find(cc_if, uid);
++ }
++ else {
++ cc = alloc_cc(mem_ctx, name, length);
++ cc->uid = next_uid(cc_if);
++ DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
++ }
++
++ DWC_MEMCPY(&(cc->chid[0]), chid, 16);
++ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
++ DWC_MEMCPY(&(cc->ck[0]), ck, 16);
++
++ DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
++ dump_bytes("CHID", cc->chid, 16);
++ dump_bytes("CDID", cc->cdid, 16);
++ dump_bytes("CK", cc->ck, 16);
++ return cc->uid;
++}
++
++/* Internal cc_clear */
++static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
++{
++ while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
++ dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
++ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
++ free_cc(mem_ctx, cc);
++ }
++}
++
++dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
++ dwc_notifier_t *notifier, unsigned is_host)
++{
++ dwc_cc_if_t *cc_if = NULL;
++
++ /* Allocate a common_cc_if structure */
++ cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
++
++ if (!cc_if)
++ return NULL;
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++ DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
++#else
++ cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
++#endif
++ if (!cc_if->mutex) {
++ dwc_free(mem_ctx, cc_if);
++ return NULL;
++ }
++
++ DWC_CIRCLEQ_INIT(&cc_if->list);
++ cc_if->is_host = is_host;
++ cc_if->notifier = notifier;
++ return cc_if;
++}
++
++void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
++{
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++ DWC_MUTEX_FREE(cc_if->mutex);
++#else
++ dwc_mutex_free(mtx_ctx, cc_if->mutex);
++#endif
++ cc_clear(mem_ctx, cc_if);
++ dwc_free(mem_ctx, cc_if);
++}
++
++static void cc_changed(dwc_cc_if_t *cc_if)
++{
++ if (cc_if->notifier) {
++ dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
++ }
++}
++
++void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
++{
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc_clear(mem_ctx, cc_if);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ cc_changed(cc_if);
++}
++
++int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++ uint32_t uid;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ cc_changed(cc_if);
++
++ return uid;
++}
++
++void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++ dwc_cc_t* cc;
++
++ DWC_DEBUGC("Change connection context %d", id);
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (!cc) {
++ DWC_ERROR("Uid %d not found in cc list\n", id);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return;
++ }
++
++ if (chid) {
++ DWC_MEMCPY(&(cc->chid[0]), chid, 16);
++ }
++ if (cdid) {
++ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
++ }
++ if (ck) {
++ DWC_MEMCPY(&(cc->ck[0]), ck, 16);
++ }
++
++ if (name) {
++ if (cc->name) {
++ dwc_free(mem_ctx, cc->name);
++ }
++ cc->name = dwc_alloc(mem_ctx, length);
++ if (!cc->name) {
++ DWC_ERROR("Out of memory in dwc_cc_change()\n");
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return;
++ }
++ cc->length = length;
++ DWC_MEMCPY(cc->name, name, length);
++ }
++
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ cc_changed(cc_if);
++
++ DWC_DEBUGC("Changed connection context id=%d\n", id);
++ dump_bytes("New CHID", cc->chid, 16);
++ dump_bytes("New CDID", cc->cdid, 16);
++ dump_bytes("New CK", cc->ck, 16);
++}
++
++void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
++{
++ dwc_cc_t *cc;
++
++ DWC_DEBUGC("Removing connection context %d", id);
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (!cc) {
++ DWC_ERROR("Uid %d not found in cc list\n", id);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return;
++ }
++
++ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ free_cc(mem_ctx, cc);
++
++ cc_changed(cc_if);
++}
++
++uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
++{
++ uint8_t *buf, *x;
++ uint8_t zero = 0;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ *length = cc_data_size(cc_if);
++ if (!(*length)) {
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return NULL;
++ }
++
++ DWC_DEBUGC("Creating data for saving (length=%d)", *length);
++
++ buf = dwc_alloc(mem_ctx, *length);
++ if (!buf) {
++ *length = 0;
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return NULL;
++ }
++
++ x = buf;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ DWC_MEMCPY(x, cc->chid, 16);
++ x += 16;
++ DWC_MEMCPY(x, cc->cdid, 16);
++ x += 16;
++ DWC_MEMCPY(x, cc->ck, 16);
++ x += 16;
++ if (cc->name) {
++ DWC_MEMCPY(x, &cc->length, 1);
++ x += 1;
++ DWC_MEMCPY(x, cc->name, cc->length);
++ x += cc->length;
++ }
++ else {
++ DWC_MEMCPY(x, &zero, 1);
++ x += 1;
++ }
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return buf;
++}
++
++void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
++{
++ uint8_t name_length;
++ uint8_t *name;
++ uint8_t *chid;
++ uint8_t *cdid;
++ uint8_t *ck;
++ uint32_t i = 0;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc_clear(mem_ctx, cc_if);
++
++ while (i < length) {
++ chid = &data[i];
++ i += 16;
++ cdid = &data[i];
++ i += 16;
++ ck = &data[i];
++ i += 16;
++
++ name_length = data[i];
++ i ++;
++
++ if (name_length) {
++ name = &data[i];
++ i += name_length;
++ }
++ else {
++ name = NULL;
++ }
++
++ /* check to see if we haven't overflown the buffer */
++ if (i > length) {
++ DWC_ERROR("Data format error while attempting to load CCs "
++ "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
++ break;
++ }
++
++ cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ cc_changed(cc_if);
++}
++
++uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
++{
++ uint32_t uid = 0;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ uid = cc_match_chid(cc_if, chid);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return uid;
++}
++uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
++{
++ uint32_t uid = 0;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ uid = cc_match_cdid(cc_if, cdid);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return uid;
++}
++
++uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
++{
++ uint8_t *ck = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ ck = cc->ck;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return ck;
++
++}
++
++uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
++{
++ uint8_t *retval = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ retval = cc->chid;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return retval;
++}
++
++uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
++{
++ uint8_t *retval = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ retval = cc->cdid;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return retval;
++}
++
++uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
++{
++ uint8_t *retval = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ *length = 0;
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ *length = cc->length;
++ retval = cc->name;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return retval;
++}
++
++#endif /* DWC_CCLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.h b/drivers/usb/host/dwc_common_port/dwc_cc.h
+new file mode 100644
+index 000000000000..f86e6f21792b
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
+@@ -0,0 +1,224 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
++ * $Revision: #4 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifndef _DWC_CC_H_
++#define _DWC_CC_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file defines the Context Context library.
++ *
++ * The main data structure is dwc_cc_if_t which is returned by either the
++ * dwc_cc_if_alloc function or returned by the module to the user via a provided
++ * function. The data structure is opaque and should only be manipulated via the
++ * functions provied in this API.
++ *
++ * It manages a list of connection contexts and operations can be performed to
++ * add, remove, query, search, and change, those contexts. Additionally,
++ * a dwc_notifier_t object can be requested from the manager so that
++ * the user can be notified whenever the context list has changed.
++ */
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++#include "dwc_notifier.h"
++
++
++/* Notifications */
++#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
++
++struct dwc_cc_if;
++typedef struct dwc_cc_if dwc_cc_if_t;
++
++
++/** @name Connection Context Operations */
++/** @{ */
++
++/** This function allocates memory for a dwc_cc_if_t structure, initializes
++ * fields to default values, and returns a pointer to the structure or NULL on
++ * error. */
++extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
++ dwc_notifier_t *notifier, unsigned is_host);
++
++/** Frees the memory for the specified CC structure allocated from
++ * dwc_cc_if_alloc(). */
++extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
++
++/** Removes all contexts from the connection context list */
++extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
++
++/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
++ * If a CHID already exists, the CK and name are overwritten. Statistics are
++ * not overwritten.
++ *
++ * @param cc_if The cc_if structure.
++ * @param chid A pointer to the 16-byte CHID. This value will be copied.
++ * @param ck A pointer to the 16-byte CK. This value will be copied.
++ * @param cdid A pointer to the 16-byte CDID. This value will be copied.
++ * @param name An optional host friendly name as defined in the association model
++ * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
++ * @param length The length othe unicode string.
++ * @return A unique identifier used to refer to this context that is valid for
++ * as long as this context is still in the list. */
++extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name,
++ uint8_t length);
++
++/** Changes the CHID, CK, CDID, or Name values of a connection context in the
++ * list, preserving any accumulated statistics. This would typically be called
++ * if the host decideds to change the context with a SET_CONNECTION request.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
++ * indicates no change.
++ * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
++ * indicates no change.
++ * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
++ * indicates no change.
++ * @param name Host friendly name UTF16-LE. NULL indicates no change.
++ * @param length Length of name. */
++extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
++ uint8_t *chid, uint8_t *cdid, uint8_t *ck,
++ uint8_t *name, uint8_t length);
++
++/** Remove the specified connection context.
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context to remove. */
++extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
++
++/** Get a binary block of data for the connection context list and attributes.
++ * This data can be used by the OS specific driver to save the connection
++ * context list into non-volatile memory.
++ *
++ * @param cc_if The cc_if structure.
++ * @param length Return the length of the data buffer.
++ * @return A pointer to the data buffer. The memory for this buffer should be
++ * freed with DWC_FREE() after use. */
++extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
++ unsigned int *length);
++
++/** Restore the connection context list from the binary data that was previously
++ * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
++ * driver to load a connection context list from non-volatile memory.
++ *
++ * @param cc_if The cc_if structure.
++ * @param data The data bytes as returned from dwc_cc_data_for_save.
++ * @param length The length of the data. */
++extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
++ uint8_t *data, unsigned int length);
++
++/** Find the connection context from the specified CHID.
++ *
++ * @param cc_if The cc_if structure.
++ * @param chid A pointer to the CHID data.
++ * @return A non-zero identifier of the connection context if the CHID matches.
++ * Otherwise returns 0. */
++extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
++
++/** Find the connection context from the specified CDID.
++ *
++ * @param cc_if The cc_if structure.
++ * @param cdid A pointer to the CDID data.
++ * @return A non-zero identifier of the connection context if the CHID matches.
++ * Otherwise returns 0. */
++extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
++
++/** Retrieve the CK from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CK data. The memory does not need to be freed. */
++extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
++
++/** Retrieve the CHID from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CHID data. The memory does not need to be freed. */
++extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
++
++/** Retrieve the CDID from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CDID data. The memory does not need to be freed. */
++extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
++
++extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
++
++/** Checks a buffer for non-zero.
++ * @param id A pointer to a 16 byte buffer.
++ * @return true if the 16 byte value is non-zero. */
++static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
++ int i;
++ for (i=0; i<16; i++) {
++ if (id[i]) return 1;
++ }
++ return 0;
++}
++
++/** Checks a buffer for zero.
++ * @param id A pointer to a 16 byte buffer.
++ * @return true if the 16 byte value is zero. */
++static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
++ return !dwc_assoc_is_not_zero_id(id);
++}
++
++/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
++ * buffer. */
++static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
++ char *ptr = buffer;
++ int i;
++ for (i=0; i<16; i++) {
++ ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
++ if (i < 15) {
++ ptr += DWC_SPRINTF(ptr, " ");
++ }
++ }
++ return ptr - buffer;
++}
++
++/** @} */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CC_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
+new file mode 100644
+index 000000000000..6dd04b58f8f6
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
+@@ -0,0 +1,1308 @@
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++ return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++ return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++ bcopy(src, dest, size);
++ return dest;
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++ return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++ return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++ return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++ return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++ return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++ int len = DWC_STRLEN(str) + 1;
++ char *new = DWC_ALLOC_ATOMIC(len);
++
++ if (!new) {
++ return NULL;
++ }
++
++ DWC_MEMCPY(new, str, len);
++ return new;
++}
++
++int DWC_ATOI(char *str, int32_t *value)
++{
++ char *end = NULL;
++
++ *value = strtol(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++int DWC_ATOUI(char *str, uint32_t *value)
++{
++ char *end = NULL;
++
++ *value = strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++
++#endif /* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++// return in_irq();
++ return 0;
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++// return in_softirq();
++ return 0;
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++ vprintf(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++ return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsprintf(buffer, format, args);
++ va_end(args);
++ return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsnprintf(buffer, size, format, args);
++ va_end(args);
++ return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++// BUG_ON(1); ???
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++ uint32_t align,
++ uint32_t alloc)
++{
++ struct dma_pool *pool = dma_pool_create("Pool", NULL,
++ size, align, alloc);
++ return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++ dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++ memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++ dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
++{
++ if (error)
++ return;
++ *(bus_addr_t *)arg = segs[0].ds_addr;
++}
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++ int error;
++
++ error = bus_dma_tag_create(
++#if __FreeBSD_version >= 700000
++ bus_get_dma_tag(dma->dev), /* parent */
++#else
++ NULL, /* parent */
++#endif
++ 4, 0, /* alignment, bounds */
++ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
++ BUS_SPACE_MAXADDR, /* highaddr */
++ NULL, NULL, /* filter, filterarg */
++ size, /* maxsize */
++ 1, /* nsegments */
++ size, /* maxsegsize */
++ 0, /* flags */
++ NULL, /* lockfunc */
++ NULL, /* lockarg */
++ &dma->dma_tag);
++ if (error) {
++ device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
++ __func__, error);
++ goto fail_0;
++ }
++
++ error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
++ BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
++ if (error) {
++ device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
++ __func__, (uintmax_t)size, error);
++ goto fail_1;
++ }
++
++ dma->dma_paddr = 0;
++ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
++ dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
++ if (error || dma->dma_paddr == 0) {
++ device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
++ __func__, error);
++ goto fail_2;
++ }
++
++ *dma_addr = dma->dma_paddr;
++ return dma->dma_vaddr;
++
++fail_2:
++ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
++fail_1:
++ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
++ bus_dma_tag_destroy(dma->dma_tag);
++fail_0:
++ dma->dma_map = NULL;
++ dma->dma_tag = NULL;
++
++ return NULL;
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++
++ if (dma->dma_tag == NULL)
++ return;
++ if (dma->dma_map != NULL) {
++ bus_dmamap_sync(dma->dma_tag, dma->dma_map,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
++ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
++ dma->dma_map = NULL;
++ }
++
++ bus_dma_tag_destroy(dma->dma_tag);
++ dma->dma_tag = NULL;
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++ free(addr, M_DEVBUF);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++ get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ struct scatterlist sgd;
++ struct scatterlist sgs;
++
++ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++ if (tfm == NULL) {
++ printk("failed to load transform for aes CBC\n");
++ return -1;
++ }
++
++ crypto_blkcipher_setkey(tfm, key, keylen);
++ crypto_blkcipher_set_iv(tfm, iv, 16);
++
++ sg_init_one(&sgd, out, messagelen);
++ sg_init_one(&sgs, message, messagelen);
++
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++ crypto_free_blkcipher(tfm);
++ DWC_ERROR("AES CBC encryption failed");
++ return -1;
++ }
++
++ crypto_free_blkcipher(tfm);
++ return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, len);
++ crypto_hash_digest(&desc, &sg, len, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, messagelen);
++ crypto_hash_setkey(tfm, key, keylen);
++ crypto_hash_digest(&desc, &sg, messagelen, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++#endif /* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_4(io->iot, io->ioh, ior);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_8(io->iot, io->ioh, ior);
++}
++#endif
++
++void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior, value);
++}
++
++#if 0
++void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior, value);
++}
++#endif
++
++void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
++ uint32_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior,
++ (bus_space_read_4(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++
++#if 0
++void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
++ uint64_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior,
++ (bus_space_read_8(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++ struct mtx *sl = DWC_ALLOC(sizeof(*sl));
++
++ if (!sl) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ return NULL;
++ }
++
++ mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
++ return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++ struct mtx *sl = (struct mtx *)lock;
++
++ mtx_destroy(sl);
++ DWC_FREE(sl);
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++ mtx_lock_spin((struct mtx *)lock); // ???
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++ mtx_unlock_spin((struct mtx *)lock); // ???
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++ mtx_lock_spin((struct mtx *)lock);
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++ mtx_unlock_spin((struct mtx *)lock);
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++ struct mtx *m;
++ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
++
++ if (!mutex) {
++ DWC_ERROR("Cannot allocate memory for mutex");
++ return NULL;
++ }
++
++ m = (struct mtx *)mutex;
++ mtx_init(m, "dw3mtx", NULL, MTX_DEF);
++ return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++ mtx_destroy((struct mtx *)mutex);
++ DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++ struct mtx *m = (struct mtx *)mutex;
++
++ mtx_lock(m);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++ struct mtx *m = (struct mtx *)mutex;
++
++ return mtx_trylock(m);
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++ struct mtx *m = (struct mtx *)mutex;
++
++ mtx_unlock(m);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++ DELAY(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++ do {
++ DELAY(1000);
++ } while (--msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++ struct timeval tv;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++ pause("dw3slp", tvtohz(&tv));
++}
++
++uint32_t DWC_TIME(void)
++{
++ struct timeval tv;
++
++ microuptime(&tv); // or getmicrouptime? (less precise, but faster)
++ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++ struct callout t;
++ char *name;
++ dwc_spinlock_t *lock;
++ dwc_timer_callback_t cb;
++ void *data;
++};
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (!t) {
++ DWC_ERROR("Cannot allocate memory for timer");
++ return NULL;
++ }
++
++ callout_init(&t->t, 1);
++
++ t->name = DWC_STRDUP(name);
++ if (!t->name) {
++ DWC_ERROR("Cannot allocate memory for timer->name");
++ goto no_name;
++ }
++
++ t->lock = DWC_SPINLOCK_ALLOC();
++ if (!t->lock) {
++ DWC_ERROR("Cannot allocate memory for lock");
++ goto no_lock;
++ }
++
++ t->cb = cb;
++ t->data = data;
++
++ return t;
++
++ no_lock:
++ DWC_FREE(t->name);
++ no_name:
++ DWC_FREE(t);
++
++ return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++ DWC_SPINLOCK_FREE(timer->lock);
++ DWC_FREE(timer->name);
++ DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++ struct timeval tv;
++
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++ struct mtx lock;
++ int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ return NULL;
++ }
++
++ mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
++ wq->abort = 0;
++
++ return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++ mtx_destroy(&wq->lock);
++ DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++// intrmask_t ipl;
++ int result = 0;
++
++ mtx_lock(&wq->lock);
++// ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++// splx(ipl);
++ result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
++// ipl = splbio();
++ }
++
++ if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++
++ } else if (result == EINTR) { // signaled - interrupt
++ result = -DWC_E_ABORT;
++
++ } else if (wq->abort) {
++ result = -DWC_E_ABORT;
++
++ } else {
++ result = 0;
++ }
++
++ wq->abort = 0;
++// splx(ipl);
++ mtx_unlock(&wq->lock);
++ return result;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs)
++{
++ struct timeval tv, tv1, tv2;
++// intrmask_t ipl;
++ int result = 0;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++
++ mtx_lock(&wq->lock);
++// ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++// splx(ipl);
++ getmicrouptime(&tv1);
++ result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
++ getmicrouptime(&tv2);
++// ipl = splbio();
++ }
++
++ if (result == 0) { // awoken
++ if (wq->abort) {
++ result = -DWC_E_ABORT;
++ } else {
++ tv2.tv_usec -= tv1.tv_usec;
++ if (tv2.tv_usec < 0) {
++ tv2.tv_usec += 1000000;
++ tv2.tv_sec--;
++ }
++
++ tv2.tv_sec -= tv1.tv_sec;
++ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
++ result = msecs - result;
++ if (result <= 0)
++ result = 1;
++ }
++ } else if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++
++ } else if (result == EINTR) { // signaled - interrupt
++ result = -DWC_E_ABORT;
++
++ } else { // timed out
++ result = -DWC_E_TIMEOUT;
++ }
++
++ wq->abort = 0;
++// splx(ipl);
++ mtx_unlock(&wq->lock);
++ return result;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++ wakeup(wq);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++// intrmask_t ipl;
++
++ mtx_lock(&wq->lock);
++// ipl = splbio();
++ wq->abort = 1;
++ wakeup(wq);
++// splx(ipl);
++ mtx_unlock(&wq->lock);
++}
++
++
++/* Threading */
++
++struct dwc_thread {
++ struct proc *proc;
++ int abort;
++};
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++ int retval;
++ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
++
++ if (!thread) {
++ return NULL;
++ }
++
++ thread->abort = 0;
++ retval = kthread_create((void (*)(void *))func, data, &thread->proc,
++ RFPROC | RFNOWAIT, 0, "%s", name);
++ if (retval) {
++ DWC_FREE(thread);
++ return NULL;
++ }
++
++ return thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++ int retval;
++
++ thread->abort = 1;
++ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
++
++ if (retval == 0) {
++ /* DWC_THREAD_EXIT() will free the thread struct */
++ return 0;
++ }
++
++ /* NOTE: We leak the thread struct if thread doesn't die */
++
++ if (retval == EWOULDBLOCK) {
++ return -DWC_E_TIMEOUT;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
++{
++ return thread->abort;
++}
++
++void DWC_THREAD_EXIT(dwc_thread_t *thread)
++{
++ wakeup(&thread->abort);
++ DWC_FREE(thread);
++ kthread_exit(0);
++}
++
++
++/* tasklets
++ - Runs in interrupt context (cannot sleep)
++ - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
++ - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
++ */
++struct dwc_tasklet {
++ struct task t;
++ dwc_tasklet_callback_t cb;
++ void *data;
++};
++
++static void tasklet_callback(void *data, int pending) // what to do with pending ???
++{
++ dwc_tasklet_t *task = (dwc_tasklet_t *)data;
++
++ task->cb(task->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
++
++ if (task) {
++ task->cb = cb;
++ task->data = data;
++ TASK_INIT(&task->t, 0, tasklet_callback, task);
++ } else {
++ DWC_ERROR("Cannot allocate memory for tasklet");
++ }
++
++ return task;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++ taskqueue_drain(taskqueue_fast, &task->t); // ???
++ DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++ /* Uses predefined system queue */
++ taskqueue_enqueue_fast(taskqueue_fast, &task->t);
++}
++
++
++/* workqueues
++ - Runs in process context (can sleep)
++ */
++typedef struct work_container {
++ dwc_work_callback_t cb;
++ void *data;
++ dwc_workq_t *wq;
++ char *name;
++ int hz;
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_ENTRY(work_container) entry;
++#endif
++ struct task task;
++} work_container_t;
++
++#ifdef DEBUG
++DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
++#endif
++
++struct dwc_workq {
++ struct taskqueue *taskq;
++ dwc_spinlock_t *lock;
++ dwc_waitq_t *waitq;
++ int pending;
++
++#ifdef DEBUG
++ struct work_container_queue entries;
++#endif
++};
++
++static void do_work(void *data, int pending) // what to do with pending ???
++{
++ work_container_t *container = (work_container_t *)data;
++ dwc_workq_t *wq = container->wq;
++ dwc_irqflags_t flags;
++
++ if (container->hz) {
++ pause("dw3wrk", container->hz);
++ }
++
++ container->cb(container->data);
++ DWC_DEBUG("Work done: %s, container=%p", container->name, container);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
++#endif
++ if (container->name)
++ DWC_FREE(container->name);
++ DWC_FREE(container);
++ wq->pending--;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++ dwc_workq_t *workq = (dwc_workq_t *)data;
++
++ return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for workqueue");
++ return NULL;
++ }
++
++ wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
++ if (!wq->taskq) {
++ DWC_ERROR("Cannot allocate memory for taskqueue");
++ goto no_taskq;
++ }
++
++ wq->pending = 0;
++
++ wq->lock = DWC_SPINLOCK_ALLOC();
++ if (!wq->lock) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ goto no_lock;
++ }
++
++ wq->waitq = DWC_WAITQ_ALLOC();
++ if (!wq->waitq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ goto no_waitq;
++ }
++
++ taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INIT(&wq->entries);
++#endif
++ return wq;
++
++ no_waitq:
++ DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++ taskqueue_free(wq->taskq);
++ no_taskq:
++ DWC_FREE(wq);
++
++ return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++
++ if (wq->pending != 0) {
++ struct work_container *container;
++
++ DWC_ERROR("Destroying work queue with pending work");
++
++ DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
++ DWC_ERROR("Work %s still pending", container->name);
++ }
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++#endif
++ DWC_WAITQ_FREE(wq->waitq);
++ DWC_SPINLOCK_FREE(wq->lock);
++ taskqueue_free(wq->taskq);
++ DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++ char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ container->hz = 0;
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++
++ TASK_INIT(&container->task, 0, do_work, container);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ taskqueue_enqueue_fast(wq->taskq, &container->task);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ struct timeval tv;
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ container->hz = tvtohz(&tv);
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++
++ TASK_INIT(&container->task, 0, do_work, container);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ taskqueue_enqueue_fast(wq->taskq, &container->task);
++}
++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++ return wq->pending;
++}
+diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
+new file mode 100644
+index 000000000000..1460afaf997d
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
+@@ -0,0 +1,1409 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the Linux kernel implementation of the DWC platform library. */
++#include <linux/moduleparam.h>
++#include <linux/ctype.h>
++#include <linux/crypto.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/cdev.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/random.h>
++#include <linux/scatterlist.h>
++#include <linux/slab.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/timer.h>
++#include <linux/usb.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++# include <linux/usb/gadget.h>
++#else
++# include <linux/usb_gadget.h>
++#endif
++
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++ return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++ return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++ return memmove(dest, src, size);
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++ return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++ return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++ return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++ return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++ return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++ int len = DWC_STRLEN(str) + 1;
++ char *new = DWC_ALLOC_ATOMIC(len);
++
++ if (!new) {
++ return NULL;
++ }
++
++ DWC_MEMCPY(new, str, len);
++ return new;
++}
++
++int DWC_ATOI(const char *str, int32_t *value)
++{
++ char *end = NULL;
++
++ *value = simple_strtol(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++int DWC_ATOUI(const char *str, uint32_t *value)
++{
++ char *end = NULL;
++
++ *value = simple_strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++#endif /* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++ return in_irq();
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++ return in_softirq();
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++ vprintk(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++ return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsprintf(buffer, format, args);
++ va_end(args);
++ return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsnprintf(buffer, size, format, args);
++ va_end(args);
++ return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_WARNING);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_ERR);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_ERR);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++ BUG_ON(1);
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_DEBUG);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++ uint32_t align,
++ uint32_t alloc)
++{
++ struct dma_pool *pool = dma_pool_create("Pool", NULL,
++ size, align, alloc);
++ return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++ dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++ memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++ dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ return dma_alloc_coherent(dma_ctx, size, dma_addr, GFP_KERNEL | GFP_DMA32);
++}
++
++void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ return dma_alloc_coherent(dma_ctx, size, dma_addr, GFP_ATOMIC);
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++ dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++ return kzalloc(size, GFP_KERNEL);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++ return kzalloc(size, GFP_ATOMIC);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++ kfree(addr);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++ get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ struct scatterlist sgd;
++ struct scatterlist sgs;
++
++ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++ if (tfm == NULL) {
++ printk("failed to load transform for aes CBC\n");
++ return -1;
++ }
++
++ crypto_blkcipher_setkey(tfm, key, keylen);
++ crypto_blkcipher_set_iv(tfm, iv, 16);
++
++ sg_init_one(&sgd, out, messagelen);
++ sg_init_one(&sgs, message, messagelen);
++
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++ crypto_free_blkcipher(tfm);
++ DWC_ERROR("AES CBC encryption failed");
++ return -1;
++ }
++
++ crypto_free_blkcipher(tfm);
++ return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, len);
++ crypto_hash_digest(&desc, &sg, len, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, messagelen);
++ crypto_hash_setkey(tfm, key, keylen);
++ crypto_hash_digest(&desc, &sg, messagelen, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++#endif /* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(uint32_t volatile *reg)
++{
++ return readl(reg);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(uint64_t volatile *reg)
++{
++}
++#endif
++
++void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
++{
++ writel(value, reg);
++}
++
++#if 0
++void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
++{
++}
++#endif
++
++void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
++{
++ writel((readl(reg) & ~clear_mask) | set_mask, reg);
++}
++
++#if 0
++void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
++{
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++ spinlock_t *sl = (spinlock_t *)1;
++
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ sl = DWC_ALLOC(sizeof(*sl));
++ if (!sl) {
++ DWC_ERROR("Cannot allocate memory for spinlock\n");
++ return NULL;
++ }
++
++ spin_lock_init(sl);
++#endif
++ return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ DWC_FREE(lock);
++#endif
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_lock((spinlock_t *)lock);
++#endif
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_unlock((spinlock_t *)lock);
++#endif
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++ dwc_irqflags_t f;
++
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_lock_irqsave((spinlock_t *)lock, f);
++#else
++ local_irq_save(f);
++#endif
++ *flags = f;
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_unlock_irqrestore((spinlock_t *)lock, flags);
++#else
++ local_irq_restore(flags);
++#endif
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++ struct mutex *m;
++ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
++
++ if (!mutex) {
++ DWC_ERROR("Cannot allocate memory for mutex\n");
++ return NULL;
++ }
++
++ m = (struct mutex *)mutex;
++ mutex_init(m);
++ return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++ mutex_destroy((struct mutex *)mutex);
++ DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++ struct mutex *m = (struct mutex *)mutex;
++ mutex_lock(m);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++ struct mutex *m = (struct mutex *)mutex;
++ return mutex_trylock(m);
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++ struct mutex *m = (struct mutex *)mutex;
++ mutex_unlock(m);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++ udelay(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++ mdelay(msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++ msleep(msecs);
++}
++
++uint32_t DWC_TIME(void)
++{
++ return jiffies_to_msecs(jiffies);
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++ struct timer_list t;
++ char *name;
++ dwc_timer_callback_t cb;
++ void *data;
++ uint8_t scheduled;
++ dwc_spinlock_t *lock;
++};
++
++static void timer_callback(struct timer_list *tt)
++{
++ dwc_timer_t *timer = from_timer(timer, tt, t);
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++ timer->scheduled = 0;
++ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++ DWC_DEBUGC("Timer %s callback", timer->name);
++ timer->cb(timer->data);
++}
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (!t) {
++ DWC_ERROR("Cannot allocate memory for timer");
++ return NULL;
++ }
++
++ t->name = DWC_STRDUP(name);
++ if (!t->name) {
++ DWC_ERROR("Cannot allocate memory for timer->name");
++ goto no_name;
++ }
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
++ DWC_SPINLOCK_ALLOC_LINUX_DEBUG(t->lock);
++#else
++ t->lock = DWC_SPINLOCK_ALLOC();
++#endif
++ if (!t->lock) {
++ DWC_ERROR("Cannot allocate memory for lock");
++ goto no_lock;
++ }
++
++ t->scheduled = 0;
++ t->t.expires = jiffies;
++ timer_setup(&t->t, timer_callback, 0);
++
++ t->cb = cb;
++ t->data = data;
++
++ return t;
++
++ no_lock:
++ DWC_FREE(t->name);
++ no_name:
++ DWC_FREE(t);
++ return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++
++ if (timer->scheduled) {
++ del_timer(&timer->t);
++ timer->scheduled = 0;
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++ DWC_SPINLOCK_FREE(timer->lock);
++ DWC_FREE(timer->name);
++ DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++
++ if (!timer->scheduled) {
++ timer->scheduled = 1;
++ DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
++ timer->t.expires = jiffies + msecs_to_jiffies(time);
++ add_timer(&timer->t);
++ } else {
++ DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
++ mod_timer(&timer->t, jiffies + msecs_to_jiffies(time));
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++ del_timer(&timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++ wait_queue_head_t queue;
++ int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue\n");
++ return NULL;
++ }
++
++ init_waitqueue_head(&wq->queue);
++ wq->abort = 0;
++ return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++ DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++ int result = wait_event_interruptible(wq->queue,
++ cond(data) || wq->abort);
++ if (result == -ERESTARTSYS) {
++ wq->abort = 0;
++ return -DWC_E_RESTART;
++ }
++
++ if (wq->abort == 1) {
++ wq->abort = 0;
++ return -DWC_E_ABORT;
++ }
++
++ wq->abort = 0;
++
++ if (result == 0) {
++ return 0;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs)
++{
++ int32_t tmsecs;
++ int result = wait_event_interruptible_timeout(wq->queue,
++ cond(data) || wq->abort,
++ msecs_to_jiffies(msecs));
++ if (result == -ERESTARTSYS) {
++ wq->abort = 0;
++ return -DWC_E_RESTART;
++ }
++
++ if (wq->abort == 1) {
++ wq->abort = 0;
++ return -DWC_E_ABORT;
++ }
++
++ wq->abort = 0;
++
++ if (result > 0) {
++ tmsecs = jiffies_to_msecs(result);
++ if (!tmsecs) {
++ return 1;
++ }
++
++ return tmsecs;
++ }
++
++ if (result == 0) {
++ return -DWC_E_TIMEOUT;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++ wq->abort = 0;
++ wake_up_interruptible(&wq->queue);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++ wq->abort = 1;
++ wake_up_interruptible(&wq->queue);
++}
++
++
++/* Threading */
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++ struct task_struct *thread = kthread_run(func, data, name);
++
++ if (thread == ERR_PTR(-ENOMEM)) {
++ return NULL;
++ }
++
++ return (dwc_thread_t *)thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++ return kthread_stop((struct task_struct *)thread);
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
++{
++ return kthread_should_stop();
++}
++
++
++/* tasklets
++ - run in interrupt context (cannot sleep)
++ - each tasklet runs on a single CPU
++ - different tasklets can be running simultaneously on different CPUs
++ */
++struct dwc_tasklet {
++ struct tasklet_struct t;
++ dwc_tasklet_callback_t cb;
++ void *data;
++};
++
++static void tasklet_callback(unsigned long data)
++{
++ dwc_tasklet_t *t = (dwc_tasklet_t *)data;
++ t->cb(t->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++ dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (t) {
++ t->cb = cb;
++ t->data = data;
++ tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
++ } else {
++ DWC_ERROR("Cannot allocate memory for tasklet\n");
++ }
++
++ return t;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++ DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++ tasklet_schedule(&task->t);
++}
++
++void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task)
++{
++ tasklet_hi_schedule(&task->t);
++}
++
++
++/* workqueues
++ - run in process context (can sleep)
++ */
++typedef struct work_container {
++ dwc_work_callback_t cb;
++ void *data;
++ dwc_workq_t *wq;
++ char *name;
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_ENTRY(work_container) entry;
++#endif
++ struct delayed_work work;
++} work_container_t;
++
++#ifdef DEBUG
++DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
++#endif
++
++struct dwc_workq {
++ struct workqueue_struct *wq;
++ dwc_spinlock_t *lock;
++ dwc_waitq_t *waitq;
++ int pending;
++
++#ifdef DEBUG
++ struct work_container_queue entries;
++#endif
++};
++
++static void do_work(struct work_struct *work)
++{
++ dwc_irqflags_t flags;
++ struct delayed_work *dw = container_of(work, struct delayed_work, work);
++ work_container_t *container = container_of(dw, struct work_container, work);
++ dwc_workq_t *wq = container->wq;
++
++ container->cb(container->data);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
++#endif
++ DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
++ if (container->name) {
++ DWC_FREE(container->name);
++ }
++ DWC_FREE(container);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending--;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++ dwc_workq_t *workq = (dwc_workq_t *)data;
++ return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ return NULL;
++ }
++
++ wq->wq = create_singlethread_workqueue(name);
++ if (!wq->wq) {
++ goto no_wq;
++ }
++
++ wq->pending = 0;
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
++ DWC_SPINLOCK_ALLOC_LINUX_DEBUG(wq->lock);
++#else
++ wq->lock = DWC_SPINLOCK_ALLOC();
++#endif
++ if (!wq->lock) {
++ goto no_lock;
++ }
++
++ wq->waitq = DWC_WAITQ_ALLOC();
++ if (!wq->waitq) {
++ goto no_waitq;
++ }
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INIT(&wq->entries);
++#endif
++ return wq;
++
++ no_waitq:
++ DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++ destroy_workqueue(wq->wq);
++ no_wq:
++ DWC_FREE(wq);
++
++ return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++ if (wq->pending != 0) {
++ struct work_container *wc;
++ DWC_ERROR("Destroying work queue with pending work");
++ DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
++ DWC_ERROR("Work %s still pending", wc->name);
++ }
++ }
++#endif
++ destroy_workqueue(wq->wq);
++ DWC_SPINLOCK_FREE(wq->lock);
++ DWC_WAITQ_FREE(wq->waitq);
++ DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++ char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container\n");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name\n");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
++ INIT_WORK(&container->work.work, do_work);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ queue_work(wq->wq, &container->work.work);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container\n");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name\n");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
++ INIT_DELAYED_WORK(&container->work, do_work);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
++}
++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++ return wq->pending;
++}
++
++
++#ifdef DWC_LIBMODULE
++
++#ifdef DWC_CCLIB
++/* CC */
++EXPORT_SYMBOL(dwc_cc_if_alloc);
++EXPORT_SYMBOL(dwc_cc_if_free);
++EXPORT_SYMBOL(dwc_cc_clear);
++EXPORT_SYMBOL(dwc_cc_add);
++EXPORT_SYMBOL(dwc_cc_remove);
++EXPORT_SYMBOL(dwc_cc_change);
++EXPORT_SYMBOL(dwc_cc_data_for_save);
++EXPORT_SYMBOL(dwc_cc_restore_from_data);
++EXPORT_SYMBOL(dwc_cc_match_chid);
++EXPORT_SYMBOL(dwc_cc_match_cdid);
++EXPORT_SYMBOL(dwc_cc_ck);
++EXPORT_SYMBOL(dwc_cc_chid);
++EXPORT_SYMBOL(dwc_cc_cdid);
++EXPORT_SYMBOL(dwc_cc_name);
++#endif /* DWC_CCLIB */
++
++#ifdef DWC_CRYPTOLIB
++# ifndef CONFIG_MACH_IPMATE
++/* Modpow */
++EXPORT_SYMBOL(dwc_modpow);
++
++/* DH */
++EXPORT_SYMBOL(dwc_dh_modpow);
++EXPORT_SYMBOL(dwc_dh_derive_keys);
++EXPORT_SYMBOL(dwc_dh_pk);
++# endif /* CONFIG_MACH_IPMATE */
++
++/* Crypto */
++EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
++EXPORT_SYMBOL(dwc_wusb_cmf);
++EXPORT_SYMBOL(dwc_wusb_prf);
++EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
++EXPORT_SYMBOL(dwc_wusb_gen_nonce);
++EXPORT_SYMBOL(dwc_wusb_gen_key);
++EXPORT_SYMBOL(dwc_wusb_gen_mic);
++#endif /* DWC_CRYPTOLIB */
++
++/* Notification */
++#ifdef DWC_NOTIFYLIB
++EXPORT_SYMBOL(dwc_alloc_notification_manager);
++EXPORT_SYMBOL(dwc_free_notification_manager);
++EXPORT_SYMBOL(dwc_register_notifier);
++EXPORT_SYMBOL(dwc_unregister_notifier);
++EXPORT_SYMBOL(dwc_add_observer);
++EXPORT_SYMBOL(dwc_remove_observer);
++EXPORT_SYMBOL(dwc_notify);
++#endif
++
++/* Memory Debugging Routines */
++#ifdef DWC_DEBUG_MEMORY
++EXPORT_SYMBOL(dwc_alloc_debug);
++EXPORT_SYMBOL(dwc_alloc_atomic_debug);
++EXPORT_SYMBOL(dwc_free_debug);
++EXPORT_SYMBOL(dwc_dma_alloc_debug);
++EXPORT_SYMBOL(dwc_dma_free_debug);
++#endif
++
++EXPORT_SYMBOL(DWC_MEMSET);
++EXPORT_SYMBOL(DWC_MEMCPY);
++EXPORT_SYMBOL(DWC_MEMMOVE);
++EXPORT_SYMBOL(DWC_MEMCMP);
++EXPORT_SYMBOL(DWC_STRNCMP);
++EXPORT_SYMBOL(DWC_STRCMP);
++EXPORT_SYMBOL(DWC_STRLEN);
++EXPORT_SYMBOL(DWC_STRCPY);
++EXPORT_SYMBOL(DWC_STRDUP);
++EXPORT_SYMBOL(DWC_ATOI);
++EXPORT_SYMBOL(DWC_ATOUI);
++
++#ifdef DWC_UTFLIB
++EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
++#endif /* DWC_UTFLIB */
++
++EXPORT_SYMBOL(DWC_IN_IRQ);
++EXPORT_SYMBOL(DWC_IN_BH);
++EXPORT_SYMBOL(DWC_VPRINTF);
++EXPORT_SYMBOL(DWC_VSNPRINTF);
++EXPORT_SYMBOL(DWC_PRINTF);
++EXPORT_SYMBOL(DWC_SPRINTF);
++EXPORT_SYMBOL(DWC_SNPRINTF);
++EXPORT_SYMBOL(__DWC_WARN);
++EXPORT_SYMBOL(__DWC_ERROR);
++EXPORT_SYMBOL(DWC_EXCEPTION);
++
++#ifdef DEBUG
++EXPORT_SYMBOL(__DWC_DEBUG);
++#endif
++
++EXPORT_SYMBOL(__DWC_DMA_ALLOC);
++EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
++EXPORT_SYMBOL(__DWC_DMA_FREE);
++EXPORT_SYMBOL(__DWC_ALLOC);
++EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
++EXPORT_SYMBOL(__DWC_FREE);
++
++#ifdef DWC_CRYPTOLIB
++EXPORT_SYMBOL(DWC_RANDOM_BYTES);
++EXPORT_SYMBOL(DWC_AES_CBC);
++EXPORT_SYMBOL(DWC_SHA256);
++EXPORT_SYMBOL(DWC_HMAC_SHA256);
++#endif
++
++EXPORT_SYMBOL(DWC_CPU_TO_LE32);
++EXPORT_SYMBOL(DWC_CPU_TO_BE32);
++EXPORT_SYMBOL(DWC_LE32_TO_CPU);
++EXPORT_SYMBOL(DWC_BE32_TO_CPU);
++EXPORT_SYMBOL(DWC_CPU_TO_LE16);
++EXPORT_SYMBOL(DWC_CPU_TO_BE16);
++EXPORT_SYMBOL(DWC_LE16_TO_CPU);
++EXPORT_SYMBOL(DWC_BE16_TO_CPU);
++EXPORT_SYMBOL(DWC_READ_REG32);
++EXPORT_SYMBOL(DWC_WRITE_REG32);
++EXPORT_SYMBOL(DWC_MODIFY_REG32);
++
++#if 0
++EXPORT_SYMBOL(DWC_READ_REG64);
++EXPORT_SYMBOL(DWC_WRITE_REG64);
++EXPORT_SYMBOL(DWC_MODIFY_REG64);
++#endif
++
++EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
++EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
++EXPORT_SYMBOL(DWC_SPINLOCK);
++EXPORT_SYMBOL(DWC_SPINUNLOCK);
++EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
++EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
++EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
++
++#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
++EXPORT_SYMBOL(DWC_MUTEX_FREE);
++#endif
++
++EXPORT_SYMBOL(DWC_MUTEX_LOCK);
++EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
++EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
++EXPORT_SYMBOL(DWC_UDELAY);
++EXPORT_SYMBOL(DWC_MDELAY);
++EXPORT_SYMBOL(DWC_MSLEEP);
++EXPORT_SYMBOL(DWC_TIME);
++EXPORT_SYMBOL(DWC_TIMER_ALLOC);
++EXPORT_SYMBOL(DWC_TIMER_FREE);
++EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
++EXPORT_SYMBOL(DWC_TIMER_CANCEL);
++EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
++EXPORT_SYMBOL(DWC_WAITQ_FREE);
++EXPORT_SYMBOL(DWC_WAITQ_WAIT);
++EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
++EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
++EXPORT_SYMBOL(DWC_WAITQ_ABORT);
++EXPORT_SYMBOL(DWC_THREAD_RUN);
++EXPORT_SYMBOL(DWC_THREAD_STOP);
++EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
++EXPORT_SYMBOL(DWC_TASK_ALLOC);
++EXPORT_SYMBOL(DWC_TASK_FREE);
++EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
++EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
++EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
++EXPORT_SYMBOL(DWC_WORKQ_FREE);
++EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
++EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
++EXPORT_SYMBOL(DWC_WORKQ_PENDING);
++
++static int dwc_common_port_init_module(void)
++{
++ int result = 0;
++
++ printk(KERN_DEBUG "Module dwc_common_port init\n" );
++
++#ifdef DWC_DEBUG_MEMORY
++ result = dwc_memory_debug_start(NULL);
++ if (result) {
++ printk(KERN_ERR
++ "dwc_memory_debug_start() failed with error %d\n",
++ result);
++ return result;
++ }
++#endif
++
++#ifdef DWC_NOTIFYLIB
++ result = dwc_alloc_notification_manager(NULL, NULL);
++ if (result) {
++ printk(KERN_ERR
++ "dwc_alloc_notification_manager() failed with error %d\n",
++ result);
++ return result;
++ }
++#endif
++ return result;
++}
++
++static void dwc_common_port_exit_module(void)
++{
++ printk(KERN_DEBUG "Module dwc_common_port exit\n" );
++
++#ifdef DWC_NOTIFYLIB
++ dwc_free_notification_manager();
++#endif
++
++#ifdef DWC_DEBUG_MEMORY
++ dwc_memory_debug_stop();
++#endif
++}
++
++module_init(dwc_common_port_init_module);
++module_exit(dwc_common_port_exit_module);
++
++MODULE_DESCRIPTION("DWC Common Library - Portable version");
++MODULE_AUTHOR("Synopsys Inc.");
++MODULE_LICENSE ("GPL");
++
++#endif /* DWC_LIBMODULE */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
+new file mode 100644
+index 000000000000..49b07e172264
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
+@@ -0,0 +1,1275 @@
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++ return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++ return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++ bcopy(src, dest, size);
++ return dest;
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++ return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++ return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++ return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++ return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++ return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++ int len = DWC_STRLEN(str) + 1;
++ char *new = DWC_ALLOC_ATOMIC(len);
++
++ if (!new) {
++ return NULL;
++ }
++
++ DWC_MEMCPY(new, str, len);
++ return new;
++}
++
++int DWC_ATOI(char *str, int32_t *value)
++{
++ char *end = NULL;
++
++ /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
++ * should be equivalent on 2's complement machines
++ */
++ *value = strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++int DWC_ATOUI(char *str, uint32_t *value)
++{
++ char *end = NULL;
++
++ *value = strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++
++#endif /* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++// return in_irq();
++ return 0;
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++// return in_softirq();
++ return 0;
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++ vprintf(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++ return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsprintf(buffer, format, args);
++ va_end(args);
++ return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsnprintf(buffer, size, format, args);
++ va_end(args);
++ return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++// BUG_ON(1); ???
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++ uint32_t align,
++ uint32_t alloc)
++{
++ struct dma_pool *pool = dma_pool_create("Pool", NULL,
++ size, align, alloc);
++ return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++ dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++ memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++ dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++ int error;
++
++ error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
++ sizeof(dma->segs) / sizeof(dma->segs[0]),
++ &dma->nsegs, BUS_DMA_NOWAIT);
++ if (error) {
++ printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
++ (uintmax_t)size, error);
++ goto fail_0;
++ }
++
++ error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
++ (caddr_t *)&dma->dma_vaddr,
++ BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
++ if (error) {
++ printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
++ goto fail_1;
++ }
++
++ error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
++ BUS_DMA_NOWAIT, &dma->dma_map);
++ if (error) {
++ printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
++ goto fail_2;
++ }
++
++ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
++ size, NULL, BUS_DMA_NOWAIT);
++ if (error) {
++ printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
++ goto fail_3;
++ }
++
++ dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
++ *dma_addr = dma->dma_paddr;
++ return dma->dma_vaddr;
++
++fail_3:
++ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
++fail_2:
++ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
++fail_1:
++ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
++fail_0:
++ dma->dma_map = NULL;
++ dma->dma_vaddr = NULL;
++ dma->nsegs = 0;
++
++ return NULL;
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++
++ if (dma->dma_map != NULL) {
++ bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
++ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
++ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
++ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
++ dma->dma_paddr = 0;
++ dma->dma_map = NULL;
++ dma->dma_vaddr = NULL;
++ dma->nsegs = 0;
++ }
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++ free(addr, M_DEVBUF);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++ get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ struct scatterlist sgd;
++ struct scatterlist sgs;
++
++ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++ if (tfm == NULL) {
++ printk("failed to load transform for aes CBC\n");
++ return -1;
++ }
++
++ crypto_blkcipher_setkey(tfm, key, keylen);
++ crypto_blkcipher_set_iv(tfm, iv, 16);
++
++ sg_init_one(&sgd, out, messagelen);
++ sg_init_one(&sgs, message, messagelen);
++
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++ crypto_free_blkcipher(tfm);
++ DWC_ERROR("AES CBC encryption failed");
++ return -1;
++ }
++
++ crypto_free_blkcipher(tfm);
++ return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, len);
++ crypto_hash_digest(&desc, &sg, len, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, messagelen);
++ crypto_hash_setkey(tfm, key, keylen);
++ crypto_hash_digest(&desc, &sg, messagelen, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++#endif /* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_4(io->iot, io->ioh, ior);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_8(io->iot, io->ioh, ior);
++}
++#endif
++
++void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior, value);
++}
++
++#if 0
++void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior, value);
++}
++#endif
++
++void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
++ uint32_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior,
++ (bus_space_read_4(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++
++#if 0
++void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
++ uint64_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior,
++ (bus_space_read_8(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++ struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
++
++ if (!sl) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ return NULL;
++ }
++
++ simple_lock_init(sl);
++ return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++ struct simplelock *sl = (struct simplelock *)lock;
++
++ DWC_FREE(sl);
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++ simple_lock((struct simplelock *)lock);
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++ simple_unlock((struct simplelock *)lock);
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++ simple_lock((struct simplelock *)lock);
++ *flags = splbio();
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++ splx(flags);
++ simple_unlock((struct simplelock *)lock);
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++ dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
++
++ if (!mutex) {
++ DWC_ERROR("Cannot allocate memory for mutex");
++ return NULL;
++ }
++
++ lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
++ return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++ DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++ lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++ int status;
++
++ status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
++ return status == 0;
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++ lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++ DELAY(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++ do {
++ DELAY(1000);
++ } while (--msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++ struct timeval tv;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++ tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
++}
++
++uint32_t DWC_TIME(void)
++{
++ struct timeval tv;
++
++ microuptime(&tv); // or getmicrouptime? (less precise, but faster)
++ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++ struct callout t;
++ char *name;
++ dwc_spinlock_t *lock;
++ dwc_timer_callback_t cb;
++ void *data;
++};
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (!t) {
++ DWC_ERROR("Cannot allocate memory for timer");
++ return NULL;
++ }
++
++ callout_init(&t->t);
++
++ t->name = DWC_STRDUP(name);
++ if (!t->name) {
++ DWC_ERROR("Cannot allocate memory for timer->name");
++ goto no_name;
++ }
++
++ t->lock = DWC_SPINLOCK_ALLOC();
++ if (!t->lock) {
++ DWC_ERROR("Cannot allocate memory for timer->lock");
++ goto no_lock;
++ }
++
++ t->cb = cb;
++ t->data = data;
++
++ return t;
++
++ no_lock:
++ DWC_FREE(t->name);
++ no_name:
++ DWC_FREE(t);
++
++ return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++ DWC_SPINLOCK_FREE(timer->lock);
++ DWC_FREE(timer->name);
++ DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++ struct timeval tv;
++
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++ struct simplelock lock;
++ int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ return NULL;
++ }
++
++ simple_lock_init(&wq->lock);
++ wq->abort = 0;
++
++ return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++ DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++ int ipl;
++ int result = 0;
++
++ simple_lock(&wq->lock);
++ ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++ splx(ipl);
++ result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
++ ipl = splbio();
++ }
++
++ if (result == 0) { // awoken
++ if (wq->abort) {
++ wq->abort = 0;
++ result = -DWC_E_ABORT;
++ } else {
++ result = 0;
++ }
++
++ splx(ipl);
++ simple_unlock(&wq->lock);
++ } else {
++ wq->abort = 0;
++ splx(ipl);
++ simple_unlock(&wq->lock);
++
++ if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++ } else { // signaled - must be EINTR
++ result = -DWC_E_ABORT;
++ }
++ }
++
++ return result;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs)
++{
++ struct timeval tv, tv1, tv2;
++ int ipl;
++ int result = 0;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++
++ simple_lock(&wq->lock);
++ ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++ splx(ipl);
++ getmicrouptime(&tv1);
++ result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
++ getmicrouptime(&tv2);
++ ipl = splbio();
++ }
++
++ if (result == 0) { // awoken
++ if (wq->abort) {
++ wq->abort = 0;
++ splx(ipl);
++ simple_unlock(&wq->lock);
++ result = -DWC_E_ABORT;
++ } else {
++ splx(ipl);
++ simple_unlock(&wq->lock);
++
++ tv2.tv_usec -= tv1.tv_usec;
++ if (tv2.tv_usec < 0) {
++ tv2.tv_usec += 1000000;
++ tv2.tv_sec--;
++ }
++
++ tv2.tv_sec -= tv1.tv_sec;
++ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
++ result = msecs - result;
++ if (result <= 0)
++ result = 1;
++ }
++ } else {
++ wq->abort = 0;
++ splx(ipl);
++ simple_unlock(&wq->lock);
++
++ if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++
++ } else if (result == EINTR) { // signaled - interrupt
++ result = -DWC_E_ABORT;
++
++ } else { // timed out
++ result = -DWC_E_TIMEOUT;
++ }
++ }
++
++ return result;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++ wakeup(wq);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++ int ipl;
++
++ simple_lock(&wq->lock);
++ ipl = splbio();
++ wq->abort = 1;
++ wakeup(wq);
++ splx(ipl);
++ simple_unlock(&wq->lock);
++}
++
++
++/* Threading */
++
++struct dwc_thread {
++ struct proc *proc;
++ int abort;
++};
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++ int retval;
++ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
++
++ if (!thread) {
++ return NULL;
++ }
++
++ thread->abort = 0;
++ retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
++ "%s", name);
++ if (retval) {
++ DWC_FREE(thread);
++ return NULL;
++ }
++
++ return thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++ int retval;
++
++ thread->abort = 1;
++ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
++
++ if (retval == 0) {
++ /* DWC_THREAD_EXIT() will free the thread struct */
++ return 0;
++ }
++
++ /* NOTE: We leak the thread struct if thread doesn't die */
++
++ if (retval == EWOULDBLOCK) {
++ return -DWC_E_TIMEOUT;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
++{
++ return thread->abort;
++}
++
++void DWC_THREAD_EXIT(dwc_thread_t *thread)
++{
++ wakeup(&thread->abort);
++ DWC_FREE(thread);
++ kthread_exit(0);
++}
++
++/* tasklets
++ - Runs in interrupt context (cannot sleep)
++ - Each tasklet runs on a single CPU
++ - Different tasklets can be running simultaneously on different CPUs
++ [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
++ halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
++ */
++struct dwc_tasklet {
++ dwc_tasklet_callback_t cb;
++ void *data;
++};
++
++static void tasklet_callback(void *data)
++{
++ dwc_tasklet_t *task = (dwc_tasklet_t *)data;
++
++ task->cb(task->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
++
++ if (task) {
++ task->cb = cb;
++ task->data = data;
++ } else {
++ DWC_ERROR("Cannot allocate memory for tasklet");
++ }
++
++ return task;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++ DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++ tasklet_callback(task);
++}
++
++
++/* workqueues
++ - Runs in process context (can sleep)
++ */
++typedef struct work_container {
++ dwc_work_callback_t cb;
++ void *data;
++ dwc_workq_t *wq;
++ char *name;
++ int hz;
++ struct work task;
++} work_container_t;
++
++struct dwc_workq {
++ struct workqueue *taskq;
++ dwc_spinlock_t *lock;
++ dwc_waitq_t *waitq;
++ int pending;
++ struct work_container *container;
++};
++
++static void do_work(struct work *task, void *data)
++{
++ dwc_workq_t *wq = (dwc_workq_t *)data;
++ work_container_t *container = wq->container;
++ dwc_irqflags_t flags;
++
++ if (container->hz) {
++ tsleep(container, 0, "dw3wrk", container->hz);
++ }
++
++ container->cb(container->data);
++ DWC_DEBUG("Work done: %s, container=%p", container->name, container);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ if (container->name)
++ DWC_FREE(container->name);
++ DWC_FREE(container);
++ wq->pending--;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++ dwc_workq_t *workq = (dwc_workq_t *)data;
++
++ return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++ int result;
++ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for workqueue");
++ return NULL;
++ }
++
++ result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
++ IPL_BIO, 0);
++ if (result) {
++ DWC_ERROR("Cannot create workqueue");
++ goto no_taskq;
++ }
++
++ wq->pending = 0;
++
++ wq->lock = DWC_SPINLOCK_ALLOC();
++ if (!wq->lock) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ goto no_lock;
++ }
++
++ wq->waitq = DWC_WAITQ_ALLOC();
++ if (!wq->waitq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ goto no_waitq;
++ }
++
++ return wq;
++
++ no_waitq:
++ DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++ workqueue_destroy(wq->taskq);
++ no_taskq:
++ DWC_FREE(wq);
++
++ return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++
++ if (wq->pending != 0) {
++ struct work_container *container = wq->container;
++
++ DWC_ERROR("Destroying work queue with pending work");
++
++ if (container && container->name) {
++ DWC_ERROR("Work %s still pending", container->name);
++ }
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++#endif
++ DWC_WAITQ_FREE(wq->waitq);
++ DWC_SPINLOCK_FREE(wq->lock);
++ workqueue_destroy(wq->taskq);
++ DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++ char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ container->hz = 0;
++ wq->container = container;
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++ workqueue_enqueue(wq->taskq, &container->task);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ struct timeval tv;
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ container->hz = tvtohz(&tv);
++ wq->container = container;
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++ workqueue_enqueue(wq->taskq, &container->task);
++}
++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++ return wq->pending;
++}
+diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.c b/drivers/usb/host/dwc_common_port/dwc_crypto.c
+new file mode 100644
+index 000000000000..3b0353296148
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
+@@ -0,0 +1,308 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
++ * $Revision: #5 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++
++/** @file
++ * This file contains the WUSB cryptographic routines.
++ */
++
++#ifdef DWC_CRYPTOLIB
++
++#include "dwc_crypto.h"
++#include "usb.h"
++
++#ifdef DEBUG
++static inline void dump_bytes(char *name, uint8_t *bytes, int len)
++{
++ int i;
++ DWC_PRINTF("%s: ", name);
++ for (i=0; i<len; i++) {
++ DWC_PRINTF("%02x ", bytes[i]);
++ }
++ DWC_PRINTF("\n");
++}
++#else
++#define dump_bytes(x...)
++#endif
++
++/* Display a block */
++void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
++{
++#ifdef DWC_DEBUG_CRYPTO
++ int i, blksize = 16;
++
++ DWC_DEBUG("%s", prefix);
++
++ if (suffix == NULL) {
++ suffix = "\n";
++ blksize = a;
++ }
++
++ for (i = 0; i < blksize; i++)
++ DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
++ DWC_PRINT(suffix);
++#endif
++}
++
++/**
++ * Encrypts an array of bytes using the AES encryption engine.
++ * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
++ * in-place.
++ *
++ * @return 0 on success, negative error code on error.
++ */
++int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
++{
++ u8 block_t[16];
++ DWC_MEMSET(block_t, 0, 16);
++
++ return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
++}
++
++/**
++ * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
++ * This function takes a data string and returns the encrypted CBC
++ * Counter-mode MIC.
++ *
++ * @param key The 128-bit symmetric key.
++ * @param nonce The CCM nonce.
++ * @param label The unique 14-byte ASCII text label.
++ * @param bytes The byte array to be encrypted.
++ * @param len Length of the byte array.
++ * @param result Byte array to receive the 8-byte encrypted MIC.
++ */
++void dwc_wusb_cmf(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ u8 block_m[16];
++ u8 block_x[16];
++ u8 block_t[8];
++ int idx, blkNum;
++ u16 la = (u16)(len + 14);
++
++ /* Set the AES-128 key */
++ //dwc_aes_setkey(tfm, key, 16);
++
++ /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
++ block_m[0] = 0x59;
++ for (idx = 0; idx < 13; idx++)
++ block_m[idx + 1] = nonce[idx];
++ block_m[14] = 0;
++ block_m[15] = 0;
++
++ /* Produce the CBC IV */
++ dwc_wusb_aes_encrypt(block_m, key, block_x);
++ show_block(block_m, "CBC IV in: ", "\n", 0);
++ show_block(block_x, "CBC IV out:", "\n", 0);
++
++ /* Fill block B1 from l(a) = Blen + 14, and A */
++ block_x[0] ^= (u8)(la >> 8);
++ block_x[1] ^= (u8)la;
++ for (idx = 0; idx < 14; idx++)
++ block_x[idx + 2] ^= label[idx];
++ show_block(block_x, "After xor: ", "b1\n", 16);
++
++ dwc_wusb_aes_encrypt(block_x, key, block_x);
++ show_block(block_x, "After AES: ", "b1\n", 16);
++
++ idx = 0;
++ blkNum = 0;
++
++ /* Fill remaining blocks with B */
++ while (len-- > 0) {
++ block_x[idx] ^= *bytes++;
++ if (++idx >= 16) {
++ idx = 0;
++ show_block(block_x, "After xor: ", "\n", blkNum);
++ dwc_wusb_aes_encrypt(block_x, key, block_x);
++ show_block(block_x, "After AES: ", "\n", blkNum);
++ blkNum++;
++ }
++ }
++
++ /* Handle partial last block */
++ if (idx > 0) {
++ show_block(block_x, "After xor: ", "\n", blkNum);
++ dwc_wusb_aes_encrypt(block_x, key, block_x);
++ show_block(block_x, "After AES: ", "\n", blkNum);
++ }
++
++ /* Save the MIC tag */
++ DWC_MEMCPY(block_t, block_x, 8);
++ show_block(block_t, "MIC tag : ", NULL, 8);
++
++ /* Fill block A0 from flags = 0x01, N, and counter = 0 */
++ block_m[0] = 0x01;
++ block_m[14] = 0;
++ block_m[15] = 0;
++
++ /* Encrypt the counter */
++ dwc_wusb_aes_encrypt(block_m, key, block_x);
++ show_block(block_x, "CTR[MIC] : ", NULL, 8);
++
++ /* XOR with MIC tag */
++ for (idx = 0; idx < 8; idx++) {
++ block_t[idx] ^= block_x[idx];
++ }
++
++ /* Return result to caller */
++ DWC_MEMCPY(result, block_t, 8);
++ show_block(result, "CCM-MIC : ", NULL, 8);
++
++}
++
++/**
++ * The PRF function described in section 6.5 of the WUSB spec. This function
++ * concatenates MIC values returned from dwc_cmf() to create a value of
++ * the requested length.
++ *
++ * @param prf_len Length of the PRF function in bits (64, 128, or 256).
++ * @param key, nonce, label, bytes, len Same as for dwc_cmf().
++ * @param result Byte array to receive the result.
++ */
++void dwc_wusb_prf(int prf_len, u8 *key,
++ u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
++{
++ int i;
++
++ nonce[0] = 0;
++ for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
++ dwc_wusb_cmf(key, nonce, label, bytes, len, result);
++ result += 8;
++ }
++}
++
++/**
++ * Fills in CCM Nonce per the WUSB spec.
++ *
++ * @param[in] haddr Host address.
++ * @param[in] daddr Device address.
++ * @param[in] tkid Session Key(PTK) identifier.
++ * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
++ */
++void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
++ uint8_t *nonce)
++{
++
++ DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
++
++ DWC_MEMSET(&nonce[0], 0, 16);
++
++ DWC_MEMCPY(&nonce[6], tkid, 3);
++ nonce[9] = daddr & 0xFF;
++ nonce[10] = (daddr >> 8) & 0xFF;
++ nonce[11] = haddr & 0xFF;
++ nonce[12] = (haddr >> 8) & 0xFF;
++
++ dump_bytes("CCM nonce", nonce, 16);
++}
++
++/**
++ * Generates a 16-byte cryptographic-grade random number for the Host/Device
++ * Nonce.
++ */
++void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
++{
++ uint8_t inonce[16];
++ uint32_t temp[4];
++
++ /* Fill in the Nonce */
++ DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
++ inonce[9] = addr & 0xFF;
++ inonce[10] = (addr >> 8) & 0xFF;
++ inonce[11] = inonce[9];
++ inonce[12] = inonce[10];
++
++ /* Collect "randomness samples" */
++ DWC_RANDOM_BYTES((uint8_t *)temp, 16);
++
++ dwc_wusb_prf_128((uint8_t *)temp, nonce,
++ "Random Numbers", (uint8_t *)temp, sizeof(temp),
++ nonce);
++}
++
++/**
++ * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
++ * WUSB spec.
++ *
++ * @param[in] ccm_nonce Pointer to CCM Nonce.
++ * @param[in] mk Master Key to derive the session from
++ * @param[in] hnonce Pointer to Host Nonce.
++ * @param[in] dnonce Pointer to Device Nonce.
++ * @param[out] kck Pointer to where the KCK output is to be written.
++ * @param[out] ptk Pointer to where the PTK output is to be written.
++ */
++void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
++ uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
++{
++ uint8_t idata[32];
++ uint8_t odata[32];
++
++ dump_bytes("ck", mk, 16);
++ dump_bytes("hnonce", hnonce, 16);
++ dump_bytes("dnonce", dnonce, 16);
++
++ /* The data is the HNonce and DNonce concatenated */
++ DWC_MEMCPY(&idata[0], hnonce, 16);
++ DWC_MEMCPY(&idata[16], dnonce, 16);
++
++ dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
++
++ /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
++ DWC_MEMCPY(kck, &odata[0], 16);
++ DWC_MEMCPY(ptk, &odata[16], 16);
++
++ dump_bytes("kck", kck, 16);
++ dump_bytes("ptk", ptk, 16);
++}
++
++/**
++ * Generates the Message Integrity Code over the Handshake data per the
++ * WUSB spec.
++ *
++ * @param ccm_nonce Pointer to CCM Nonce.
++ * @param kck Pointer to Key Confirmation Key.
++ * @param data Pointer to Handshake data to be checked.
++ * @param mic Pointer to where the MIC output is to be written.
++ */
++void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
++ uint8_t *data, uint8_t *mic)
++{
++
++ dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
++ data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
++}
++
++#endif /* DWC_CRYPTOLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.h b/drivers/usb/host/dwc_common_port/dwc_crypto.h
+new file mode 100644
+index 000000000000..26fcddcfe9ba
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
+@@ -0,0 +1,111 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
++ * $Revision: #3 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++
++#ifndef _DWC_CRYPTO_H_
++#define _DWC_CRYPTO_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file contains declarations for the WUSB Cryptographic routines as
++ * defined in the WUSB spec. They are only to be used internally by the DWC UWB
++ * modules.
++ */
++
++#include "dwc_os.h"
++
++int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
++
++void dwc_wusb_cmf(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result);
++void dwc_wusb_prf(int prf_len, u8 *key,
++ u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
++
++/**
++ * The PRF-64 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
++}
++
++/**
++ * The PRF-128 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
++}
++
++/**
++ * The PRF-256 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
++}
++
++
++void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
++ uint8_t *nonce);
++void dwc_wusb_gen_nonce(uint16_t addr,
++ uint8_t *nonce);
++
++void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
++ uint8_t *hnonce, uint8_t *dnonce,
++ uint8_t *kck, uint8_t *ptk);
++
++
++void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
++ *kck, uint8_t *data, uint8_t *mic);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CRYPTO_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.c b/drivers/usb/host/dwc_common_port/dwc_dh.c
+new file mode 100644
+index 000000000000..2b429a32aaf0
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
+@@ -0,0 +1,291 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
++ * $Revision: #3 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifdef DWC_CRYPTOLIB
++
++#ifndef CONFIG_MACH_IPMATE
++
++#include "dwc_dh.h"
++#include "dwc_modpow.h"
++
++#ifdef DEBUG
++/* This function prints out a buffer in the format described in the Association
++ * Model specification. */
++static void dh_dump(char *str, void *_num, int len)
++{
++ uint8_t *num = _num;
++ int i;
++ DWC_PRINTF("%s\n", str);
++ for (i = 0; i < len; i ++) {
++ DWC_PRINTF("%02x", num[i]);
++ if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
++ if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
++ }
++
++ DWC_PRINTF("\n");
++}
++#else
++#define dh_dump(_x...) do {; } while(0)
++#endif
++
++/* Constant g value */
++static __u32 dh_g[] = {
++ 0x02000000,
++};
++
++/* Constant p value */
++static __u32 dh_p[] = {
++ 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
++ 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
++ 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
++ 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
++ 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
++ 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
++ 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
++ 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
++ 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
++ 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
++ 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
++ 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
++};
++
++static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
++{
++ uint8_t *in = _in;
++ uint8_t *out = _out;
++ int i;
++ for (i=0; i<len; i++) {
++ out[i] = in[len-1-i];
++ }
++}
++
++/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
++ * big endian numbers of size len, in bytes. Each len value must be a multiple
++ * of 4. */
++int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
++ void *exp, uint32_t exp_len,
++ void *mod, uint32_t mod_len,
++ void *out)
++{
++ /* modpow() takes little endian numbers. AM uses big-endian. This
++ * function swaps bytes of numbers before passing onto modpow. */
++
++ int retval = 0;
++ uint32_t *result;
++
++ uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
++ uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
++ uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
++
++ dh_swap_bytes(num, &bignum_num[1], num_len);
++ bignum_num[0] = num_len / 4;
++
++ dh_swap_bytes(exp, &bignum_exp[1], exp_len);
++ bignum_exp[0] = exp_len / 4;
++
++ dh_swap_bytes(mod, &bignum_mod[1], mod_len);
++ bignum_mod[0] = mod_len / 4;
++
++ result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
++ if (!result) {
++ retval = -1;
++ goto dh_modpow_nomem;
++ }
++
++ dh_swap_bytes(&result[1], out, result[0] * 4);
++ dwc_free(mem_ctx, result);
++
++ dh_modpow_nomem:
++ dwc_free(mem_ctx, bignum_num);
++ dwc_free(mem_ctx, bignum_exp);
++ dwc_free(mem_ctx, bignum_mod);
++ return retval;
++}
++
++
++int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
++{
++ int retval;
++ uint8_t m3[385];
++
++#ifndef DH_TEST_VECTORS
++ DWC_RANDOM_BYTES(exp, 32);
++#endif
++
++ /* Compute the pkd */
++ if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
++ exp, 32,
++ dh_p, 384, pk))) {
++ return retval;
++ }
++
++ m3[384] = nd;
++ DWC_MEMCPY(&m3[0], pk, 384);
++ DWC_SHA256(m3, 385, hash);
++
++ dh_dump("PK", pk, 384);
++ dh_dump("SHA-256(M3)", hash, 32);
++ return 0;
++}
++
++int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
++ uint8_t *exp, int is_host,
++ char *dd, uint8_t *ck, uint8_t *kdk)
++{
++ int retval;
++ uint8_t mv[784];
++ uint8_t sha_result[32];
++ uint8_t dhkey[384];
++ uint8_t shared_secret[384];
++ char *message;
++ uint32_t vd;
++
++ uint8_t *pk;
++
++ if (is_host) {
++ pk = pkd;
++ }
++ else {
++ pk = pkh;
++ }
++
++ if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
++ exp, 32,
++ dh_p, 384, shared_secret))) {
++ return retval;
++ }
++ dh_dump("Shared Secret", shared_secret, 384);
++
++ DWC_SHA256(shared_secret, 384, dhkey);
++ dh_dump("DHKEY", dhkey, 384);
++
++ DWC_MEMCPY(&mv[0], pkd, 384);
++ DWC_MEMCPY(&mv[384], pkh, 384);
++ DWC_MEMCPY(&mv[768], "displayed digest", 16);
++ dh_dump("MV", mv, 784);
++
++ DWC_SHA256(mv, 784, sha_result);
++ dh_dump("SHA-256(MV)", sha_result, 32);
++ dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
++
++ dh_swap_bytes(sha_result, &vd, 4);
++#ifdef DEBUG
++ DWC_PRINTF("Vd (decimal) = %d\n", vd);
++#endif
++
++ switch (nd) {
++ case 2:
++ vd = vd % 100;
++ DWC_SPRINTF(dd, "%02d", vd);
++ break;
++ case 3:
++ vd = vd % 1000;
++ DWC_SPRINTF(dd, "%03d", vd);
++ break;
++ case 4:
++ vd = vd % 10000;
++ DWC_SPRINTF(dd, "%04d", vd);
++ break;
++ }
++#ifdef DEBUG
++ DWC_PRINTF("Display Digits: %s\n", dd);
++#endif
++
++ message = "connection key";
++ DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
++ dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
++ DWC_MEMCPY(ck, sha_result, 16);
++
++ message = "key derivation key";
++ DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
++ dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
++ DWC_MEMCPY(kdk, sha_result, 32);
++
++ return 0;
++}
++
++
++#ifdef DH_TEST_VECTORS
++
++static __u8 dh_a[] = {
++ 0x44, 0x00, 0x51, 0xd6,
++ 0xf0, 0xb5, 0x5e, 0xa9,
++ 0x67, 0xab, 0x31, 0xc6,
++ 0x8a, 0x8b, 0x5e, 0x37,
++ 0xd9, 0x10, 0xda, 0xe0,
++ 0xe2, 0xd4, 0x59, 0xa4,
++ 0x86, 0x45, 0x9c, 0xaa,
++ 0xdf, 0x36, 0x75, 0x16,
++};
++
++static __u8 dh_b[] = {
++ 0x5d, 0xae, 0xc7, 0x86,
++ 0x79, 0x80, 0xa3, 0x24,
++ 0x8c, 0xe3, 0x57, 0x8f,
++ 0xc7, 0x5f, 0x1b, 0x0f,
++ 0x2d, 0xf8, 0x9d, 0x30,
++ 0x6f, 0xa4, 0x52, 0xcd,
++ 0xe0, 0x7a, 0x04, 0x8a,
++ 0xde, 0xd9, 0x26, 0x56,
++};
++
++void dwc_run_dh_test_vectors(void *mem_ctx)
++{
++ uint8_t pkd[384];
++ uint8_t pkh[384];
++ uint8_t hashd[32];
++ uint8_t hashh[32];
++ uint8_t ck[16];
++ uint8_t kdk[32];
++ char dd[5];
++
++ DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
++
++ /* compute the PKd and SHA-256(PKd || Nd) */
++ DWC_PRINTF("Computing PKd\n");
++ dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
++
++ /* compute the PKd and SHA-256(PKh || Nd) */
++ DWC_PRINTF("Computing PKh\n");
++ dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
++
++ /* compute the dhkey */
++ dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
++}
++#endif /* DH_TEST_VECTORS */
++
++#endif /* !CONFIG_MACH_IPMATE */
++
++#endif /* DWC_CRYPTOLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.h b/drivers/usb/host/dwc_common_port/dwc_dh.h
+new file mode 100644
+index 000000000000..25c1cc0d588a
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
+@@ -0,0 +1,106 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
++ * $Revision: #4 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifndef _DWC_DH_H_
++#define _DWC_DH_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * This file defines the common functions on device and host for performing
++ * numeric association as defined in the WUSB spec. They are only to be
++ * used internally by the DWC UWB modules. */
++
++extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
++extern int dwc_dh_hmac_sha256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen,
++ uint8_t *out);
++extern int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
++ void *exp, uint32_t exp_len,
++ void *mod, uint32_t mod_len,
++ void *out);
++
++/** Computes PKD or PKH, and SHA-256(PKd || Nd)
++ *
++ * PK = g^exp mod p.
++ *
++ * Input:
++ * Nd = Number of digits on the device.
++ *
++ * Output:
++ * exp = A 32-byte buffer to be filled with a randomly generated number.
++ * used as either A or B.
++ * pk = A 384-byte buffer to be filled with the PKH or PKD.
++ * hash = A 32-byte buffer to be filled with SHA-256(PK || ND).
++ */
++extern int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash);
++
++/** Computes the DHKEY, and VD.
++ *
++ * If called from host, then it will comput DHKEY=PKD^exp % p.
++ * If called from device, then it will comput DHKEY=PKH^exp % p.
++ *
++ * Input:
++ * pkd = The PKD value.
++ * pkh = The PKH value.
++ * exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk.
++ * is_host = Set to non zero if a WUSB host is calling this function.
++ *
++ * Output:
++
++ * dd = A pointer to an buffer to be set to the displayed digits string to be shown
++ * to the user. This buffer should be at 5 bytes long to hold 4 digits plus a
++ * null termination character. This buffer can be used directly for display.
++ * ck = A 16-byte buffer to be filled with the CK.
++ * kdk = A 32-byte buffer to be filled with the KDK.
++ */
++extern int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
++ uint8_t *exp, int is_host,
++ char *dd, uint8_t *ck, uint8_t *kdk);
++
++#ifdef DH_TEST_VECTORS
++extern void dwc_run_dh_test_vectors(void);
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_DH_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_list.h b/drivers/usb/host/dwc_common_port/dwc_list.h
+new file mode 100644
+index 000000000000..4ce560df0cae
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_list.h
+@@ -0,0 +1,594 @@
++/* $OpenBSD: queue.h,v 1.26 2004/05/04 16:59:32 grange Exp $ */
++/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
++
++/*
++ * Copyright (c) 1991, 1993
++ * The Regents of the University of California. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. Neither the name of the University nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * @(#)queue.h 8.5 (Berkeley) 8/20/94
++ */
++
++#ifndef _DWC_LIST_H_
++#define _DWC_LIST_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file defines linked list operations. It is derived from BSD with
++ * only the MACRO names being prefixed with DWC_. This is because a few of
++ * these names conflict with those on Linux. For documentation on use, see the
++ * inline comments in the source code. The original license for this source
++ * code applies and is preserved in the dwc_list.h source file.
++ */
++
++/*
++ * This file defines five types of data structures: singly-linked lists,
++ * lists, simple queues, tail queues, and circular queues.
++ *
++ *
++ * A singly-linked list is headed by a single forward pointer. The elements
++ * are singly linked for minimum space and pointer manipulation overhead at
++ * the expense of O(n) removal for arbitrary elements. New elements can be
++ * added to the list after an existing element or at the head of the list.
++ * Elements being removed from the head of the list should use the explicit
++ * macro for this purpose for optimum efficiency. A singly-linked list may
++ * only be traversed in the forward direction. Singly-linked lists are ideal
++ * for applications with large datasets and few or no removals or for
++ * implementing a LIFO queue.
++ *
++ * A list is headed by a single forward pointer (or an array of forward
++ * pointers for a hash table header). The elements are doubly linked
++ * so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before
++ * or after an existing element or at the head of the list. A list
++ * may only be traversed in the forward direction.
++ *
++ * A simple queue is headed by a pair of pointers, one the head of the
++ * list and the other to the tail of the list. The elements are singly
++ * linked to save space, so elements can only be removed from the
++ * head of the list. New elements can be added to the list before or after
++ * an existing element, at the head of the list, or at the end of the
++ * list. A simple queue may only be traversed in the forward direction.
++ *
++ * A tail queue is headed by a pair of pointers, one to the head of the
++ * list and the other to the tail of the list. The elements are doubly
++ * linked so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before or
++ * after an existing element, at the head of the list, or at the end of
++ * the list. A tail queue may be traversed in either direction.
++ *
++ * A circle queue is headed by a pair of pointers, one to the head of the
++ * list and the other to the tail of the list. The elements are doubly
++ * linked so that an arbitrary element can be removed without a need to
++ * traverse the list. New elements can be added to the list before or after
++ * an existing element, at the head of the list, or at the end of the list.
++ * A circle queue may be traversed in either direction, but has a more
++ * complex end of list detection.
++ *
++ * For details on the use of these macros, see the queue(3) manual page.
++ */
++
++/*
++ * Double-linked List.
++ */
++
++typedef struct dwc_list_link {
++ struct dwc_list_link *next;
++ struct dwc_list_link *prev;
++} dwc_list_link_t;
++
++#define DWC_LIST_INIT(link) do { \
++ (link)->next = (link); \
++ (link)->prev = (link); \
++} while (0)
++
++#define DWC_LIST_FIRST(link) ((link)->next)
++#define DWC_LIST_LAST(link) ((link)->prev)
++#define DWC_LIST_END(link) (link)
++#define DWC_LIST_NEXT(link) ((link)->next)
++#define DWC_LIST_PREV(link) ((link)->prev)
++#define DWC_LIST_EMPTY(link) \
++ (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
++#define DWC_LIST_ENTRY(link, type, field) \
++ (type *)((uint8_t *)(link) - (size_t)(&((type *)0)->field))
++
++#if 0
++#define DWC_LIST_INSERT_HEAD(list, link) do { \
++ (link)->next = (list)->next; \
++ (link)->prev = (list); \
++ (list)->next->prev = (link); \
++ (list)->next = (link); \
++} while (0)
++
++#define DWC_LIST_INSERT_TAIL(list, link) do { \
++ (link)->next = (list); \
++ (link)->prev = (list)->prev; \
++ (list)->prev->next = (link); \
++ (list)->prev = (link); \
++} while (0)
++#else
++#define DWC_LIST_INSERT_HEAD(list, link) do { \
++ dwc_list_link_t *__next__ = (list)->next; \
++ __next__->prev = (link); \
++ (link)->next = __next__; \
++ (link)->prev = (list); \
++ (list)->next = (link); \
++} while (0)
++
++#define DWC_LIST_INSERT_TAIL(list, link) do { \
++ dwc_list_link_t *__prev__ = (list)->prev; \
++ (list)->prev = (link); \
++ (link)->next = (list); \
++ (link)->prev = __prev__; \
++ __prev__->next = (link); \
++} while (0)
++#endif
++
++#if 0
++static inline void __list_add(struct list_head *new,
++ struct list_head *prev,
++ struct list_head *next)
++{
++ next->prev = new;
++ new->next = next;
++ new->prev = prev;
++ prev->next = new;
++}
++
++static inline void list_add(struct list_head *new, struct list_head *head)
++{
++ __list_add(new, head, head->next);
++}
++
++static inline void list_add_tail(struct list_head *new, struct list_head *head)
++{
++ __list_add(new, head->prev, head);
++}
++
++static inline void __list_del(struct list_head * prev, struct list_head * next)
++{
++ next->prev = prev;
++ prev->next = next;
++}
++
++static inline void list_del(struct list_head *entry)
++{
++ __list_del(entry->prev, entry->next);
++ entry->next = LIST_POISON1;
++ entry->prev = LIST_POISON2;
++}
++#endif
++
++#define DWC_LIST_REMOVE(link) do { \
++ (link)->next->prev = (link)->prev; \
++ (link)->prev->next = (link)->next; \
++} while (0)
++
++#define DWC_LIST_REMOVE_INIT(link) do { \
++ DWC_LIST_REMOVE(link); \
++ DWC_LIST_INIT(link); \
++} while (0)
++
++#define DWC_LIST_MOVE_HEAD(list, link) do { \
++ DWC_LIST_REMOVE(link); \
++ DWC_LIST_INSERT_HEAD(list, link); \
++} while (0)
++
++#define DWC_LIST_MOVE_TAIL(list, link) do { \
++ DWC_LIST_REMOVE(link); \
++ DWC_LIST_INSERT_TAIL(list, link); \
++} while (0)
++
++#define DWC_LIST_FOREACH(var, list) \
++ for((var) = DWC_LIST_FIRST(list); \
++ (var) != DWC_LIST_END(list); \
++ (var) = DWC_LIST_NEXT(var))
++
++#define DWC_LIST_FOREACH_SAFE(var, var2, list) \
++ for((var) = DWC_LIST_FIRST(list), (var2) = DWC_LIST_NEXT(var); \
++ (var) != DWC_LIST_END(list); \
++ (var) = (var2), (var2) = DWC_LIST_NEXT(var2))
++
++#define DWC_LIST_FOREACH_REVERSE(var, list) \
++ for((var) = DWC_LIST_LAST(list); \
++ (var) != DWC_LIST_END(list); \
++ (var) = DWC_LIST_PREV(var))
++
++/*
++ * Singly-linked List definitions.
++ */
++#define DWC_SLIST_HEAD(name, type) \
++struct name { \
++ struct type *slh_first; /* first element */ \
++}
++
++#define DWC_SLIST_HEAD_INITIALIZER(head) \
++ { NULL }
++
++#define DWC_SLIST_ENTRY(type) \
++struct { \
++ struct type *sle_next; /* next element */ \
++}
++
++/*
++ * Singly-linked List access methods.
++ */
++#define DWC_SLIST_FIRST(head) ((head)->slh_first)
++#define DWC_SLIST_END(head) NULL
++#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
++#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
++
++#define DWC_SLIST_FOREACH(var, head, field) \
++ for((var) = SLIST_FIRST(head); \
++ (var) != SLIST_END(head); \
++ (var) = SLIST_NEXT(var, field))
++
++#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \
++ for((varp) = &SLIST_FIRST((head)); \
++ ((var) = *(varp)) != SLIST_END(head); \
++ (varp) = &SLIST_NEXT((var), field))
++
++/*
++ * Singly-linked List functions.
++ */
++#define DWC_SLIST_INIT(head) { \
++ SLIST_FIRST(head) = SLIST_END(head); \
++}
++
++#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \
++ (elm)->field.sle_next = (slistelm)->field.sle_next; \
++ (slistelm)->field.sle_next = (elm); \
++} while (0)
++
++#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \
++ (elm)->field.sle_next = (head)->slh_first; \
++ (head)->slh_first = (elm); \
++} while (0)
++
++#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \
++ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
++} while (0)
++
++#define DWC_SLIST_REMOVE_HEAD(head, field) do { \
++ (head)->slh_first = (head)->slh_first->field.sle_next; \
++} while (0)
++
++#define DWC_SLIST_REMOVE(head, elm, type, field) do { \
++ if ((head)->slh_first == (elm)) { \
++ SLIST_REMOVE_HEAD((head), field); \
++ } \
++ else { \
++ struct type *curelm = (head)->slh_first; \
++ while( curelm->field.sle_next != (elm) ) \
++ curelm = curelm->field.sle_next; \
++ curelm->field.sle_next = \
++ curelm->field.sle_next->field.sle_next; \
++ } \
++} while (0)
++
++/*
++ * Simple queue definitions.
++ */
++#define DWC_SIMPLEQ_HEAD(name, type) \
++struct name { \
++ struct type *sqh_first; /* first element */ \
++ struct type **sqh_last; /* addr of last next element */ \
++}
++
++#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \
++ { NULL, &(head).sqh_first }
++
++#define DWC_SIMPLEQ_ENTRY(type) \
++struct { \
++ struct type *sqe_next; /* next element */ \
++}
++
++/*
++ * Simple queue access methods.
++ */
++#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first)
++#define DWC_SIMPLEQ_END(head) NULL
++#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
++#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
++
++#define DWC_SIMPLEQ_FOREACH(var, head, field) \
++ for((var) = SIMPLEQ_FIRST(head); \
++ (var) != SIMPLEQ_END(head); \
++ (var) = SIMPLEQ_NEXT(var, field))
++
++/*
++ * Simple queue functions.
++ */
++#define DWC_SIMPLEQ_INIT(head) do { \
++ (head)->sqh_first = NULL; \
++ (head)->sqh_last = &(head)->sqh_first; \
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
++ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
++ (head)->sqh_last = &(elm)->field.sqe_next; \
++ (head)->sqh_first = (elm); \
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
++ (elm)->field.sqe_next = NULL; \
++ *(head)->sqh_last = (elm); \
++ (head)->sqh_last = &(elm)->field.sqe_next; \
++} while (0)
++
++#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
++ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
++ (head)->sqh_last = &(elm)->field.sqe_next; \
++ (listelm)->field.sqe_next = (elm); \
++} while (0)
++
++#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \
++ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
++ (head)->sqh_last = &(head)->sqh_first; \
++} while (0)
++
++/*
++ * Tail queue definitions.
++ */
++#define DWC_TAILQ_HEAD(name, type) \
++struct name { \
++ struct type *tqh_first; /* first element */ \
++ struct type **tqh_last; /* addr of last next element */ \
++}
++
++#define DWC_TAILQ_HEAD_INITIALIZER(head) \
++ { NULL, &(head).tqh_first }
++
++#define DWC_TAILQ_ENTRY(type) \
++struct { \
++ struct type *tqe_next; /* next element */ \
++ struct type **tqe_prev; /* address of previous next element */ \
++}
++
++/*
++ * tail queue access methods
++ */
++#define DWC_TAILQ_FIRST(head) ((head)->tqh_first)
++#define DWC_TAILQ_END(head) NULL
++#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
++#define DWC_TAILQ_LAST(head, headname) \
++ (*(((struct headname *)((head)->tqh_last))->tqh_last))
++/* XXX */
++#define DWC_TAILQ_PREV(elm, headname, field) \
++ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
++#define DWC_TAILQ_EMPTY(head) \
++ (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))
++
++#define DWC_TAILQ_FOREACH(var, head, field) \
++ for ((var) = DWC_TAILQ_FIRST(head); \
++ (var) != DWC_TAILQ_END(head); \
++ (var) = DWC_TAILQ_NEXT(var, field))
++
++#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
++ for ((var) = DWC_TAILQ_LAST(head, headname); \
++ (var) != DWC_TAILQ_END(head); \
++ (var) = DWC_TAILQ_PREV(var, headname, field))
++
++/*
++ * Tail queue functions.
++ */
++#define DWC_TAILQ_INIT(head) do { \
++ (head)->tqh_first = NULL; \
++ (head)->tqh_last = &(head)->tqh_first; \
++} while (0)
++
++#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \
++ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
++ (head)->tqh_first->field.tqe_prev = \
++ &(elm)->field.tqe_next; \
++ else \
++ (head)->tqh_last = &(elm)->field.tqe_next; \
++ (head)->tqh_first = (elm); \
++ (elm)->field.tqe_prev = &(head)->tqh_first; \
++} while (0)
++
++#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \
++ (elm)->field.tqe_next = NULL; \
++ (elm)->field.tqe_prev = (head)->tqh_last; \
++ *(head)->tqh_last = (elm); \
++ (head)->tqh_last = &(elm)->field.tqe_next; \
++} while (0)
++
++#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
++ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
++ (elm)->field.tqe_next->field.tqe_prev = \
++ &(elm)->field.tqe_next; \
++ else \
++ (head)->tqh_last = &(elm)->field.tqe_next; \
++ (listelm)->field.tqe_next = (elm); \
++ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
++} while (0)
++
++#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
++ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
++ (elm)->field.tqe_next = (listelm); \
++ *(listelm)->field.tqe_prev = (elm); \
++ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
++} while (0)
++
++#define DWC_TAILQ_REMOVE(head, elm, field) do { \
++ if (((elm)->field.tqe_next) != NULL) \
++ (elm)->field.tqe_next->field.tqe_prev = \
++ (elm)->field.tqe_prev; \
++ else \
++ (head)->tqh_last = (elm)->field.tqe_prev; \
++ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
++} while (0)
++
++#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \
++ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
++ (elm2)->field.tqe_next->field.tqe_prev = \
++ &(elm2)->field.tqe_next; \
++ else \
++ (head)->tqh_last = &(elm2)->field.tqe_next; \
++ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
++ *(elm2)->field.tqe_prev = (elm2); \
++} while (0)
++
++/*
++ * Circular queue definitions.
++ */
++#define DWC_CIRCLEQ_HEAD(name, type) \
++struct name { \
++ struct type *cqh_first; /* first element */ \
++ struct type *cqh_last; /* last element */ \
++}
++
++#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \
++ { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
++
++#define DWC_CIRCLEQ_ENTRY(type) \
++struct { \
++ struct type *cqe_next; /* next element */ \
++ struct type *cqe_prev; /* previous element */ \
++}
++
++/*
++ * Circular queue access methods
++ */
++#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first)
++#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last)
++#define DWC_CIRCLEQ_END(head) ((void *)(head))
++#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
++#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
++#define DWC_CIRCLEQ_EMPTY(head) \
++ (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
++
++#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
++
++#define DWC_CIRCLEQ_FOREACH(var, head, field) \
++ for((var) = DWC_CIRCLEQ_FIRST(head); \
++ (var) != DWC_CIRCLEQ_END(head); \
++ (var) = DWC_CIRCLEQ_NEXT(var, field))
++
++#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \
++ for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \
++ (var) != DWC_CIRCLEQ_END(head); \
++ (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
++
++#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \
++ for((var) = DWC_CIRCLEQ_LAST(head); \
++ (var) != DWC_CIRCLEQ_END(head); \
++ (var) = DWC_CIRCLEQ_PREV(var, field))
++
++/*
++ * Circular queue functions.
++ */
++#define DWC_CIRCLEQ_INIT(head) do { \
++ (head)->cqh_first = DWC_CIRCLEQ_END(head); \
++ (head)->cqh_last = DWC_CIRCLEQ_END(head); \
++} while (0)
++
++#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \
++ (elm)->field.cqe_next = NULL; \
++ (elm)->field.cqe_prev = NULL; \
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
++ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
++ (elm)->field.cqe_prev = (listelm); \
++ if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
++ (head)->cqh_last = (elm); \
++ else \
++ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
++ (listelm)->field.cqe_next = (elm); \
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
++ (elm)->field.cqe_next = (listelm); \
++ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
++ if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
++ (head)->cqh_first = (elm); \
++ else \
++ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
++ (listelm)->field.cqe_prev = (elm); \
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
++ (elm)->field.cqe_next = (head)->cqh_first; \
++ (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \
++ if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \
++ (head)->cqh_last = (elm); \
++ else \
++ (head)->cqh_first->field.cqe_prev = (elm); \
++ (head)->cqh_first = (elm); \
++} while (0)
++
++#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
++ (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \
++ (elm)->field.cqe_prev = (head)->cqh_last; \
++ if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \
++ (head)->cqh_first = (elm); \
++ else \
++ (head)->cqh_last->field.cqe_next = (elm); \
++ (head)->cqh_last = (elm); \
++} while (0)
++
++#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \
++ if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \
++ (head)->cqh_last = (elm)->field.cqe_prev; \
++ else \
++ (elm)->field.cqe_next->field.cqe_prev = \
++ (elm)->field.cqe_prev; \
++ if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \
++ (head)->cqh_first = (elm)->field.cqe_next; \
++ else \
++ (elm)->field.cqe_prev->field.cqe_next = \
++ (elm)->field.cqe_next; \
++} while (0)
++
++#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \
++ DWC_CIRCLEQ_REMOVE(head, elm, field); \
++ DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
++} while (0)
++
++#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
++ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
++ DWC_CIRCLEQ_END(head)) \
++ (head).cqh_last = (elm2); \
++ else \
++ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
++ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
++ DWC_CIRCLEQ_END(head)) \
++ (head).cqh_first = (elm2); \
++ else \
++ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
++} while (0)
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_LIST_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_mem.c b/drivers/usb/host/dwc_common_port/dwc_mem.c
+new file mode 100644
+index 000000000000..ad645ff1ba7e
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_mem.c
+@@ -0,0 +1,245 @@
++/* Memory Debugging */
++#ifdef DWC_DEBUG_MEMORY
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++struct allocation {
++ void *addr;
++ void *ctx;
++ char *func;
++ int line;
++ uint32_t size;
++ int dma;
++ DWC_CIRCLEQ_ENTRY(allocation) entry;
++};
++
++DWC_CIRCLEQ_HEAD(allocation_queue, allocation);
++
++struct allocation_manager {
++ void *mem_ctx;
++ struct allocation_queue allocations;
++
++ /* statistics */
++ int num;
++ int num_freed;
++ int num_active;
++ uint32_t total;
++ uint32_t cur;
++ uint32_t max;
++};
++
++static struct allocation_manager *manager = NULL;
++
++static int add_allocation(void *ctx, uint32_t size, char const *func, int line, void *addr,
++ int dma)
++{
++ struct allocation *a;
++
++ DWC_ASSERT(manager != NULL, "manager not allocated");
++
++ a = __DWC_ALLOC_ATOMIC(manager->mem_ctx, sizeof(*a));
++ if (!a) {
++ return -DWC_E_NO_MEMORY;
++ }
++
++ a->func = __DWC_ALLOC_ATOMIC(manager->mem_ctx, DWC_STRLEN(func) + 1);
++ if (!a->func) {
++ __DWC_FREE(manager->mem_ctx, a);
++ return -DWC_E_NO_MEMORY;
++ }
++
++ DWC_MEMCPY(a->func, func, DWC_STRLEN(func) + 1);
++ a->addr = addr;
++ a->ctx = ctx;
++ a->line = line;
++ a->size = size;
++ a->dma = dma;
++ DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry);
++
++ /* Update stats */
++ manager->num++;
++ manager->num_active++;
++ manager->total += size;
++ manager->cur += size;
++
++ if (manager->max < manager->cur) {
++ manager->max = manager->cur;
++ }
++
++ return 0;
++}
++
++static struct allocation *find_allocation(void *ctx, void *addr)
++{
++ struct allocation *a;
++
++ DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
++ if (a->ctx == ctx && a->addr == addr) {
++ return a;
++ }
++ }
++
++ return NULL;
++}
++
++static void free_allocation(void *ctx, void *addr, char const *func, int line)
++{
++ struct allocation *a = find_allocation(ctx, addr);
++
++ if (!a) {
++ DWC_ASSERT(0,
++ "Free of address %p that was never allocated or already freed %s:%d",
++ addr, func, line);
++ return;
++ }
++
++ DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry);
++
++ manager->num_active--;
++ manager->num_freed++;
++ manager->cur -= a->size;
++ __DWC_FREE(manager->mem_ctx, a->func);
++ __DWC_FREE(manager->mem_ctx, a);
++}
++
++int dwc_memory_debug_start(void *mem_ctx)
++{
++ DWC_ASSERT(manager == NULL, "Memory debugging has already started\n");
++
++ if (manager) {
++ return -DWC_E_BUSY;
++ }
++
++ manager = __DWC_ALLOC(mem_ctx, sizeof(*manager));
++ if (!manager) {
++ return -DWC_E_NO_MEMORY;
++ }
++
++ DWC_CIRCLEQ_INIT(&manager->allocations);
++ manager->mem_ctx = mem_ctx;
++ manager->num = 0;
++ manager->num_freed = 0;
++ manager->num_active = 0;
++ manager->total = 0;
++ manager->cur = 0;
++ manager->max = 0;
++
++ return 0;
++}
++
++void dwc_memory_debug_stop(void)
++{
++ struct allocation *a;
++
++ dwc_memory_debug_report();
++
++ DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
++ DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line);
++ free_allocation(a->ctx, a->addr, NULL, -1);
++ }
++
++ __DWC_FREE(manager->mem_ctx, manager);
++}
++
++void dwc_memory_debug_report(void)
++{
++ struct allocation *a;
++
++ DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n");
++ DWC_PRINTF("Num Allocations = %d\n", manager->num);
++ DWC_PRINTF("Freed = %d\n", manager->num_freed);
++ DWC_PRINTF("Active = %d\n", manager->num_active);
++ DWC_PRINTF("Current Memory Used = %d\n", manager->cur);
++ DWC_PRINTF("Total Memory Used = %d\n", manager->total);
++ DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max);
++ DWC_PRINTF("Unfreed allocations:\n");
++
++ DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) {
++ DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n",
++ a->addr, a->size, a->func, a->line, a->dma);
++ }
++}
++
++/* The replacement functions */
++void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line)
++{
++ void *addr = __DWC_ALLOC(mem_ctx, size);
++
++ if (!addr) {
++ return NULL;
++ }
++
++ if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
++ __DWC_FREE(mem_ctx, addr);
++ return NULL;
++ }
++
++ return addr;
++}
++
++void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func,
++ int line)
++{
++ void *addr = __DWC_ALLOC_ATOMIC(mem_ctx, size);
++
++ if (!addr) {
++ return NULL;
++ }
++
++ if (add_allocation(mem_ctx, size, func, line, addr, 0)) {
++ __DWC_FREE(mem_ctx, addr);
++ return NULL;
++ }
++
++ return addr;
++}
++
++void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line)
++{
++ free_allocation(mem_ctx, addr, func, line);
++ __DWC_FREE(mem_ctx, addr);
++}
++
++void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
++ char const *func, int line)
++{
++ void *addr = __DWC_DMA_ALLOC(dma_ctx, size, dma_addr);
++
++ if (!addr) {
++ return NULL;
++ }
++
++ if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
++ __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
++ return NULL;
++ }
++
++ return addr;
++}
++
++void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size,
++ dwc_dma_t *dma_addr, char const *func, int line)
++{
++ void *addr = __DWC_DMA_ALLOC_ATOMIC(dma_ctx, size, dma_addr);
++
++ if (!addr) {
++ return NULL;
++ }
++
++ if (add_allocation(dma_ctx, size, func, line, addr, 1)) {
++ __DWC_DMA_FREE(dma_ctx, size, addr, *dma_addr);
++ return NULL;
++ }
++
++ return addr;
++}
++
++void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
++ dwc_dma_t dma_addr, char const *func, int line)
++{
++ free_allocation(dma_ctx, virt_addr, func, line);
++ __DWC_DMA_FREE(dma_ctx, size, virt_addr, dma_addr);
++}
++
++#endif /* DWC_DEBUG_MEMORY */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.c b/drivers/usb/host/dwc_common_port/dwc_modpow.c
+new file mode 100644
+index 000000000000..20045381208a
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c
+@@ -0,0 +1,636 @@
++/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows.
++ *
++ * PuTTY is copyright 1997-2007 Simon Tatham.
++ *
++ * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
++ * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
++ * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
++ * Kuhn, and CORE SDI S.A.
++ *
++ * Permission is hereby granted, free of charge, to any person
++ * obtaining a copy of this software and associated documentation files
++ * (the "Software"), to deal in the Software without restriction,
++ * including without limitation the rights to use, copy, modify, merge,
++ * publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so,
++ * subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be
++ * included in all copies or substantial portions of the Software.
++
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
++ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
++ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ */
++#ifdef DWC_CRYPTOLIB
++
++#ifndef CONFIG_MACH_IPMATE
++
++#include "dwc_modpow.h"
++
++#define BIGNUM_INT_MASK 0xFFFFFFFFUL
++#define BIGNUM_TOP_BIT 0x80000000UL
++#define BIGNUM_INT_BITS 32
++
++
++static void *snmalloc(void *mem_ctx, size_t n, size_t size)
++{
++ void *p;
++ size *= n;
++ if (size == 0) size = 1;
++ p = dwc_alloc(mem_ctx, size);
++ return p;
++}
++
++#define snewn(ctx, n, type) ((type *)snmalloc((ctx), (n), sizeof(type)))
++#define sfree dwc_free
++
++/*
++ * Usage notes:
++ * * Do not call the DIVMOD_WORD macro with expressions such as array
++ * subscripts, as some implementations object to this (see below).
++ * * Note that none of the division methods below will cope if the
++ * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
++ * to avoid this case.
++ * If this condition occurs, in the case of the x86 DIV instruction,
++ * an overflow exception will occur, which (according to a correspondent)
++ * will manifest on Windows as something like
++ * 0xC0000095: Integer overflow
++ * The C variant won't give the right answer, either.
++ */
++
++#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
++
++#if defined __GNUC__ && defined __i386__
++#define DIVMOD_WORD(q, r, hi, lo, w) \
++ __asm__("div %2" : \
++ "=d" (r), "=a" (q) : \
++ "r" (w), "d" (hi), "a" (lo))
++#else
++#define DIVMOD_WORD(q, r, hi, lo, w) do { \
++ BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
++ q = n / w; \
++ r = n % w; \
++} while (0)
++#endif
++
++// q = n / w;
++// r = n % w;
++
++#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
++
++#define BIGNUM_INTERNAL
++
++static Bignum newbn(void *mem_ctx, int length)
++{
++ Bignum b = snewn(mem_ctx, length + 1, BignumInt);
++ //if (!b)
++ //abort(); /* FIXME */
++ DWC_MEMSET(b, 0, (length + 1) * sizeof(*b));
++ b[0] = length;
++ return b;
++}
++
++void freebn(void *mem_ctx, Bignum b)
++{
++ /*
++ * Burn the evidence, just in case.
++ */
++ DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1));
++ sfree(mem_ctx, b);
++}
++
++/*
++ * Compute c = a * b.
++ * Input is in the first len words of a and b.
++ * Result is returned in the first 2*len words of c.
++ */
++static void internal_mul(BignumInt *a, BignumInt *b,
++ BignumInt *c, int len)
++{
++ int i, j;
++ BignumDblInt t;
++
++ for (j = 0; j < 2 * len; j++)
++ c[j] = 0;
++
++ for (i = len - 1; i >= 0; i--) {
++ t = 0;
++ for (j = len - 1; j >= 0; j--) {
++ t += MUL_WORD(a[i], (BignumDblInt) b[j]);
++ t += (BignumDblInt) c[i + j + 1];
++ c[i + j + 1] = (BignumInt) t;
++ t = t >> BIGNUM_INT_BITS;
++ }
++ c[i] = (BignumInt) t;
++ }
++}
++
++static void internal_add_shifted(BignumInt *number,
++ unsigned n, int shift)
++{
++ int word = 1 + (shift / BIGNUM_INT_BITS);
++ int bshift = shift % BIGNUM_INT_BITS;
++ BignumDblInt addend;
++
++ addend = (BignumDblInt)n << bshift;
++
++ while (addend) {
++ addend += number[word];
++ number[word] = (BignumInt) addend & BIGNUM_INT_MASK;
++ addend >>= BIGNUM_INT_BITS;
++ word++;
++ }
++}
++
++/*
++ * Compute a = a % m.
++ * Input in first alen words of a and first mlen words of m.
++ * Output in first alen words of a
++ * (of which first alen-mlen words will be zero).
++ * The MSW of m MUST have its high bit set.
++ * Quotient is accumulated in the `quotient' array, which is a Bignum
++ * rather than the internal bigendian format. Quotient parts are shifted
++ * left by `qshift' before adding into quot.
++ */
++static void internal_mod(BignumInt *a, int alen,
++ BignumInt *m, int mlen,
++ BignumInt *quot, int qshift)
++{
++ BignumInt m0, m1;
++ unsigned int h;
++ int i, k;
++
++ m0 = m[0];
++ if (mlen > 1)
++ m1 = m[1];
++ else
++ m1 = 0;
++
++ for (i = 0; i <= alen - mlen; i++) {
++ BignumDblInt t;
++ unsigned int q, r, c, ai1;
++
++ if (i == 0) {
++ h = 0;
++ } else {
++ h = a[i - 1];
++ a[i - 1] = 0;
++ }
++
++ if (i == alen - 1)
++ ai1 = 0;
++ else
++ ai1 = a[i + 1];
++
++ /* Find q = h:a[i] / m0 */
++ if (h >= m0) {
++ /*
++ * Special case.
++ *
++ * To illustrate it, suppose a BignumInt is 8 bits, and
++ * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then
++ * our initial division will be 0xA123 / 0xA1, which
++ * will give a quotient of 0x100 and a divide overflow.
++ * However, the invariants in this division algorithm
++ * are not violated, since the full number A1:23:... is
++ * _less_ than the quotient prefix A1:B2:... and so the
++ * following correction loop would have sorted it out.
++ *
++ * In this situation we set q to be the largest
++ * quotient we _can_ stomach (0xFF, of course).
++ */
++ q = BIGNUM_INT_MASK;
++ } else {
++ /* Macro doesn't want an array subscript expression passed
++ * into it (see definition), so use a temporary. */
++ BignumInt tmplo = a[i];
++ DIVMOD_WORD(q, r, h, tmplo, m0);
++
++ /* Refine our estimate of q by looking at
++ h:a[i]:a[i+1] / m0:m1 */
++ t = MUL_WORD(m1, q);
++ if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) {
++ q--;
++ t -= m1;
++ r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */
++ if (r >= (BignumDblInt) m0 &&
++ t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--;
++ }
++ }
++
++ /* Subtract q * m from a[i...] */
++ c = 0;
++ for (k = mlen - 1; k >= 0; k--) {
++ t = MUL_WORD(q, m[k]);
++ t += c;
++ c = (unsigned)(t >> BIGNUM_INT_BITS);
++ if ((BignumInt) t > a[i + k])
++ c++;
++ a[i + k] -= (BignumInt) t;
++ }
++
++ /* Add back m in case of borrow */
++ if (c != h) {
++ t = 0;
++ for (k = mlen - 1; k >= 0; k--) {
++ t += m[k];
++ t += a[i + k];
++ a[i + k] = (BignumInt) t;
++ t = t >> BIGNUM_INT_BITS;
++ }
++ q--;
++ }
++ if (quot)
++ internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i));
++ }
++}
++
++/*
++ * Compute p % mod.
++ * The most significant word of mod MUST be non-zero.
++ * We assume that the result array is the same size as the mod array.
++ * We optionally write out a quotient if `quotient' is non-NULL.
++ * We can avoid writing out the result if `result' is NULL.
++ */
++void bigdivmod(void *mem_ctx, Bignum p, Bignum mod, Bignum result, Bignum quotient)
++{
++ BignumInt *n, *m;
++ int mshift;
++ int plen, mlen, i, j;
++
++ /* Allocate m of size mlen, copy mod to m */
++ /* We use big endian internally */
++ mlen = mod[0];
++ m = snewn(mem_ctx, mlen, BignumInt);
++ //if (!m)
++ //abort(); /* FIXME */
++ for (j = 0; j < mlen; j++)
++ m[j] = mod[mod[0] - j];
++
++ /* Shift m left to make msb bit set */
++ for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++)
++ if ((m[0] << mshift) & BIGNUM_TOP_BIT)
++ break;
++ if (mshift) {
++ for (i = 0; i < mlen - 1; i++)
++ m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift));
++ m[mlen - 1] = m[mlen - 1] << mshift;
++ }
++
++ plen = p[0];
++ /* Ensure plen > mlen */
++ if (plen <= mlen)
++ plen = mlen + 1;
++
++ /* Allocate n of size plen, copy p to n */
++ n = snewn(mem_ctx, plen, BignumInt);
++ //if (!n)
++ //abort(); /* FIXME */
++ for (j = 0; j < plen; j++)
++ n[j] = 0;
++ for (j = 1; j <= (int)p[0]; j++)
++ n[plen - j] = p[j];
++
++ /* Main computation */
++ internal_mod(n, plen, m, mlen, quotient, mshift);
++
++ /* Fixup result in case the modulus was shifted */
++ if (mshift) {
++ for (i = plen - mlen - 1; i < plen - 1; i++)
++ n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift));
++ n[plen - 1] = n[plen - 1] << mshift;
++ internal_mod(n, plen, m, mlen, quotient, 0);
++ for (i = plen - 1; i >= plen - mlen; i--)
++ n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift));
++ }
++
++ /* Copy result to buffer */
++ if (result) {
++ for (i = 1; i <= (int)result[0]; i++) {
++ int j = plen - i;
++ result[i] = j >= 0 ? n[j] : 0;
++ }
++ }
++
++ /* Free temporary arrays */
++ for (i = 0; i < mlen; i++)
++ m[i] = 0;
++ sfree(mem_ctx, m);
++ for (i = 0; i < plen; i++)
++ n[i] = 0;
++ sfree(mem_ctx, n);
++}
++
++/*
++ * Simple remainder.
++ */
++Bignum bigmod(void *mem_ctx, Bignum a, Bignum b)
++{
++ Bignum r = newbn(mem_ctx, b[0]);
++ bigdivmod(mem_ctx, a, b, r, NULL);
++ return r;
++}
++
++/*
++ * Compute (base ^ exp) % mod.
++ */
++Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod)
++{
++ BignumInt *a, *b, *n, *m;
++ int mshift;
++ int mlen, i, j;
++ Bignum base, result;
++
++ /*
++ * The most significant word of mod needs to be non-zero. It
++ * should already be, but let's make sure.
++ */
++ //assert(mod[mod[0]] != 0);
++
++ /*
++ * Make sure the base is smaller than the modulus, by reducing
++ * it modulo the modulus if not.
++ */
++ base = bigmod(mem_ctx, base_in, mod);
++
++ /* Allocate m of size mlen, copy mod to m */
++ /* We use big endian internally */
++ mlen = mod[0];
++ m = snewn(mem_ctx, mlen, BignumInt);
++ //if (!m)
++ //abort(); /* FIXME */
++ for (j = 0; j < mlen; j++)
++ m[j] = mod[mod[0] - j];
++
++ /* Shift m left to make msb bit set */
++ for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++)
++ if ((m[0] << mshift) & BIGNUM_TOP_BIT)
++ break;
++ if (mshift) {
++ for (i = 0; i < mlen - 1; i++)
++ m[i] =
++ (m[i] << mshift) | (m[i + 1] >>
++ (BIGNUM_INT_BITS - mshift));
++ m[mlen - 1] = m[mlen - 1] << mshift;
++ }
++
++ /* Allocate n of size mlen, copy base to n */
++ n = snewn(mem_ctx, mlen, BignumInt);
++ //if (!n)
++ //abort(); /* FIXME */
++ i = mlen - base[0];
++ for (j = 0; j < i; j++)
++ n[j] = 0;
++ for (j = 0; j < base[0]; j++)
++ n[i + j] = base[base[0] - j];
++
++ /* Allocate a and b of size 2*mlen. Set a = 1 */
++ a = snewn(mem_ctx, 2 * mlen, BignumInt);
++ //if (!a)
++ //abort(); /* FIXME */
++ b = snewn(mem_ctx, 2 * mlen, BignumInt);
++ //if (!b)
++ //abort(); /* FIXME */
++ for (i = 0; i < 2 * mlen; i++)
++ a[i] = 0;
++ a[2 * mlen - 1] = 1;
++
++ /* Skip leading zero bits of exp. */
++ i = 0;
++ j = BIGNUM_INT_BITS - 1;
++ while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
++ j--;
++ if (j < 0) {
++ i++;
++ j = BIGNUM_INT_BITS - 1;
++ }
++ }
++
++ /* Main computation */
++ while (i < exp[0]) {
++ while (j >= 0) {
++ internal_mul(a + mlen, a + mlen, b, mlen);
++ internal_mod(b, mlen * 2, m, mlen, NULL, 0);
++ if ((exp[exp[0] - i] & (1 << j)) != 0) {
++ internal_mul(b + mlen, n, a, mlen);
++ internal_mod(a, mlen * 2, m, mlen, NULL, 0);
++ } else {
++ BignumInt *t;
++ t = a;
++ a = b;
++ b = t;
++ }
++ j--;
++ }
++ i++;
++ j = BIGNUM_INT_BITS - 1;
++ }
++
++ /* Fixup result in case the modulus was shifted */
++ if (mshift) {
++ for (i = mlen - 1; i < 2 * mlen - 1; i++)
++ a[i] =
++ (a[i] << mshift) | (a[i + 1] >>
++ (BIGNUM_INT_BITS - mshift));
++ a[2 * mlen - 1] = a[2 * mlen - 1] << mshift;
++ internal_mod(a, mlen * 2, m, mlen, NULL, 0);
++ for (i = 2 * mlen - 1; i >= mlen; i--)
++ a[i] =
++ (a[i] >> mshift) | (a[i - 1] <<
++ (BIGNUM_INT_BITS - mshift));
++ }
++
++ /* Copy result to buffer */
++ result = newbn(mem_ctx, mod[0]);
++ for (i = 0; i < mlen; i++)
++ result[result[0] - i] = a[i + mlen];
++ while (result[0] > 1 && result[result[0]] == 0)
++ result[0]--;
++
++ /* Free temporary arrays */
++ for (i = 0; i < 2 * mlen; i++)
++ a[i] = 0;
++ sfree(mem_ctx, a);
++ for (i = 0; i < 2 * mlen; i++)
++ b[i] = 0;
++ sfree(mem_ctx, b);
++ for (i = 0; i < mlen; i++)
++ m[i] = 0;
++ sfree(mem_ctx, m);
++ for (i = 0; i < mlen; i++)
++ n[i] = 0;
++ sfree(mem_ctx, n);
++
++ freebn(mem_ctx, base);
++
++ return result;
++}
++
++
++#ifdef UNITTEST
++
++static __u32 dh_p[] = {
++ 96,
++ 0xFFFFFFFF,
++ 0xFFFFFFFF,
++ 0xA93AD2CA,
++ 0x4B82D120,
++ 0xE0FD108E,
++ 0x43DB5BFC,
++ 0x74E5AB31,
++ 0x08E24FA0,
++ 0xBAD946E2,
++ 0x770988C0,
++ 0x7A615D6C,
++ 0xBBE11757,
++ 0x177B200C,
++ 0x521F2B18,
++ 0x3EC86A64,
++ 0xD8760273,
++ 0xD98A0864,
++ 0xF12FFA06,
++ 0x1AD2EE6B,
++ 0xCEE3D226,
++ 0x4A25619D,
++ 0x1E8C94E0,
++ 0xDB0933D7,
++ 0xABF5AE8C,
++ 0xA6E1E4C7,
++ 0xB3970F85,
++ 0x5D060C7D,
++ 0x8AEA7157,
++ 0x58DBEF0A,
++ 0xECFB8504,
++ 0xDF1CBA64,
++ 0xA85521AB,
++ 0x04507A33,
++ 0xAD33170D,
++ 0x8AAAC42D,
++ 0x15728E5A,
++ 0x98FA0510,
++ 0x15D22618,
++ 0xEA956AE5,
++ 0x3995497C,
++ 0x95581718,
++ 0xDE2BCBF6,
++ 0x6F4C52C9,
++ 0xB5C55DF0,
++ 0xEC07A28F,
++ 0x9B2783A2,
++ 0x180E8603,
++ 0xE39E772C,
++ 0x2E36CE3B,
++ 0x32905E46,
++ 0xCA18217C,
++ 0xF1746C08,
++ 0x4ABC9804,
++ 0x670C354E,
++ 0x7096966D,
++ 0x9ED52907,
++ 0x208552BB,
++ 0x1C62F356,
++ 0xDCA3AD96,
++ 0x83655D23,
++ 0xFD24CF5F,
++ 0x69163FA8,
++ 0x1C55D39A,
++ 0x98DA4836,
++ 0xA163BF05,
++ 0xC2007CB8,
++ 0xECE45B3D,
++ 0x49286651,
++ 0x7C4B1FE6,
++ 0xAE9F2411,
++ 0x5A899FA5,
++ 0xEE386BFB,
++ 0xF406B7ED,
++ 0x0BFF5CB6,
++ 0xA637ED6B,
++ 0xF44C42E9,
++ 0x625E7EC6,
++ 0xE485B576,
++ 0x6D51C245,
++ 0x4FE1356D,
++ 0xF25F1437,
++ 0x302B0A6D,
++ 0xCD3A431B,
++ 0xEF9519B3,
++ 0x8E3404DD,
++ 0x514A0879,
++ 0x3B139B22,
++ 0x020BBEA6,
++ 0x8A67CC74,
++ 0x29024E08,
++ 0x80DC1CD1,
++ 0xC4C6628B,
++ 0x2168C234,
++ 0xC90FDAA2,
++ 0xFFFFFFFF,
++ 0xFFFFFFFF,
++};
++
++static __u32 dh_a[] = {
++ 8,
++ 0xdf367516,
++ 0x86459caa,
++ 0xe2d459a4,
++ 0xd910dae0,
++ 0x8a8b5e37,
++ 0x67ab31c6,
++ 0xf0b55ea9,
++ 0x440051d6,
++};
++
++static __u32 dh_b[] = {
++ 8,
++ 0xded92656,
++ 0xe07a048a,
++ 0x6fa452cd,
++ 0x2df89d30,
++ 0xc75f1b0f,
++ 0x8ce3578f,
++ 0x7980a324,
++ 0x5daec786,
++};
++
++static __u32 dh_g[] = {
++ 1,
++ 2,
++};
++
++int main(void)
++{
++ int i;
++ __u32 *k;
++ k = dwc_modpow(NULL, dh_g, dh_a, dh_p);
++
++ printf("\n\n");
++ for (i=0; i<k[0]; i++) {
++ __u32 word32 = k[k[0] - i];
++ __u16 l = word32 & 0xffff;
++ __u16 m = (word32 & 0xffff0000) >> 16;
++ printf("%04x %04x ", m, l);
++ if (!((i + 1)%13)) printf("\n");
++ }
++ printf("\n\n");
++
++ if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) {
++ printf("PASS\n\n");
++ }
++ else {
++ printf("FAIL\n\n");
++ }
++
++}
++
++#endif /* UNITTEST */
++
++#endif /* CONFIG_MACH_IPMATE */
++
++#endif /*DWC_CRYPTOLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.h b/drivers/usb/host/dwc_common_port/dwc_modpow.h
+new file mode 100644
+index 000000000000..64f00c276e71
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h
+@@ -0,0 +1,34 @@
++/*
++ * dwc_modpow.h
++ * See dwc_modpow.c for license and changes
++ */
++#ifndef _DWC_MODPOW_H
++#define _DWC_MODPOW_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * This file defines the module exponentiation function which is only used
++ * internally by the DWC UWB modules for calculation of PKs during numeric
++ * association. The routine is taken from the PUTTY, an open source terminal
++ * emulator. The PUTTY License is preserved in the dwc_modpow.c file.
++ *
++ */
++
++typedef uint32_t BignumInt;
++typedef uint64_t BignumDblInt;
++typedef BignumInt *Bignum;
++
++/* Compute modular exponentiaion */
++extern Bignum dwc_modpow(void *mem_ctx, Bignum base_in, Bignum exp, Bignum mod);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LINUX_BIGNUM_H */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.c b/drivers/usb/host/dwc_common_port/dwc_notifier.c
+new file mode 100644
+index 000000000000..8b3772afe11d
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c
+@@ -0,0 +1,319 @@
++#ifdef DWC_NOTIFYLIB
++
++#include "dwc_notifier.h"
++#include "dwc_list.h"
++
++typedef struct dwc_observer {
++ void *observer;
++ dwc_notifier_callback_t callback;
++ void *data;
++ char *notification;
++ DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
++} observer_t;
++
++DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
++
++typedef struct dwc_notifier {
++ void *mem_ctx;
++ void *object;
++ struct observer_queue observers;
++ DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
++} notifier_t;
++
++DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
++
++typedef struct manager {
++ void *mem_ctx;
++ void *wkq_ctx;
++ dwc_workq_t *wq;
++// dwc_mutex_t *mutex;
++ struct notifier_queue notifiers;
++} manager_t;
++
++static manager_t *manager = NULL;
++
++static int create_manager(void *mem_ctx, void *wkq_ctx)
++{
++ manager = dwc_alloc(mem_ctx, sizeof(manager_t));
++ if (!manager) {
++ return -DWC_E_NO_MEMORY;
++ }
++
++ DWC_CIRCLEQ_INIT(&manager->notifiers);
++
++ manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
++ if (!manager->wq) {
++ return -DWC_E_NO_MEMORY;
++ }
++
++ return 0;
++}
++
++static void free_manager(void)
++{
++ dwc_workq_free(manager->wq);
++
++ /* All notifiers must have unregistered themselves before this module
++ * can be removed. Hitting this assertion indicates a programmer
++ * error. */
++ DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
++ "Notification manager being freed before all notifiers have been removed");
++ dwc_free(manager->mem_ctx, manager);
++}
++
++#ifdef DEBUG
++static void dump_manager(void)
++{
++ notifier_t *n;
++ observer_t *o;
++
++ DWC_ASSERT(manager, "Notification manager not found");
++
++ DWC_DEBUG("List of all notifiers and observers:\n");
++ DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
++ DWC_DEBUG("Notifier %p has observers:\n", n->object);
++ DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
++ DWC_DEBUG(" %p watching %s\n", o->observer, o->notification);
++ }
++ }
++}
++#else
++#define dump_manager(...)
++#endif
++
++static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
++ dwc_notifier_callback_t callback, void *data)
++{
++ observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
++
++ if (!new_observer) {
++ return NULL;
++ }
++
++ DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
++ new_observer->observer = observer;
++ new_observer->notification = notification;
++ new_observer->callback = callback;
++ new_observer->data = data;
++ return new_observer;
++}
++
++static void free_observer(void *mem_ctx, observer_t *observer)
++{
++ dwc_free(mem_ctx, observer);
++}
++
++static notifier_t *alloc_notifier(void *mem_ctx, void *object)
++{
++ notifier_t *notifier;
++
++ if (!object) {
++ return NULL;
++ }
++
++ notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
++ if (!notifier) {
++ return NULL;
++ }
++
++ DWC_CIRCLEQ_INIT(&notifier->observers);
++ DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
++
++ notifier->mem_ctx = mem_ctx;
++ notifier->object = object;
++ return notifier;
++}
++
++static void free_notifier(notifier_t *notifier)
++{
++ observer_t *observer;
++
++ DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
++ free_observer(notifier->mem_ctx, observer);
++ }
++
++ dwc_free(notifier->mem_ctx, notifier);
++}
++
++static notifier_t *find_notifier(void *object)
++{
++ notifier_t *notifier;
++
++ DWC_ASSERT(manager, "Notification manager not found");
++
++ if (!object) {
++ return NULL;
++ }
++
++ DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
++ if (notifier->object == object) {
++ return notifier;
++ }
++ }
++
++ return NULL;
++}
++
++int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
++{
++ return create_manager(mem_ctx, wkq_ctx);
++}
++
++void dwc_free_notification_manager(void)
++{
++ free_manager();
++}
++
++dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
++{
++ notifier_t *notifier;
++
++ DWC_ASSERT(manager, "Notification manager not found");
++
++ notifier = find_notifier(object);
++ if (notifier) {
++ DWC_ERROR("Notifier %p is already registered\n", object);
++ return NULL;
++ }
++
++ notifier = alloc_notifier(mem_ctx, object);
++ if (!notifier) {
++ return NULL;
++ }
++
++ DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
++
++ DWC_INFO("Notifier %p registered", object);
++ dump_manager();
++
++ return notifier;
++}
++
++void dwc_unregister_notifier(dwc_notifier_t *notifier)
++{
++ DWC_ASSERT(manager, "Notification manager not found");
++
++ if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
++ observer_t *o;
++
++ DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
++ DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
++ DWC_DEBUGC(" %p watching %s\n", o->observer, o->notification);
++ }
++
++ DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
++ "Notifier %p has active observers when removing", notifier);
++ }
++
++ DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
++ free_notifier(notifier);
++
++ DWC_INFO("Notifier unregistered");
++ dump_manager();
++}
++
++/* Add an observer to observe the notifier for a particular state, event, or notification. */
++int dwc_add_observer(void *observer, void *object, char *notification,
++ dwc_notifier_callback_t callback, void *data)
++{
++ notifier_t *notifier = find_notifier(object);
++ observer_t *new_observer;
++
++ if (!notifier) {
++ DWC_ERROR("Notifier %p is not found when adding observer\n", object);
++ return -DWC_E_INVALID;
++ }
++
++ new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
++ if (!new_observer) {
++ return -DWC_E_NO_MEMORY;
++ }
++
++ DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
++
++ DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
++ observer, object, notification, callback, data);
++
++ dump_manager();
++ return 0;
++}
++
++int dwc_remove_observer(void *observer)
++{
++ notifier_t *n;
++
++ DWC_ASSERT(manager, "Notification manager not found");
++
++ DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
++ observer_t *o;
++ observer_t *o2;
++
++ DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
++ if (o->observer == observer) {
++ DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
++ DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
++ o->observer, n->object, o->notification);
++ free_observer(n->mem_ctx, o);
++ }
++ }
++ }
++
++ dump_manager();
++ return 0;
++}
++
++typedef struct callback_data {
++ void *mem_ctx;
++ dwc_notifier_callback_t cb;
++ void *observer;
++ void *data;
++ void *object;
++ char *notification;
++ void *notification_data;
++} cb_data_t;
++
++static void cb_task(void *data)
++{
++ cb_data_t *cb = (cb_data_t *)data;
++
++ cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
++ dwc_free(cb->mem_ctx, cb);
++}
++
++void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
++{
++ observer_t *o;
++
++ DWC_ASSERT(manager, "Notification manager not found");
++
++ DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
++ int len = DWC_STRLEN(notification);
++
++ if (DWC_STRLEN(o->notification) != len) {
++ continue;
++ }
++
++ if (DWC_STRNCMP(o->notification, notification, len) == 0) {
++ cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
++
++ if (!cb_data) {
++ DWC_ERROR("Failed to allocate callback data\n");
++ return;
++ }
++
++ cb_data->mem_ctx = notifier->mem_ctx;
++ cb_data->cb = o->callback;
++ cb_data->observer = o->observer;
++ cb_data->data = o->data;
++ cb_data->object = notifier->object;
++ cb_data->notification = notification;
++ cb_data->notification_data = notification_data;
++ DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
++ DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
++ "Notify callback from %p for Notification %s, to observer %p",
++ cb_data->object, notification, cb_data->observer);
++ }
++ }
++}
++
++#endif /* DWC_NOTIFYLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.h b/drivers/usb/host/dwc_common_port/dwc_notifier.h
+new file mode 100644
+index 000000000000..4a8cdfe565b1
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h
+@@ -0,0 +1,122 @@
++
++#ifndef __DWC_NOTIFIER_H__
++#define __DWC_NOTIFIER_H__
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * A simple implementation of the Observer pattern. Any "module" can
++ * register as an observer or notifier. The notion of "module" is abstract and
++ * can mean anything used to identify either an observer or notifier. Usually
++ * it will be a pointer to a data structure which contains some state, ie an
++ * object.
++ *
++ * Before any notifiers can be added, the global notification manager must be
++ * brought up with dwc_alloc_notification_manager().
++ * dwc_free_notification_manager() will bring it down and free all resources.
++ * These would typically be called upon module load and unload. The
++ * notification manager is a single global instance that handles all registered
++ * observable modules and observers so this should be done only once.
++ *
++ * A module can be observable by using Notifications to publicize some general
++ * information about it's state or operation. It does not care who listens, or
++ * even if anyone listens, or what they do with the information. The observable
++ * modules do not need to know any information about it's observers or their
++ * interface, or their state or data.
++ *
++ * Any module can register to emit Notifications. It should publish a list of
++ * notifications that it can emit and their behavior, such as when they will get
++ * triggered, and what information will be provided to the observer. Then it
++ * should register itself as an observable module. See dwc_register_notifier().
++ *
++ * Any module can observe any observable, registered module, provided it has a
++ * handle to the other module and knows what notifications to observe. See
++ * dwc_add_observer().
++ *
++ * A function of type dwc_notifier_callback_t is called whenever a notification
++ * is triggered with one or more observers observing it. This function is
++ * called in it's own process so it may sleep or block if needed. It is
++ * guaranteed to be called sometime after the notification has occurred and will
++ * be called once per each time the notification is triggered. It will NOT be
++ * called in the same process context used to trigger the notification.
++ *
++ * @section Limitiations
++ *
++ * Keep in mind that Notifications that can be triggered in rapid sucession may
++ * schedule too many processes too handle. Be aware of this limitation when
++ * designing to use notifications, and only add notifications for appropriate
++ * observable information.
++ *
++ * Also Notification callbacks are not synchronous. If you need to synchronize
++ * the behavior between module/observer you must use other means. And perhaps
++ * that will mean Notifications are not the proper solution.
++ */
++
++struct dwc_notifier;
++typedef struct dwc_notifier dwc_notifier_t;
++
++/** The callback function must be of this type.
++ *
++ * @param object This is the object that is being observed.
++ * @param notification This is the notification that was triggered.
++ * @param observer This is the observer
++ * @param notification_data This is notification-specific data that the notifier
++ * has included in this notification. The value of this should be published in
++ * the documentation of the observable module with the notifications.
++ * @param user_data This is any custom data that the observer provided when
++ * adding itself as an observer to the notification. */
++typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer,
++ void *notification_data, void *user_data);
++
++/** Brings up the notification manager. */
++extern int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx);
++/** Brings down the notification manager. */
++extern void dwc_free_notification_manager(void);
++
++/** This function registers an observable module. A dwc_notifier_t object is
++ * returned to the observable module. This is an opaque object that is used by
++ * the observable module to trigger notifications. This object should only be
++ * accessible to functions that are authorized to trigger notifications for this
++ * module. Observers do not need this object. */
++extern dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object);
++
++/** This function unregisters an observable module. All observers have to be
++ * removed prior to unregistration. */
++extern void dwc_unregister_notifier(dwc_notifier_t *notifier);
++
++/** Add a module as an observer to the observable module. The observable module
++ * needs to have previously registered with the notification manager.
++ *
++ * @param observer The observer module
++ * @param object The module to observe
++ * @param notification The notification to observe
++ * @param callback The callback function to call
++ * @param user_data Any additional user data to pass into the callback function */
++extern int dwc_add_observer(void *observer, void *object, char *notification,
++ dwc_notifier_callback_t callback, void *user_data);
++
++/** Removes the specified observer from all notifications that it is currently
++ * observing. */
++extern int dwc_remove_observer(void *observer);
++
++/** This function triggers a Notification. It should be called by the
++ * observable module, or any module or library which the observable module
++ * allows to trigger notification on it's behalf. Such as the dwc_cc_t.
++ *
++ * dwc_notify is a non-blocking function. Callbacks are scheduled called in
++ * their own process context for each trigger. Callbacks can be blocking.
++ * dwc_notify can be called from interrupt context if needed.
++ *
++ */
++void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* __DWC_NOTIFIER_H__ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h
+new file mode 100644
+index 000000000000..9a86d299403b
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_os.h
+@@ -0,0 +1,1276 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_os.h $
++ * $Revision: #14 $
++ * $Date: 2010/11/04 $
++ * $Change: 1621695 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifndef _DWC_OS_H_
++#define _DWC_OS_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * DWC portability library, low level os-wrapper functions
++ *
++ */
++
++/* These basic types need to be defined by some OS header file or custom header
++ * file for your specific target architecture.
++ *
++ * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
++ *
++ * Any custom or alternate header file must be added and enabled here.
++ */
++
++#ifdef DWC_LINUX
++# include <linux/types.h>
++# ifdef CONFIG_DEBUG_MUTEXES
++# include <linux/mutex.h>
++# endif
++# include <linux/spinlock.h>
++# include <linux/errno.h>
++# include <stdarg.h>
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++# include <os_dep.h>
++#endif
++
++
++/** @name Primitive Types and Values */
++
++/** We define a boolean type for consistency. Can be either YES or NO */
++typedef uint8_t dwc_bool_t;
++#define YES 1
++#define NO 0
++
++#ifdef DWC_LINUX
++
++/** @name Error Codes */
++#define DWC_E_INVALID EINVAL
++#define DWC_E_NO_MEMORY ENOMEM
++#define DWC_E_NO_DEVICE ENODEV
++#define DWC_E_NOT_SUPPORTED EOPNOTSUPP
++#define DWC_E_TIMEOUT ETIMEDOUT
++#define DWC_E_BUSY EBUSY
++#define DWC_E_AGAIN EAGAIN
++#define DWC_E_RESTART ERESTART
++#define DWC_E_ABORT ECONNABORTED
++#define DWC_E_SHUTDOWN ESHUTDOWN
++#define DWC_E_NO_DATA ENODATA
++#define DWC_E_DISCONNECT ECONNRESET
++#define DWC_E_UNKNOWN EINVAL
++#define DWC_E_NO_STREAM_RES ENOSR
++#define DWC_E_COMMUNICATION ECOMM
++#define DWC_E_OVERFLOW EOVERFLOW
++#define DWC_E_PROTOCOL EPROTO
++#define DWC_E_IN_PROGRESS EINPROGRESS
++#define DWC_E_PIPE EPIPE
++#define DWC_E_IO EIO
++#define DWC_E_NO_SPACE ENOSPC
++
++#else
++
++/** @name Error Codes */
++#define DWC_E_INVALID 1001
++#define DWC_E_NO_MEMORY 1002
++#define DWC_E_NO_DEVICE 1003
++#define DWC_E_NOT_SUPPORTED 1004
++#define DWC_E_TIMEOUT 1005
++#define DWC_E_BUSY 1006
++#define DWC_E_AGAIN 1007
++#define DWC_E_RESTART 1008
++#define DWC_E_ABORT 1009
++#define DWC_E_SHUTDOWN 1010
++#define DWC_E_NO_DATA 1011
++#define DWC_E_DISCONNECT 2000
++#define DWC_E_UNKNOWN 3000
++#define DWC_E_NO_STREAM_RES 4001
++#define DWC_E_COMMUNICATION 4002
++#define DWC_E_OVERFLOW 4003
++#define DWC_E_PROTOCOL 4004
++#define DWC_E_IN_PROGRESS 4005
++#define DWC_E_PIPE 4006
++#define DWC_E_IO 4007
++#define DWC_E_NO_SPACE 4008
++
++#endif
++
++
++/** @name Tracing/Logging Functions
++ *
++ * These function provide the capability to add tracing, debugging, and error
++ * messages, as well exceptions as assertions. The WUDEV uses these
++ * extensively. These could be logged to the main console, the serial port, an
++ * internal buffer, etc. These functions could also be no-op if they are too
++ * expensive on your system. By default undefining the DEBUG macro already
++ * no-ops some of these functions. */
++
++/** Returns non-zero if in interrupt context. */
++extern dwc_bool_t DWC_IN_IRQ(void);
++#define dwc_in_irq DWC_IN_IRQ
++
++/** Returns "IRQ" if DWC_IN_IRQ is true. */
++static inline char *dwc_irq(void) {
++ return DWC_IN_IRQ() ? "IRQ" : "";
++}
++
++/** Returns non-zero if in bottom-half context. */
++extern dwc_bool_t DWC_IN_BH(void);
++#define dwc_in_bh DWC_IN_BH
++
++/** Returns "BH" if DWC_IN_BH is true. */
++static inline char *dwc_bh(void) {
++ return DWC_IN_BH() ? "BH" : "";
++}
++
++/**
++ * A vprintf() clone. Just call vprintf if you've got it.
++ */
++extern void DWC_VPRINTF(char *format, va_list args);
++#define dwc_vprintf DWC_VPRINTF
++
++/**
++ * A vsnprintf() clone. Just call vprintf if you've got it.
++ */
++extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args);
++#define dwc_vsnprintf DWC_VSNPRINTF
++
++/**
++ * printf() clone. Just call printf if you've go it.
++ */
++extern void DWC_PRINTF(char *format, ...)
++/* This provides compiler level static checking of the parameters if you're
++ * using GCC. */
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 1, 2)));
++#else
++ ;
++#endif
++#define dwc_printf DWC_PRINTF
++
++/**
++ * sprintf() clone. Just call sprintf if you've got it.
++ */
++extern int DWC_SPRINTF(char *string, char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 2, 3)));
++#else
++ ;
++#endif
++#define dwc_sprintf DWC_SPRINTF
++
++/**
++ * snprintf() clone. Just call snprintf if you've got it.
++ */
++extern int DWC_SNPRINTF(char *string, int size, char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 3, 4)));
++#else
++ ;
++#endif
++#define dwc_snprintf DWC_SNPRINTF
++
++/**
++ * Prints a WARNING message. On systems that don't differentiate between
++ * warnings and regular log messages, just print it. Indicates that something
++ * may be wrong with the driver. Works like printf().
++ *
++ * Use the DWC_WARN macro to call this function.
++ */
++extern void __DWC_WARN(char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 1, 2)));
++#else
++ ;
++#endif
++
++/**
++ * Prints an error message. On systems that don't differentiate between errors
++ * and regular log messages, just print it. Indicates that something went wrong
++ * with the driver. Works like printf().
++ *
++ * Use the DWC_ERROR macro to call this function.
++ */
++extern void __DWC_ERROR(char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 1, 2)));
++#else
++ ;
++#endif
++
++/**
++ * Prints an exception error message and takes some user-defined action such as
++ * print out a backtrace or trigger a breakpoint. Indicates that something went
++ * abnormally wrong with the driver such as programmer error, or other
++ * exceptional condition. It should not be ignored so even on systems without
++ * printing capability, some action should be taken to notify the developer of
++ * it. Works like printf().
++ */
++extern void DWC_EXCEPTION(char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 1, 2)));
++#else
++ ;
++#endif
++#define dwc_exception DWC_EXCEPTION
++
++#ifndef DWC_OTG_DEBUG_LEV
++#define DWC_OTG_DEBUG_LEV 0
++#endif
++
++#ifdef DEBUG
++/**
++ * Prints out a debug message. Used for logging/trace messages.
++ *
++ * Use the DWC_DEBUG macro to call this function
++ */
++extern void __DWC_DEBUG(char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 1, 2)));
++#else
++ ;
++#endif
++#else
++#define __DWC_DEBUG printk
++#endif
++
++/**
++ * Prints out a Debug message.
++ */
++#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", \
++ __func__, dwc_irq(), ## _args)
++#define dwc_debug DWC_DEBUG
++/**
++ * Prints out a Debug message if enabled at compile time.
++ */
++#if DWC_OTG_DEBUG_LEV > 0
++#define DWC_DEBUGC(_format, _args...) DWC_DEBUG(_format, ##_args )
++#else
++#define DWC_DEBUGC(_format, _args...)
++#endif
++#define dwc_debugc DWC_DEBUGC
++/**
++ * Prints out an informative message.
++ */
++#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", \
++ dwc_irq(), ## _args)
++#define dwc_info DWC_INFO
++/**
++ * Prints out an informative message if enabled at compile time.
++ */
++#if DWC_OTG_DEBUG_LEV > 1
++#define DWC_INFOC(_format, _args...) DWC_INFO(_format, ##_args )
++#else
++#define DWC_INFOC(_format, _args...)
++#endif
++#define dwc_infoc DWC_INFOC
++/**
++ * Prints out a warning message.
++ */
++#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", \
++ dwc_irq(), __func__, __LINE__, ## _args)
++#define dwc_warn DWC_WARN
++/**
++ * Prints out an error message.
++ */
++#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", \
++ dwc_irq(), __func__, __LINE__, ## _args)
++#define dwc_error DWC_ERROR
++
++#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", \
++ dwc_irq(), __func__, __LINE__, ## _args)
++#define dwc_proto_error DWC_PROTO_ERROR
++
++#ifdef DEBUG
++/** Prints out a exception error message if the _expr expression fails. Disabled
++ * if DEBUG is not enabled. */
++#define DWC_ASSERT(_expr, _format, _args...) do { \
++ if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), \
++ __FILE__, __LINE__, ## _args); } \
++ } while (0)
++#else
++#define DWC_ASSERT(_x...)
++#endif
++#define dwc_assert DWC_ASSERT
++
++
++/** @name Byte Ordering
++ * The following functions are for conversions between processor's byte ordering
++ * and specific ordering you want.
++ */
++
++/** Converts 32 bit data in CPU byte ordering to little endian. */
++extern uint32_t DWC_CPU_TO_LE32(uint32_t *p);
++#define dwc_cpu_to_le32 DWC_CPU_TO_LE32
++
++/** Converts 32 bit data in CPU byte orderint to big endian. */
++extern uint32_t DWC_CPU_TO_BE32(uint32_t *p);
++#define dwc_cpu_to_be32 DWC_CPU_TO_BE32
++
++/** Converts 32 bit little endian data to CPU byte ordering. */
++extern uint32_t DWC_LE32_TO_CPU(uint32_t *p);
++#define dwc_le32_to_cpu DWC_LE32_TO_CPU
++
++/** Converts 32 bit big endian data to CPU byte ordering. */
++extern uint32_t DWC_BE32_TO_CPU(uint32_t *p);
++#define dwc_be32_to_cpu DWC_BE32_TO_CPU
++
++/** Converts 16 bit data in CPU byte ordering to little endian. */
++extern uint16_t DWC_CPU_TO_LE16(uint16_t *p);
++#define dwc_cpu_to_le16 DWC_CPU_TO_LE16
++
++/** Converts 16 bit data in CPU byte orderint to big endian. */
++extern uint16_t DWC_CPU_TO_BE16(uint16_t *p);
++#define dwc_cpu_to_be16 DWC_CPU_TO_BE16
++
++/** Converts 16 bit little endian data to CPU byte ordering. */
++extern uint16_t DWC_LE16_TO_CPU(uint16_t *p);
++#define dwc_le16_to_cpu DWC_LE16_TO_CPU
++
++/** Converts 16 bit bi endian data to CPU byte ordering. */
++extern uint16_t DWC_BE16_TO_CPU(uint16_t *p);
++#define dwc_be16_to_cpu DWC_BE16_TO_CPU
++
++
++/** @name Register Read/Write
++ *
++ * The following six functions should be implemented to read/write registers of
++ * 32-bit and 64-bit sizes. All modules use this to read/write register values.
++ * The reg value is a pointer to the register calculated from the void *base
++ * variable passed into the driver when it is started. */
++
++#ifdef DWC_LINUX
++/* Linux doesn't need any extra parameters for register read/write, so we
++ * just throw away the IO context parameter.
++ */
++/** Reads the content of a 32-bit register. */
++extern uint32_t DWC_READ_REG32(uint32_t volatile *reg);
++#define dwc_read_reg32(_ctx_,_reg_) DWC_READ_REG32(_reg_)
++
++/** Reads the content of a 64-bit register. */
++extern uint64_t DWC_READ_REG64(uint64_t volatile *reg);
++#define dwc_read_reg64(_ctx_,_reg_) DWC_READ_REG64(_reg_)
++
++/** Writes to a 32-bit register. */
++extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value);
++#define dwc_write_reg32(_ctx_,_reg_,_val_) DWC_WRITE_REG32(_reg_, _val_)
++
++/** Writes to a 64-bit register. */
++extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value);
++#define dwc_write_reg64(_ctx_,_reg_,_val_) DWC_WRITE_REG64(_reg_, _val_)
++
++/**
++ * Modify bit values in a register. Using the
++ * algorithm: (reg_contents & ~clear_mask) | set_mask.
++ */
++extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
++#define dwc_modify_reg32(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG32(_reg_,_cmsk_,_smsk_)
++extern void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
++#define dwc_modify_reg64(_ctx_,_reg_,_cmsk_,_smsk_) DWC_MODIFY_REG64(_reg_,_cmsk_,_smsk_)
++
++#endif /* DWC_LINUX */
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++typedef struct dwc_ioctx {
++ struct device *dev;
++ bus_space_tag_t iot;
++ bus_space_handle_t ioh;
++} dwc_ioctx_t;
++
++/** BSD needs two extra parameters for register read/write, so we pass
++ * them in using the IO context parameter.
++ */
++/** Reads the content of a 32-bit register. */
++extern uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg);
++#define dwc_read_reg32 DWC_READ_REG32
++
++/** Reads the content of a 64-bit register. */
++extern uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg);
++#define dwc_read_reg64 DWC_READ_REG64
++
++/** Writes to a 32-bit register. */
++extern void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value);
++#define dwc_write_reg32 DWC_WRITE_REG32
++
++/** Writes to a 64-bit register. */
++extern void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value);
++#define dwc_write_reg64 DWC_WRITE_REG64
++
++/**
++ * Modify bit values in a register. Using the
++ * algorithm: (reg_contents & ~clear_mask) | set_mask.
++ */
++extern void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask);
++#define dwc_modify_reg32 DWC_MODIFY_REG32
++extern void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask);
++#define dwc_modify_reg64 DWC_MODIFY_REG64
++
++#endif /* DWC_FREEBSD || DWC_NETBSD */
++
++/** @cond */
++
++/** @name Some convenience MACROS used internally. Define DWC_DEBUG_REGS to log the
++ * register writes. */
++
++#ifdef DWC_LINUX
++
++# ifdef DWC_DEBUG_REGS
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
++ return DWC_READ_REG32(&container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
++ DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
++ &(((uint32_t*)container->regs->_reg)[num]), data); \
++ DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(_container_type *container) { \
++ return DWC_READ_REG32(&container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
++ DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
++ DWC_WRITE_REG32(&container->regs->_reg, data); \
++}
++
++# else /* DWC_DEBUG_REGS */
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \
++ return DWC_READ_REG32(&container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \
++ DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(_container_type *container) { \
++ return DWC_READ_REG32(&container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \
++ DWC_WRITE_REG32(&container->regs->_reg, data); \
++}
++
++# endif /* DWC_DEBUG_REGS */
++
++#endif /* DWC_LINUX */
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++
++# ifdef DWC_DEBUG_REGS
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
++ return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
++ DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, \
++ &(((uint32_t*)container->regs->_reg)[num]), data); \
++ DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
++ return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
++ DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \
++ DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
++}
++
++# else /* DWC_DEBUG_REGS */
++
++#define dwc_define_read_write_reg_n(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg##_n(void *io_ctx, _container_type *container, int num) { \
++ return DWC_READ_REG32(io_ctx, &container->regs->_reg[num]); \
++} \
++static inline void dwc_write_##_reg##_n(void *io_ctx, _container_type *container, int num, uint32_t data) { \
++ DWC_WRITE_REG32(io_ctx, &(((uint32_t*)container->regs->_reg)[num]), data); \
++}
++
++#define dwc_define_read_write_reg(_reg,_container_type) \
++static inline uint32_t dwc_read_##_reg(void *io_ctx, _container_type *container) { \
++ return DWC_READ_REG32(io_ctx, &container->regs->_reg); \
++} \
++static inline void dwc_write_##_reg(void *io_ctx, _container_type *container, uint32_t data) { \
++ DWC_WRITE_REG32(io_ctx, &container->regs->_reg, data); \
++}
++
++# endif /* DWC_DEBUG_REGS */
++
++#endif /* DWC_FREEBSD || DWC_NETBSD */
++
++/** @endcond */
++
++
++#ifdef DWC_CRYPTOLIB
++/** @name Crypto Functions
++ *
++ * These are the low-level cryptographic functions used by the driver. */
++
++/** Perform AES CBC */
++extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out);
++#define dwc_aes_cbc DWC_AES_CBC
++
++/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */
++extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length);
++#define dwc_random_bytes DWC_RANDOM_BYTES
++
++/** Perform the SHA-256 hash function */
++extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out);
++#define dwc_sha256 DWC_SHA256
++
++/** Calculated the HMAC-SHA256 */
++extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out);
++#define dwc_hmac_sha256 DWC_HMAC_SHA256
++
++#endif /* DWC_CRYPTOLIB */
++
++
++/** @name Memory Allocation
++ *
++ * These function provide access to memory allocation. There are only 2 DMA
++ * functions and 3 Regular memory functions that need to be implemented. None
++ * of the memory debugging routines need to be implemented. The allocation
++ * routines all ZERO the contents of the memory.
++ *
++ * Defining DWC_DEBUG_MEMORY turns on memory debugging and statistic gathering.
++ * This checks for memory leaks, keeping track of alloc/free pairs. It also
++ * keeps track of how much memory the driver is using at any given time. */
++
++#define DWC_PAGE_SIZE 4096
++#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff)
++#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0)
++
++#define DWC_INVALID_DMA_ADDR 0x0
++
++#ifdef DWC_LINUX
++/** Type for a DMA address */
++typedef dma_addr_t dwc_dma_t;
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++typedef bus_addr_t dwc_dma_t;
++#endif
++
++#ifdef DWC_FREEBSD
++typedef struct dwc_dmactx {
++ struct device *dev;
++ bus_dma_tag_t dma_tag;
++ bus_dmamap_t dma_map;
++ bus_addr_t dma_paddr;
++ void *dma_vaddr;
++} dwc_dmactx_t;
++#endif
++
++#ifdef DWC_NETBSD
++typedef struct dwc_dmactx {
++ struct device *dev;
++ bus_dma_tag_t dma_tag;
++ bus_dmamap_t dma_map;
++ bus_dma_segment_t segs[1];
++ int nsegs;
++ bus_addr_t dma_paddr;
++ void *dma_vaddr;
++} dwc_dmactx_t;
++#endif
++
++/* @todo these functions will be added in the future */
++#if 0
++/**
++ * Creates a DMA pool from which you can allocate DMA buffers. Buffers
++ * allocated from this pool will be guaranteed to meet the size, alignment, and
++ * boundary requirements specified.
++ *
++ * @param[in] size Specifies the size of the buffers that will be allocated from
++ * this pool.
++ * @param[in] align Specifies the byte alignment requirements of the buffers
++ * allocated from this pool. Must be a power of 2.
++ * @param[in] boundary Specifies the N-byte boundary that buffers allocated from
++ * this pool must not cross.
++ *
++ * @returns A pointer to an internal opaque structure which is not to be
++ * accessed outside of these library functions. Use this handle to specify
++ * which pools to allocate/free DMA buffers from and also to destroy the pool,
++ * when you are done with it.
++ */
++extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary);
++
++/**
++ * Destroy a DMA pool. All buffers allocated from that pool must be freed first.
++ */
++extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool);
++
++/**
++ * Allocate a buffer from the specified DMA pool and zeros its contents.
++ */
++extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr);
++
++/**
++ * Free a previously allocated buffer from the DMA pool.
++ */
++extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr);
++#endif
++
++/** Allocates a DMA capable buffer and zeroes its contents. */
++extern void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
++
++/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */
++extern void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr);
++
++/** Frees a previously allocated buffer. */
++extern void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr);
++
++/** Allocates a block of memory and zeroes its contents. */
++extern void *__DWC_ALLOC(void *mem_ctx, uint32_t size);
++
++/** Allocates a block of memory and zeroes its contents, in an atomic manner
++ * which can be used inside interrupt context. The size should be sufficiently
++ * small, a few KB at most, such that failures are not likely to occur. Can just call
++ * __DWC_ALLOC if it is atomic. */
++extern void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size);
++
++/** Frees a previously allocated buffer. */
++extern void __DWC_FREE(void *mem_ctx, void *addr);
++
++#ifndef DWC_DEBUG_MEMORY
++
++#define DWC_ALLOC(_size_) __DWC_ALLOC(NULL, _size_)
++#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(NULL, _size_)
++#define DWC_FREE(_addr_) __DWC_FREE(NULL, _addr_)
++
++# ifdef DWC_LINUX
++#define DWC_DMA_ALLOC(_dev, _size_, _dma_) __DWC_DMA_ALLOC(_dev, _size_, _dma_)
++#define DWC_DMA_ALLOC_ATOMIC(_dev, _size_, _dma_) __DWC_DMA_ALLOC_ATOMIC(_dev, _size_, _dma_)
++#define DWC_DMA_FREE(_dev, _size_,_virt_, _dma_) __DWC_DMA_FREE(_dev, _size_, _virt_, _dma_)
++# endif
++
++# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++#define DWC_DMA_ALLOC __DWC_DMA_ALLOC
++#define DWC_DMA_FREE __DWC_DMA_FREE
++# endif
++extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line);
++
++#else /* DWC_DEBUG_MEMORY */
++
++extern void *dwc_alloc_debug(void *mem_ctx, uint32_t size, char const *func, int line);
++extern void *dwc_alloc_atomic_debug(void *mem_ctx, uint32_t size, char const *func, int line);
++extern void dwc_free_debug(void *mem_ctx, void *addr, char const *func, int line);
++extern void *dwc_dma_alloc_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
++ char const *func, int line);
++extern void *dwc_dma_alloc_atomic_debug(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr,
++ char const *func, int line);
++extern void dwc_dma_free_debug(void *dma_ctx, uint32_t size, void *virt_addr,
++ dwc_dma_t dma_addr, char const *func, int line);
++
++extern int dwc_memory_debug_start(void *mem_ctx);
++extern void dwc_memory_debug_stop(void);
++extern void dwc_memory_debug_report(void);
++
++#define DWC_ALLOC(_size_) dwc_alloc_debug(NULL, _size_, __func__, __LINE__)
++#define DWC_ALLOC_ATOMIC(_size_) dwc_alloc_atomic_debug(NULL, _size_, \
++ __func__, __LINE__)
++#define DWC_FREE(_addr_) dwc_free_debug(NULL, _addr_, __func__, __LINE__)
++
++# ifdef DWC_LINUX
++#define DWC_DMA_ALLOC(_dev, _size_, _dma_) \
++ dwc_dma_alloc_debug(_dev, _size_, _dma_, __func__, __LINE__)
++#define DWC_DMA_ALLOC_ATOMIC(_dev, _size_, _dma_) \
++ dwc_dma_alloc_atomic_debug(_dev, _size_, _dma_, __func__, __LINE__)
++#define DWC_DMA_FREE(_dev, _size_, _virt_, _dma_) \
++ dwc_dma_free_debug(_dev, _size_, _virt_, _dma_, __func__, __LINE__)
++# endif
++
++# if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++#define DWC_DMA_ALLOC(_ctx_,_size_,_dma_) dwc_dma_alloc_debug(_ctx_, _size_, \
++ _dma_, __func__, __LINE__)
++#define DWC_DMA_FREE(_ctx_,_size_,_virt_,_dma_) dwc_dma_free_debug(_ctx_, _size_, \
++ _virt_, _dma_, __func__, __LINE__)
++# endif
++
++#endif /* DWC_DEBUG_MEMORY */
++
++#define dwc_alloc(_ctx_,_size_) DWC_ALLOC(_size_)
++#define dwc_alloc_atomic(_ctx_,_size_) DWC_ALLOC_ATOMIC(_size_)
++#define dwc_free(_ctx_,_addr_) DWC_FREE(_addr_)
++
++#ifdef DWC_LINUX
++/* Linux doesn't need any extra parameters for DMA buffer allocation, so we
++ * just throw away the DMA context parameter.
++ */
++#define dwc_dma_alloc(_ctx_,_size_,_dma_) DWC_DMA_ALLOC(_size_, _dma_)
++#define dwc_dma_alloc_atomic(_ctx_,_size_,_dma_) DWC_DMA_ALLOC_ATOMIC(_size_, _dma_)
++#define dwc_dma_free(_ctx_,_size_,_virt_,_dma_) DWC_DMA_FREE(_size_, _virt_, _dma_)
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++/** BSD needs several extra parameters for DMA buffer allocation, so we pass
++ * them in using the DMA context parameter.
++ */
++#define dwc_dma_alloc DWC_DMA_ALLOC
++#define dwc_dma_free DWC_DMA_FREE
++#endif
++
++
++/** @name Memory and String Processing */
++
++/** memset() clone */
++extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size);
++#define dwc_memset DWC_MEMSET
++
++/** memcpy() clone */
++extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size);
++#define dwc_memcpy DWC_MEMCPY
++
++/** memmove() clone */
++extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size);
++#define dwc_memmove DWC_MEMMOVE
++
++/** memcmp() clone */
++extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size);
++#define dwc_memcmp DWC_MEMCMP
++
++/** strcmp() clone */
++extern int DWC_STRCMP(void *s1, void *s2);
++#define dwc_strcmp DWC_STRCMP
++
++/** strncmp() clone */
++extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size);
++#define dwc_strncmp DWC_STRNCMP
++
++/** strlen() clone, for NULL terminated ASCII strings */
++extern int DWC_STRLEN(char const *str);
++#define dwc_strlen DWC_STRLEN
++
++/** strcpy() clone, for NULL terminated ASCII strings */
++extern char *DWC_STRCPY(char *to, const char *from);
++#define dwc_strcpy DWC_STRCPY
++
++/** strdup() clone. If you wish to use memory allocation debugging, this
++ * implementation of strdup should use the DWC_* memory routines instead of
++ * calling a predefined strdup. Otherwise the memory allocated by this routine
++ * will not be seen by the debugging routines. */
++extern char *DWC_STRDUP(char const *str);
++#define dwc_strdup(_ctx_,_str_) DWC_STRDUP(_str_)
++
++/** NOT an atoi() clone. Read the description carefully. Returns an integer
++ * converted from the string str in base 10 unless the string begins with a "0x"
++ * in which case it is base 16. String must be a NULL terminated sequence of
++ * ASCII characters and may optionally begin with whitespace, a + or -, and a
++ * "0x" prefix if base 16. The remaining characters must be valid digits for
++ * the number and end with a NULL character. If any invalid characters are
++ * encountered or it returns with a negative error code and the results of the
++ * conversion are undefined. On sucess it returns 0. Overflow conditions are
++ * undefined. An example implementation using atoi() can be referenced from the
++ * Linux implementation. */
++extern int DWC_ATOI(const char *str, int32_t *value);
++#define dwc_atoi DWC_ATOI
++
++/** Same as above but for unsigned. */
++extern int DWC_ATOUI(const char *str, uint32_t *value);
++#define dwc_atoui DWC_ATOUI
++
++#ifdef DWC_UTFLIB
++/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */
++extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len);
++#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE
++#endif
++
++
++/** @name Wait queues
++ *
++ * Wait queues provide a means of synchronizing between threads or processes. A
++ * process can block on a waitq if some condition is not true, waiting for it to
++ * become true. When the waitq is triggered all waiting process will get
++ * unblocked and the condition will be check again. Waitqs should be triggered
++ * every time a condition can potentially change.*/
++struct dwc_waitq;
++
++/** Type for a waitq */
++typedef struct dwc_waitq dwc_waitq_t;
++
++/** The type of waitq condition callback function. This is called every time
++ * condition is evaluated. */
++typedef int (*dwc_waitq_condition_t)(void *data);
++
++/** Allocate a waitq */
++extern dwc_waitq_t *DWC_WAITQ_ALLOC(void);
++#define dwc_waitq_alloc(_ctx_) DWC_WAITQ_ALLOC()
++
++/** Free a waitq */
++extern void DWC_WAITQ_FREE(dwc_waitq_t *wq);
++#define dwc_waitq_free DWC_WAITQ_FREE
++
++/** Check the condition and if it is false, block on the waitq. When unblocked, check the
++ * condition again. The function returns when the condition becomes true. The return value
++ * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */
++extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data);
++#define dwc_waitq_wait DWC_WAITQ_WAIT
++
++/** Check the condition and if it is false, block on the waitq. When unblocked,
++ * check the condition again. The function returns when the condition become
++ * true or the timeout has passed. The return value is 0 on condition true or
++ * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on
++ * error. */
++extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs);
++#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT
++
++/** Trigger a waitq, unblocking all processes. This should be called whenever a condition
++ * has potentially changed. */
++extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq);
++#define dwc_waitq_trigger DWC_WAITQ_TRIGGER
++
++/** Unblock all processes waiting on the waitq with an ABORTED result. */
++extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq);
++#define dwc_waitq_abort DWC_WAITQ_ABORT
++
++
++/** @name Threads
++ *
++ * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP
++ * whenever it is woken up, and then return. The DWC_THREAD_STOP function
++ * returns the value from the thread.
++ */
++
++struct dwc_thread;
++
++/** Type for a thread */
++typedef struct dwc_thread dwc_thread_t;
++
++/** The thread function */
++typedef int (*dwc_thread_function_t)(void *data);
++
++/** Create a thread and start it running the thread_function. Returns a handle
++ * to the thread */
++extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data);
++#define dwc_thread_run(_ctx_,_func_,_name_,_data_) DWC_THREAD_RUN(_func_, _name_, _data_)
++
++/** Stops a thread. Return the value returned by the thread. Or will return
++ * DWC_ABORT if the thread never started. */
++extern int DWC_THREAD_STOP(dwc_thread_t *thread);
++#define dwc_thread_stop DWC_THREAD_STOP
++
++/** Signifies to the thread that it must stop. */
++#ifdef DWC_LINUX
++/* Linux doesn't need any parameters for kthread_should_stop() */
++extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void);
++#define dwc_thread_should_stop(_thrd_) DWC_THREAD_SHOULD_STOP()
++
++/* No thread_exit function in Linux */
++#define dwc_thread_exit(_thrd_)
++#endif
++
++#if defined(DWC_FREEBSD) || defined(DWC_NETBSD)
++/** BSD needs the thread pointer for kthread_suspend_check() */
++extern dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread);
++#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP
++
++/** The thread must call this to exit. */
++extern void DWC_THREAD_EXIT(dwc_thread_t *thread);
++#define dwc_thread_exit DWC_THREAD_EXIT
++#endif
++
++
++/** @name Work queues
++ *
++ * Workqs are used to queue a callback function to be called at some later time,
++ * in another thread. */
++struct dwc_workq;
++
++/** Type for a workq */
++typedef struct dwc_workq dwc_workq_t;
++
++/** The type of the callback function to be called. */
++typedef void (*dwc_work_callback_t)(void *data);
++
++/** Allocate a workq */
++extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name);
++#define dwc_workq_alloc(_ctx_,_name_) DWC_WORKQ_ALLOC(_name_)
++
++/** Free a workq. All work must be completed before being freed. */
++extern void DWC_WORKQ_FREE(dwc_workq_t *workq);
++#define dwc_workq_free DWC_WORKQ_FREE
++
++/** Schedule a callback on the workq, passing in data. The function will be
++ * scheduled at some later time. */
++extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t cb,
++ void *data, char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 4, 5)));
++#else
++ ;
++#endif
++#define dwc_workq_schedule DWC_WORKQ_SCHEDULE
++
++/** Schedule a callback on the workq, that will be called until at least
++ * given number miliseconds have passed. */
++extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++#ifdef __GNUC__
++ __attribute__ ((format(printf, 5, 6)));
++#else
++ ;
++#endif
++#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED
++
++/** The number of processes in the workq */
++extern int DWC_WORKQ_PENDING(dwc_workq_t *workq);
++#define dwc_workq_pending DWC_WORKQ_PENDING
++
++/** Blocks until all the work in the workq is complete or timed out. Returns <
++ * 0 on timeout. */
++extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout);
++#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE
++
++
++/** @name Tasklets
++ *
++ */
++struct dwc_tasklet;
++
++/** Type for a tasklet */
++typedef struct dwc_tasklet dwc_tasklet_t;
++
++/** The type of the callback function to be called */
++typedef void (*dwc_tasklet_callback_t)(void *data);
++
++/** Allocates a tasklet */
++extern dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data);
++#define dwc_task_alloc(_ctx_,_name_,_cb_,_data_) DWC_TASK_ALLOC(_name_, _cb_, _data_)
++
++/** Frees a tasklet */
++extern void DWC_TASK_FREE(dwc_tasklet_t *task);
++#define dwc_task_free DWC_TASK_FREE
++
++/** Schedules a tasklet to run */
++extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
++#define dwc_task_schedule DWC_TASK_SCHEDULE
++
++extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task);
++#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE
++
++/** @name Timer
++ *
++ * Callbacks must be small and atomic.
++ */
++struct dwc_timer;
++
++/** Type for a timer */
++typedef struct dwc_timer dwc_timer_t;
++
++/** The type of the callback function to be called */
++typedef void (*dwc_timer_callback_t)(void *data);
++
++/** Allocates a timer */
++extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data);
++#define dwc_timer_alloc(_ctx_,_name_,_cb_,_data_) DWC_TIMER_ALLOC(_name_,_cb_,_data_)
++
++/** Frees a timer */
++extern void DWC_TIMER_FREE(dwc_timer_t *timer);
++#define dwc_timer_free DWC_TIMER_FREE
++
++/** Schedules the timer to run at time ms from now. And will repeat at every
++ * repeat_interval msec therafter
++ *
++ * Modifies a timer that is still awaiting execution to a new expiration time.
++ * The mod_time is added to the old time. */
++extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time);
++#define dwc_timer_schedule DWC_TIMER_SCHEDULE
++
++/** Disables the timer from execution. */
++extern void DWC_TIMER_CANCEL(dwc_timer_t *timer);
++#define dwc_timer_cancel DWC_TIMER_CANCEL
++
++
++/** @name Spinlocks
++ *
++ * These locks are used when the work between the lock/unlock is atomic and
++ * short. Interrupts are also disabled during the lock/unlock and thus they are
++ * suitable to lock between interrupt/non-interrupt context. They also lock
++ * between processes if you have multiple CPUs or Preemption. If you don't have
++ * multiple CPUS or Preemption, then the you can simply implement the
++ * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because
++ * the work between the lock/unlock is atomic, the process context will never
++ * change, and so you never have to lock between processes. */
++
++struct dwc_spinlock;
++
++/** Type for a spinlock */
++typedef struct dwc_spinlock dwc_spinlock_t;
++
++/** Type for the 'flags' argument to spinlock funtions */
++typedef unsigned long dwc_irqflags_t;
++
++/** Returns an initialized lock variable. This function should allocate and
++ * initialize the OS-specific data structure used for locking. This data
++ * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should
++ * be freed by the DWC_FREE_LOCK when it is no longer used.
++ *
++ * For Linux Spinlock Debugging make it macro because the debugging routines use
++ * the symbol name to determine recursive locking. Using a wrapper function
++ * makes it falsely think recursive locking occurs. */
++#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK)
++#define DWC_SPINLOCK_ALLOC_LINUX_DEBUG(lock) ({ \
++ lock = DWC_ALLOC(sizeof(spinlock_t)); \
++ if (lock) { \
++ spin_lock_init((spinlock_t *)lock); \
++ } \
++})
++#else
++extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void);
++#define dwc_spinlock_alloc(_ctx_) DWC_SPINLOCK_ALLOC()
++#endif
++
++/** Frees an initialized lock variable. */
++extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock);
++#define dwc_spinlock_free(_ctx_,_lock_) DWC_SPINLOCK_FREE(_lock_)
++
++/** Disables interrupts and blocks until it acquires the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ * @param flags Unsigned long for irq flags storage.
++ */
++extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags);
++#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE
++
++/** Re-enables the interrupt and releases the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ * @param flags Unsigned long for irq flags storage. Must be the same as was
++ * passed into DWC_LOCK.
++ */
++extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags);
++#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE
++
++/** Blocks until it acquires the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ */
++extern void DWC_SPINLOCK(dwc_spinlock_t *lock);
++#define dwc_spinlock DWC_SPINLOCK
++
++/** Releases the lock.
++ *
++ * @param lock Pointer to the spinlock.
++ */
++extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock);
++#define dwc_spinunlock DWC_SPINUNLOCK
++
++
++/** @name Mutexes
++ *
++ * Unlike spinlocks Mutexes lock only between processes and the work between the
++ * lock/unlock CAN block, therefore it CANNOT be called from interrupt context.
++ */
++
++struct dwc_mutex;
++
++/** Type for a mutex */
++typedef struct dwc_mutex dwc_mutex_t;
++
++/* For Linux Mutex Debugging make it inline because the debugging routines use
++ * the symbol to determine recursive locking. This makes it falsely think
++ * recursive locking occurs. */
++#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
++#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \
++ __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \
++ mutex_init((struct mutex *)__mutexp); \
++})
++#endif
++
++/** Allocate a mutex */
++extern dwc_mutex_t *DWC_MUTEX_ALLOC(void);
++#define dwc_mutex_alloc(_ctx_) DWC_MUTEX_ALLOC()
++
++/* For memory leak debugging when using Linux Mutex Debugging */
++#if defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)
++#define DWC_MUTEX_FREE(__mutexp) do { \
++ mutex_destroy((struct mutex *)__mutexp); \
++ DWC_FREE(__mutexp); \
++} while(0)
++#else
++/** Free a mutex */
++extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex);
++#define dwc_mutex_free(_ctx_,_mutex_) DWC_MUTEX_FREE(_mutex_)
++#endif
++
++/** Lock a mutex */
++extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex);
++#define dwc_mutex_lock DWC_MUTEX_LOCK
++
++/** Non-blocking lock returns 1 on successful lock. */
++extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex);
++#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK
++
++/** Unlock a mutex */
++extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex);
++#define dwc_mutex_unlock DWC_MUTEX_UNLOCK
++
++
++/** @name Time */
++
++/** Microsecond delay.
++ *
++ * @param usecs Microseconds to delay.
++ */
++extern void DWC_UDELAY(uint32_t usecs);
++#define dwc_udelay DWC_UDELAY
++
++/** Millisecond delay.
++ *
++ * @param msecs Milliseconds to delay.
++ */
++extern void DWC_MDELAY(uint32_t msecs);
++#define dwc_mdelay DWC_MDELAY
++
++/** Non-busy waiting.
++ * Sleeps for specified number of milliseconds.
++ *
++ * @param msecs Milliseconds to sleep.
++ */
++extern void DWC_MSLEEP(uint32_t msecs);
++#define dwc_msleep DWC_MSLEEP
++
++/**
++ * Returns number of milliseconds since boot.
++ */
++extern uint32_t DWC_TIME(void);
++#define dwc_time DWC_TIME
++
++
++
++
++/* @mainpage DWC Portability and Common Library
++ *
++ * This is the documentation for the DWC Portability and Common Library.
++ *
++ * @section intro Introduction
++ *
++ * The DWC Portability library consists of wrapper calls and data structures to
++ * all low-level functions which are typically provided by the OS. The WUDEV
++ * driver uses only these functions. In order to port the WUDEV driver, only
++ * the functions in this library need to be re-implemented, with the same
++ * behavior as documented here.
++ *
++ * The Common library consists of higher level functions, which rely only on
++ * calling the functions from the DWC Portability library. These common
++ * routines are shared across modules. Some of the common libraries need to be
++ * used directly by the driver programmer when porting WUDEV. Such as the
++ * parameter and notification libraries.
++ *
++ * @section low Portability Library OS Wrapper Functions
++ *
++ * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that
++ * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of
++ * these functions are included in the dwc_os.h file.
++ *
++ * There are many functions here covering a wide array of OS services. Please
++ * see dwc_os.h for details, and implementation notes for each function.
++ *
++ * @section common Common Library Functions
++ *
++ * Any function starting with dwc and in all lowercase is a common library
++ * routine. These functions have a portable implementation and do not need to
++ * be reimplemented when porting. The common routines can be used by any
++ * driver, and some must be used by the end user to control the drivers. For
++ * example, you must use the Parameter common library in order to set the
++ * parameters in the WUDEV module.
++ *
++ * The common libraries consist of the following:
++ *
++ * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h
++ * - Parameters - Used internally and can be used by end-user. See dwc_params.h
++ * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h
++ * - Lists - Used internally and can be used by end-user. See dwc_list.h
++ * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h
++ * - Modpow - Used internally only. See dwc_modpow.h
++ * - DH - Used internally only. See dwc_dh.h
++ * - Crypto - Used internally only. See dwc_crypto.h
++ *
++ *
++ * @section prereq Prerequistes For dwc_os.h
++ * @subsection types Data Types
++ *
++ * The dwc_os.h file assumes that several low-level data types are pre defined for the
++ * compilation environment. These data types are:
++ *
++ * - uint8_t - unsigned 8-bit data type
++ * - int8_t - signed 8-bit data type
++ * - uint16_t - unsigned 16-bit data type
++ * - int16_t - signed 16-bit data type
++ * - uint32_t - unsigned 32-bit data type
++ * - int32_t - signed 32-bit data type
++ * - uint64_t - unsigned 64-bit data type
++ * - int64_t - signed 64-bit data type
++ *
++ * Ensure that these are defined before using dwc_os.h. The easiest way to do
++ * that is to modify the top of the file to include the appropriate header.
++ * This is already done for the Linux environment. If the DWC_LINUX macro is
++ * defined, the correct header will be added. A standard header <stdint.h> is
++ * also used for environments where standard C headers are available.
++ *
++ * @subsection stdarg Variable Arguments
++ *
++ * Variable arguments are provided by a standard C header <stdarg.h>. it is
++ * available in Both the Linux and ANSI C enviornment. An equivalent must be
++ * provided in your enviornment in order to use dwc_os.h with the debug and
++ * tracing message functionality.
++ *
++ * @subsection thread Threading
++ *
++ * WUDEV Core must be run on an operating system that provides for multiple
++ * threads/processes. Threading can be implemented in many ways, even in
++ * embedded systems without an operating system. At the bare minimum, the
++ * system should be able to start any number of processes at any time to handle
++ * special work. It need not be a pre-emptive system. Process context can
++ * change upon a call to a blocking function. The hardware interrupt context
++ * that calls the module's ISR() function must be differentiable from process
++ * context, even if your processes are impemented via a hardware interrupt.
++ * Further locking mechanism between process must exist (or be implemented), and
++ * process context must have a way to disable interrupts for a period of time to
++ * lock them out. If all of this exists, the functions in dwc_os.h related to
++ * threading should be able to be implemented with the defined behavior.
++ *
++ */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_OS_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/usb.h b/drivers/usb/host/dwc_common_port/usb.h
+new file mode 100644
+index 000000000000..27bda82dac2e
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/usb.h
+@@ -0,0 +1,946 @@
++/*
++ * Copyright (c) 1998 The NetBSD Foundation, Inc.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to The NetBSD Foundation
++ * by Lennart Augustsson (lennart@augustsson.net) at
++ * Carlstedt Research & Technology.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ * must display the following acknowledgement:
++ * This product includes software developed by the NetBSD
++ * Foundation, Inc. and its contributors.
++ * 4. Neither the name of The NetBSD Foundation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
++ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* Modified by Synopsys, Inc, 12/12/2007 */
++
++
++#ifndef _USB_H_
++#define _USB_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * The USB records contain some unaligned little-endian word
++ * components. The U[SG]ETW macros take care of both the alignment
++ * and endian problem and should always be used to access non-byte
++ * values.
++ */
++typedef u_int8_t uByte;
++typedef u_int8_t uWord[2];
++typedef u_int8_t uDWord[4];
++
++#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h))
++#define UCONSTW(x) { (x) & 0xff, ((x) >> 8) & 0xff }
++#define UCONSTDW(x) { (x) & 0xff, ((x) >> 8) & 0xff, \
++ ((x) >> 16) & 0xff, ((x) >> 24) & 0xff }
++
++#if 1
++#define UGETW(w) ((w)[0] | ((w)[1] << 8))
++#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8))
++#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24))
++#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \
++ (w)[1] = (u_int8_t)((v) >> 8), \
++ (w)[2] = (u_int8_t)((v) >> 16), \
++ (w)[3] = (u_int8_t)((v) >> 24))
++#else
++/*
++ * On little-endian machines that can handle unanliged accesses
++ * (e.g. i386) these macros can be replaced by the following.
++ */
++#define UGETW(w) (*(u_int16_t *)(w))
++#define USETW(w,v) (*(u_int16_t *)(w) = (v))
++#define UGETDW(w) (*(u_int32_t *)(w))
++#define USETDW(w,v) (*(u_int32_t *)(w) = (v))
++#endif
++
++/*
++ * Macros for accessing UAS IU fields, which are big-endian
++ */
++#define IUSETW2(w,h,l) ((w)[0] = (u_int8_t)(h), (w)[1] = (u_int8_t)(l))
++#define IUCONSTW(x) { ((x) >> 8) & 0xff, (x) & 0xff }
++#define IUCONSTDW(x) { ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
++ ((x) >> 8) & 0xff, (x) & 0xff }
++#define IUGETW(w) (((w)[0] << 8) | (w)[1])
++#define IUSETW(w,v) ((w)[0] = (u_int8_t)((v) >> 8), (w)[1] = (u_int8_t)(v))
++#define IUGETDW(w) (((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
++#define IUSETDW(w,v) ((w)[0] = (u_int8_t)((v) >> 24), \
++ (w)[1] = (u_int8_t)((v) >> 16), \
++ (w)[2] = (u_int8_t)((v) >> 8), \
++ (w)[3] = (u_int8_t)(v))
++
++#define UPACKED __attribute__((__packed__))
++
++typedef struct {
++ uByte bmRequestType;
++ uByte bRequest;
++ uWord wValue;
++ uWord wIndex;
++ uWord wLength;
++} UPACKED usb_device_request_t;
++
++#define UT_GET_DIR(a) ((a) & 0x80)
++#define UT_WRITE 0x00
++#define UT_READ 0x80
++
++#define UT_GET_TYPE(a) ((a) & 0x60)
++#define UT_STANDARD 0x00
++#define UT_CLASS 0x20
++#define UT_VENDOR 0x40
++
++#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
++#define UT_DEVICE 0x00
++#define UT_INTERFACE 0x01
++#define UT_ENDPOINT 0x02
++#define UT_OTHER 0x03
++
++#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE)
++#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE)
++#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT)
++#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE)
++#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE)
++#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT)
++#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE)
++#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE)
++#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER)
++#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT)
++#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE)
++#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
++#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER)
++#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT)
++#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE)
++#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE)
++#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER)
++#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT)
++#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE)
++#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
++#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER)
++#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)
++
++/* Requests */
++#define UR_GET_STATUS 0x00
++#define USTAT_STANDARD_STATUS 0x00
++#define WUSTAT_WUSB_FEATURE 0x01
++#define WUSTAT_CHANNEL_INFO 0x02
++#define WUSTAT_RECEIVED_DATA 0x03
++#define WUSTAT_MAS_AVAILABILITY 0x04
++#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05
++#define UR_CLEAR_FEATURE 0x01
++#define UR_SET_FEATURE 0x03
++#define UR_SET_AND_TEST_FEATURE 0x0c
++#define UR_SET_ADDRESS 0x05
++#define UR_GET_DESCRIPTOR 0x06
++#define UDESC_DEVICE 0x01
++#define UDESC_CONFIG 0x02
++#define UDESC_STRING 0x03
++#define UDESC_INTERFACE 0x04
++#define UDESC_ENDPOINT 0x05
++#define UDESC_SS_USB_COMPANION 0x30
++#define UDESC_DEVICE_QUALIFIER 0x06
++#define UDESC_OTHER_SPEED_CONFIGURATION 0x07
++#define UDESC_INTERFACE_POWER 0x08
++#define UDESC_OTG 0x09
++#define WUDESC_SECURITY 0x0c
++#define WUDESC_KEY 0x0d
++#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf)
++#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4)
++#define WUD_KEY_TYPE_ASSOC 0x01
++#define WUD_KEY_TYPE_GTK 0x02
++#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6)
++#define WUD_KEY_ORIGIN_HOST 0x00
++#define WUD_KEY_ORIGIN_DEVICE 0x01
++#define WUDESC_ENCRYPTION_TYPE 0x0e
++#define WUDESC_BOS 0x0f
++#define WUDESC_DEVICE_CAPABILITY 0x10
++#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11
++#define UDESC_BOS 0x0f
++#define UDESC_DEVICE_CAPABILITY 0x10
++#define UDESC_CS_DEVICE 0x21 /* class specific */
++#define UDESC_CS_CONFIG 0x22
++#define UDESC_CS_STRING 0x23
++#define UDESC_CS_INTERFACE 0x24
++#define UDESC_CS_ENDPOINT 0x25
++#define UDESC_HUB 0x29
++#define UR_SET_DESCRIPTOR 0x07
++#define UR_GET_CONFIG 0x08
++#define UR_SET_CONFIG 0x09
++#define UR_GET_INTERFACE 0x0a
++#define UR_SET_INTERFACE 0x0b
++#define UR_SYNCH_FRAME 0x0c
++#define WUR_SET_ENCRYPTION 0x0d
++#define WUR_GET_ENCRYPTION 0x0e
++#define WUR_SET_HANDSHAKE 0x0f
++#define WUR_GET_HANDSHAKE 0x10
++#define WUR_SET_CONNECTION 0x11
++#define WUR_SET_SECURITY_DATA 0x12
++#define WUR_GET_SECURITY_DATA 0x13
++#define WUR_SET_WUSB_DATA 0x14
++#define WUDATA_DRPIE_INFO 0x01
++#define WUDATA_TRANSMIT_DATA 0x02
++#define WUDATA_TRANSMIT_PARAMS 0x03
++#define WUDATA_RECEIVE_PARAMS 0x04
++#define WUDATA_TRANSMIT_POWER 0x05
++#define WUR_LOOPBACK_DATA_WRITE 0x15
++#define WUR_LOOPBACK_DATA_READ 0x16
++#define WUR_SET_INTERFACE_DS 0x17
++
++/* Feature numbers */
++#define UF_ENDPOINT_HALT 0
++#define UF_DEVICE_REMOTE_WAKEUP 1
++#define UF_TEST_MODE 2
++#define UF_DEVICE_B_HNP_ENABLE 3
++#define UF_DEVICE_A_HNP_SUPPORT 4
++#define UF_DEVICE_A_ALT_HNP_SUPPORT 5
++#define WUF_WUSB 3
++#define WUF_TX_DRPIE 0x0
++#define WUF_DEV_XMIT_PACKET 0x1
++#define WUF_COUNT_PACKETS 0x2
++#define WUF_CAPTURE_PACKETS 0x3
++#define UF_FUNCTION_SUSPEND 0
++#define UF_U1_ENABLE 48
++#define UF_U2_ENABLE 49
++#define UF_LTM_ENABLE 50
++
++/* Class requests from the USB 2.0 hub spec, table 11-15 */
++#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE)
++#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE)
++#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR)
++#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS)
++#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS)
++#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE)
++#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE)
++#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE)
++
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bDescriptorSubtype;
++} UPACKED usb_descriptor_t;
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++} UPACKED usb_descriptor_header_t;
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uWord bcdUSB;
++#define UD_USB_2_0 0x0200
++#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0)
++ uByte bDeviceClass;
++ uByte bDeviceSubClass;
++ uByte bDeviceProtocol;
++ uByte bMaxPacketSize;
++ /* The fields below are not part of the initial descriptor. */
++ uWord idVendor;
++ uWord idProduct;
++ uWord bcdDevice;
++ uByte iManufacturer;
++ uByte iProduct;
++ uByte iSerialNumber;
++ uByte bNumConfigurations;
++} UPACKED usb_device_descriptor_t;
++#define USB_DEVICE_DESCRIPTOR_SIZE 18
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uWord wTotalLength;
++ uByte bNumInterface;
++ uByte bConfigurationValue;
++ uByte iConfiguration;
++#define UC_ATT_ONE (1 << 7) /* must be set */
++#define UC_ATT_SELFPOWER (1 << 6) /* self powered */
++#define UC_ATT_WAKEUP (1 << 5) /* can wakeup */
++#define UC_ATT_BATTERY (1 << 4) /* battery powered */
++ uByte bmAttributes;
++#define UC_BUS_POWERED 0x80
++#define UC_SELF_POWERED 0x40
++#define UC_REMOTE_WAKEUP 0x20
++ uByte bMaxPower; /* max current in 2 mA units */
++#define UC_POWER_FACTOR 2
++} UPACKED usb_config_descriptor_t;
++#define USB_CONFIG_DESCRIPTOR_SIZE 9
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bInterfaceNumber;
++ uByte bAlternateSetting;
++ uByte bNumEndpoints;
++ uByte bInterfaceClass;
++ uByte bInterfaceSubClass;
++ uByte bInterfaceProtocol;
++ uByte iInterface;
++} UPACKED usb_interface_descriptor_t;
++#define USB_INTERFACE_DESCRIPTOR_SIZE 9
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bEndpointAddress;
++#define UE_GET_DIR(a) ((a) & 0x80)
++#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7))
++#define UE_DIR_IN 0x80
++#define UE_DIR_OUT 0x00
++#define UE_ADDR 0x0f
++#define UE_GET_ADDR(a) ((a) & UE_ADDR)
++ uByte bmAttributes;
++#define UE_XFERTYPE 0x03
++#define UE_CONTROL 0x00
++#define UE_ISOCHRONOUS 0x01
++#define UE_BULK 0x02
++#define UE_INTERRUPT 0x03
++#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE)
++#define UE_ISO_TYPE 0x0c
++#define UE_ISO_ASYNC 0x04
++#define UE_ISO_ADAPT 0x08
++#define UE_ISO_SYNC 0x0c
++#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE)
++ uWord wMaxPacketSize;
++ uByte bInterval;
++} UPACKED usb_endpoint_descriptor_t;
++#define USB_ENDPOINT_DESCRIPTOR_SIZE 7
++
++typedef struct ss_endpoint_companion_descriptor {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bMaxBurst;
++#define USSE_GET_MAX_STREAMS(a) ((a) & 0x1f)
++#define USSE_SET_MAX_STREAMS(a, b) ((a) | ((b) & 0x1f))
++#define USSE_GET_MAX_PACKET_NUM(a) ((a) & 0x03)
++#define USSE_SET_MAX_PACKET_NUM(a, b) ((a) | ((b) & 0x03))
++ uByte bmAttributes;
++ uWord wBytesPerInterval;
++} UPACKED ss_endpoint_companion_descriptor_t;
++#define USB_SS_ENDPOINT_COMPANION_DESCRIPTOR_SIZE 6
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uWord bString[127];
++} UPACKED usb_string_descriptor_t;
++#define USB_MAX_STRING_LEN 128
++#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */
++
++/* Hub specific request */
++#define UR_GET_BUS_STATE 0x02
++#define UR_CLEAR_TT_BUFFER 0x08
++#define UR_RESET_TT 0x09
++#define UR_GET_TT_STATE 0x0a
++#define UR_STOP_TT 0x0b
++
++/* Hub features */
++#define UHF_C_HUB_LOCAL_POWER 0
++#define UHF_C_HUB_OVER_CURRENT 1
++#define UHF_PORT_CONNECTION 0
++#define UHF_PORT_ENABLE 1
++#define UHF_PORT_SUSPEND 2
++#define UHF_PORT_OVER_CURRENT 3
++#define UHF_PORT_RESET 4
++#define UHF_PORT_L1 5
++#define UHF_PORT_POWER 8
++#define UHF_PORT_LOW_SPEED 9
++#define UHF_PORT_HIGH_SPEED 10
++#define UHF_C_PORT_CONNECTION 16
++#define UHF_C_PORT_ENABLE 17
++#define UHF_C_PORT_SUSPEND 18
++#define UHF_C_PORT_OVER_CURRENT 19
++#define UHF_C_PORT_RESET 20
++#define UHF_C_PORT_L1 23
++#define UHF_PORT_TEST 21
++#define UHF_PORT_INDICATOR 22
++
++typedef struct {
++ uByte bDescLength;
++ uByte bDescriptorType;
++ uByte bNbrPorts;
++ uWord wHubCharacteristics;
++#define UHD_PWR 0x0003
++#define UHD_PWR_GANGED 0x0000
++#define UHD_PWR_INDIVIDUAL 0x0001
++#define UHD_PWR_NO_SWITCH 0x0002
++#define UHD_COMPOUND 0x0004
++#define UHD_OC 0x0018
++#define UHD_OC_GLOBAL 0x0000
++#define UHD_OC_INDIVIDUAL 0x0008
++#define UHD_OC_NONE 0x0010
++#define UHD_TT_THINK 0x0060
++#define UHD_TT_THINK_8 0x0000
++#define UHD_TT_THINK_16 0x0020
++#define UHD_TT_THINK_24 0x0040
++#define UHD_TT_THINK_32 0x0060
++#define UHD_PORT_IND 0x0080
++ uByte bPwrOn2PwrGood; /* delay in 2 ms units */
++#define UHD_PWRON_FACTOR 2
++ uByte bHubContrCurrent;
++ uByte DeviceRemovable[32]; /* max 255 ports */
++#define UHD_NOT_REMOV(desc, i) \
++ (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1)
++ /* deprecated */ uByte PortPowerCtrlMask[1];
++} UPACKED usb_hub_descriptor_t;
++#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uWord bcdUSB;
++ uByte bDeviceClass;
++ uByte bDeviceSubClass;
++ uByte bDeviceProtocol;
++ uByte bMaxPacketSize0;
++ uByte bNumConfigurations;
++ uByte bReserved;
++} UPACKED usb_device_qualifier_t;
++#define USB_DEVICE_QUALIFIER_SIZE 10
++
++typedef struct {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bmAttributes;
++#define UOTG_SRP 0x01
++#define UOTG_HNP 0x02
++} UPACKED usb_otg_descriptor_t;
++
++/* OTG feature selectors */
++#define UOTG_B_HNP_ENABLE 3
++#define UOTG_A_HNP_SUPPORT 4
++#define UOTG_A_ALT_HNP_SUPPORT 5
++
++typedef struct {
++ uWord wStatus;
++/* Device status flags */
++#define UDS_SELF_POWERED 0x0001
++#define UDS_REMOTE_WAKEUP 0x0002
++/* Endpoint status flags */
++#define UES_HALT 0x0001
++} UPACKED usb_status_t;
++
++typedef struct {
++ uWord wHubStatus;
++#define UHS_LOCAL_POWER 0x0001
++#define UHS_OVER_CURRENT 0x0002
++ uWord wHubChange;
++} UPACKED usb_hub_status_t;
++
++typedef struct {
++ uWord wPortStatus;
++#define UPS_CURRENT_CONNECT_STATUS 0x0001
++#define UPS_PORT_ENABLED 0x0002
++#define UPS_SUSPEND 0x0004
++#define UPS_OVERCURRENT_INDICATOR 0x0008
++#define UPS_RESET 0x0010
++#define UPS_PORT_POWER 0x0100
++#define UPS_LOW_SPEED 0x0200
++#define UPS_HIGH_SPEED 0x0400
++#define UPS_PORT_TEST 0x0800
++#define UPS_PORT_INDICATOR 0x1000
++ uWord wPortChange;
++#define UPS_C_CONNECT_STATUS 0x0001
++#define UPS_C_PORT_ENABLED 0x0002
++#define UPS_C_SUSPEND 0x0004
++#define UPS_C_OVERCURRENT_INDICATOR 0x0008
++#define UPS_C_PORT_RESET 0x0010
++} UPACKED usb_port_status_t;
++
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++/* Device class codes */
++#define UDCLASS_IN_INTERFACE 0x00
++#define UDCLASS_COMM 0x02
++#define UDCLASS_HUB 0x09
++#define UDSUBCLASS_HUB 0x00
++#define UDPROTO_FSHUB 0x00
++#define UDPROTO_HSHUBSTT 0x01
++#define UDPROTO_HSHUBMTT 0x02
++#define UDCLASS_DIAGNOSTIC 0xdc
++#define UDCLASS_WIRELESS 0xe0
++#define UDSUBCLASS_RF 0x01
++#define UDPROTO_BLUETOOTH 0x01
++#define UDCLASS_VENDOR 0xff
++
++/* Interface class codes */
++#define UICLASS_UNSPEC 0x00
++
++#define UICLASS_AUDIO 0x01
++#define UISUBCLASS_AUDIOCONTROL 1
++#define UISUBCLASS_AUDIOSTREAM 2
++#define UISUBCLASS_MIDISTREAM 3
++
++#define UICLASS_CDC 0x02 /* communication */
++#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1
++#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2
++#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3
++#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4
++#define UISUBCLASS_CAPI_CONTROLMODEL 5
++#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6
++#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7
++#define UIPROTO_CDC_AT 1
++
++#define UICLASS_HID 0x03
++#define UISUBCLASS_BOOT 1
++#define UIPROTO_BOOT_KEYBOARD 1
++
++#define UICLASS_PHYSICAL 0x05
++
++#define UICLASS_IMAGE 0x06
++
++#define UICLASS_PRINTER 0x07
++#define UISUBCLASS_PRINTER 1
++#define UIPROTO_PRINTER_UNI 1
++#define UIPROTO_PRINTER_BI 2
++#define UIPROTO_PRINTER_1284 3
++
++#define UICLASS_MASS 0x08
++#define UISUBCLASS_RBC 1
++#define UISUBCLASS_SFF8020I 2
++#define UISUBCLASS_QIC157 3
++#define UISUBCLASS_UFI 4
++#define UISUBCLASS_SFF8070I 5
++#define UISUBCLASS_SCSI 6
++#define UIPROTO_MASS_CBI_I 0
++#define UIPROTO_MASS_CBI 1
++#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */
++#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */
++
++#define UICLASS_HUB 0x09
++#define UISUBCLASS_HUB 0
++#define UIPROTO_FSHUB 0
++#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */
++#define UIPROTO_HSHUBMTT 1
++
++#define UICLASS_CDC_DATA 0x0a
++#define UISUBCLASS_DATA 0
++#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */
++#define UIPROTO_DATA_HDLC 0x31 /* HDLC */
++#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */
++#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */
++#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */
++#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */
++#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */
++#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */
++#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */
++#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */
++#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */
++#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/
++#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */
++
++#define UICLASS_SMARTCARD 0x0b
++
++/*#define UICLASS_FIRM_UPD 0x0c*/
++
++#define UICLASS_SECURITY 0x0d
++
++#define UICLASS_DIAGNOSTIC 0xdc
++
++#define UICLASS_WIRELESS 0xe0
++#define UISUBCLASS_RF 0x01
++#define UIPROTO_BLUETOOTH 0x01
++
++#define UICLASS_APPL_SPEC 0xfe
++#define UISUBCLASS_FIRMWARE_DOWNLOAD 1
++#define UISUBCLASS_IRDA 2
++#define UIPROTO_IRDA 0
++
++#define UICLASS_VENDOR 0xff
++
++#define USB_HUB_MAX_DEPTH 5
++
++/*
++ * Minimum time a device needs to be powered down to go through
++ * a power cycle. XXX Are these time in the spec?
++ */
++#define USB_POWER_DOWN_TIME 200 /* ms */
++#define USB_PORT_POWER_DOWN_TIME 100 /* ms */
++
++#if 0
++/* These are the values from the spec. */
++#define USB_PORT_RESET_DELAY 10 /* ms */
++#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */
++#define USB_PORT_RESET_RECOVERY 10 /* ms */
++#define USB_PORT_POWERUP_DELAY 100 /* ms */
++#define USB_SET_ADDRESS_SETTLE 2 /* ms */
++#define USB_RESUME_DELAY (20*5) /* ms */
++#define USB_RESUME_WAIT 10 /* ms */
++#define USB_RESUME_RECOVERY 10 /* ms */
++#define USB_EXTRA_POWER_UP_TIME 0 /* ms */
++#else
++/* Allow for marginal (i.e. non-conforming) devices. */
++#define USB_PORT_RESET_DELAY 50 /* ms */
++#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */
++#define USB_PORT_RESET_RECOVERY 250 /* ms */
++#define USB_PORT_POWERUP_DELAY 300 /* ms */
++#define USB_SET_ADDRESS_SETTLE 10 /* ms */
++#define USB_RESUME_DELAY (50*5) /* ms */
++#define USB_RESUME_WAIT 50 /* ms */
++#define USB_RESUME_RECOVERY 50 /* ms */
++#define USB_EXTRA_POWER_UP_TIME 20 /* ms */
++#endif
++
++#define USB_MIN_POWER 100 /* mA */
++#define USB_MAX_POWER 500 /* mA */
++
++#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
++
++#define USB_UNCONFIG_NO 0
++#define USB_UNCONFIG_INDEX (-1)
++
++/*** ioctl() related stuff ***/
++
++struct usb_ctl_request {
++ int ucr_addr;
++ usb_device_request_t ucr_request;
++ void *ucr_data;
++ int ucr_flags;
++#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */
++ int ucr_actlen; /* actual length transferred */
++};
++
++struct usb_alt_interface {
++ int uai_config_index;
++ int uai_interface_index;
++ int uai_alt_no;
++};
++
++#define USB_CURRENT_CONFIG_INDEX (-1)
++#define USB_CURRENT_ALT_INDEX (-1)
++
++struct usb_config_desc {
++ int ucd_config_index;
++ usb_config_descriptor_t ucd_desc;
++};
++
++struct usb_interface_desc {
++ int uid_config_index;
++ int uid_interface_index;
++ int uid_alt_index;
++ usb_interface_descriptor_t uid_desc;
++};
++
++struct usb_endpoint_desc {
++ int ued_config_index;
++ int ued_interface_index;
++ int ued_alt_index;
++ int ued_endpoint_index;
++ usb_endpoint_descriptor_t ued_desc;
++};
++
++struct usb_full_desc {
++ int ufd_config_index;
++ u_int ufd_size;
++ u_char *ufd_data;
++};
++
++struct usb_string_desc {
++ int usd_string_index;
++ int usd_language_id;
++ usb_string_descriptor_t usd_desc;
++};
++
++struct usb_ctl_report_desc {
++ int ucrd_size;
++ u_char ucrd_data[1024]; /* filled data size will vary */
++};
++
++typedef struct { u_int32_t cookie; } usb_event_cookie_t;
++
++#define USB_MAX_DEVNAMES 4
++#define USB_MAX_DEVNAMELEN 16
++struct usb_device_info {
++ u_int8_t udi_bus;
++ u_int8_t udi_addr; /* device address */
++ usb_event_cookie_t udi_cookie;
++ char udi_product[USB_MAX_STRING_LEN];
++ char udi_vendor[USB_MAX_STRING_LEN];
++ char udi_release[8];
++ u_int16_t udi_productNo;
++ u_int16_t udi_vendorNo;
++ u_int16_t udi_releaseNo;
++ u_int8_t udi_class;
++ u_int8_t udi_subclass;
++ u_int8_t udi_protocol;
++ u_int8_t udi_config;
++ u_int8_t udi_speed;
++#define USB_SPEED_UNKNOWN 0
++#define USB_SPEED_LOW 1
++#define USB_SPEED_FULL 2
++#define USB_SPEED_HIGH 3
++#define USB_SPEED_VARIABLE 4
++#define USB_SPEED_SUPER 5
++ int udi_power; /* power consumption in mA, 0 if selfpowered */
++ int udi_nports;
++ char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];
++ u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */
++#define USB_PORT_ENABLED 0xff
++#define USB_PORT_SUSPENDED 0xfe
++#define USB_PORT_POWERED 0xfd
++#define USB_PORT_DISABLED 0xfc
++};
++
++struct usb_ctl_report {
++ int ucr_report;
++ u_char ucr_data[1024]; /* filled data size will vary */
++};
++
++struct usb_device_stats {
++ u_long uds_requests[4]; /* indexed by transfer type UE_* */
++};
++
++#define WUSB_MIN_IE 0x80
++#define WUSB_WCTA_IE 0x80
++#define WUSB_WCONNECTACK_IE 0x81
++#define WUSB_WHOSTINFO_IE 0x82
++#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3)
++#define WUHI_CA_RECONN 0x00
++#define WUHI_CA_LIMITED 0x01
++#define WUHI_CA_ALL 0x03
++#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3)
++#define WUSB_WCHCHANGEANNOUNCE_IE 0x83
++#define WUSB_WDEV_DISCONNECT_IE 0x84
++#define WUSB_WHOST_DISCONNECT_IE 0x85
++#define WUSB_WRELEASE_CHANNEL_IE 0x86
++#define WUSB_WWORK_IE 0x87
++#define WUSB_WCHANNEL_STOP_IE 0x88
++#define WUSB_WDEV_KEEPALIVE_IE 0x89
++#define WUSB_WISOCH_DISCARD_IE 0x8A
++#define WUSB_WRESETDEVICE_IE 0x8B
++#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C
++#define WUSB_MAX_IE 0x8C
++
++/* Device Notification Types */
++
++#define WUSB_DN_MIN 0x01
++#define WUSB_DN_CONNECT 0x01
++# define WUSB_DA_OLDCONN 0x00
++# define WUSB_DA_NEWCONN 0x01
++# define WUSB_DA_SELF_BEACON 0x02
++# define WUSB_DA_DIR_BEACON 0x04
++# define WUSB_DA_NO_BEACON 0x06
++#define WUSB_DN_DISCONNECT 0x02
++#define WUSB_DN_EPRDY 0x03
++#define WUSB_DN_MASAVAILCHANGED 0x04
++#define WUSB_DN_REMOTEWAKEUP 0x05
++#define WUSB_DN_SLEEP 0x06
++#define WUSB_DN_ALIVE 0x07
++#define WUSB_DN_MAX 0x07
++
++#ifdef _MSC_VER
++#include <pshpack1.h>
++#endif
++
++/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */
++typedef struct wusb_hndshk_data {
++ uByte bMessageNumber;
++ uByte bStatus;
++ uByte tTKID[3];
++ uByte bReserved;
++ uByte CDID[16];
++ uByte Nonce[16];
++ uByte MIC[8];
++} UPACKED wusb_hndshk_data_t;
++#define WUSB_HANDSHAKE_LEN_FOR_MIC 38
++
++/* WUSB Connection Context */
++typedef struct wusb_conn_context {
++ uByte CHID [16];
++ uByte CDID [16];
++ uByte CK [16];
++} UPACKED wusb_conn_context_t;
++
++/* WUSB Security Descriptor */
++typedef struct wusb_security_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uWord wTotalLength;
++ uByte bNumEncryptionTypes;
++} UPACKED wusb_security_desc_t;
++
++/* WUSB Encryption Type Descriptor */
++typedef struct wusb_encrypt_type_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++
++ uByte bEncryptionType;
++#define WUETD_UNSECURE 0
++#define WUETD_WIRED 1
++#define WUETD_CCM_1 2
++#define WUETD_RSA_1 3
++
++ uByte bEncryptionValue;
++ uByte bAuthKeyIndex;
++} UPACKED wusb_encrypt_type_desc_t;
++
++/* WUSB Key Descriptor */
++typedef struct wusb_key_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte tTKID[3];
++ uByte bReserved;
++ uByte KeyData[1]; /* variable length */
++} UPACKED wusb_key_desc_t;
++
++/* WUSB BOS Descriptor (Binary device Object Store) */
++typedef struct wusb_bos_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uWord wTotalLength;
++ uByte bNumDeviceCaps;
++} UPACKED wusb_bos_desc_t;
++
++#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02
++typedef struct usb_dev_cap_20_ext_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bDevCapabilityType;
++#define USB_20_EXT_LPM 0x02
++ uDWord bmAttributes;
++} UPACKED usb_dev_cap_20_ext_desc_t;
++
++#define USB_DEVICE_CAPABILITY_SS_USB 0x03
++typedef struct usb_dev_cap_ss_usb {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bDevCapabilityType;
++#define USB_DC_SS_USB_LTM_CAPABLE 0x02
++ uByte bmAttributes;
++#define USB_DC_SS_USB_SPEED_SUPPORT_LOW 0x01
++#define USB_DC_SS_USB_SPEED_SUPPORT_FULL 0x02
++#define USB_DC_SS_USB_SPEED_SUPPORT_HIGH 0x04
++#define USB_DC_SS_USB_SPEED_SUPPORT_SS 0x08
++ uWord wSpeedsSupported;
++ uByte bFunctionalitySupport;
++ uByte bU1DevExitLat;
++ uWord wU2DevExitLat;
++} UPACKED usb_dev_cap_ss_usb_t;
++
++#define USB_DEVICE_CAPABILITY_CONTAINER_ID 0x04
++typedef struct usb_dev_cap_container_id {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bDevCapabilityType;
++ uByte bReserved;
++ uByte containerID[16];
++} UPACKED usb_dev_cap_container_id_t;
++
++/* Device Capability Type Codes */
++#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01
++
++/* Device Capability Descriptor */
++typedef struct wusb_dev_cap_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bDevCapabilityType;
++ uByte caps[1]; /* Variable length */
++} UPACKED wusb_dev_cap_desc_t;
++
++/* Device Capability Descriptor */
++typedef struct wusb_dev_cap_uwb_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bDevCapabilityType;
++ uByte bmAttributes;
++ uWord wPHYRates; /* Bitmap */
++ uByte bmTFITXPowerInfo;
++ uByte bmFFITXPowerInfo;
++ uWord bmBandGroup;
++ uByte bReserved;
++} UPACKED wusb_dev_cap_uwb_desc_t;
++
++/* Wireless USB Endpoint Companion Descriptor */
++typedef struct wusb_endpoint_companion_desc {
++ uByte bLength;
++ uByte bDescriptorType;
++ uByte bMaxBurst;
++ uByte bMaxSequence;
++ uWord wMaxStreamDelay;
++ uWord wOverTheAirPacketSize;
++ uByte bOverTheAirInterval;
++ uByte bmCompAttributes;
++} UPACKED wusb_endpoint_companion_desc_t;
++
++/* Wireless USB Numeric Association M1 Data Structure */
++typedef struct wusb_m1_data {
++ uByte version;
++ uWord langId;
++ uByte deviceFriendlyNameLength;
++ uByte sha_256_m3[32];
++ uByte deviceFriendlyName[256];
++} UPACKED wusb_m1_data_t;
++
++typedef struct wusb_m2_data {
++ uByte version;
++ uWord langId;
++ uByte hostFriendlyNameLength;
++ uByte pkh[384];
++ uByte hostFriendlyName[256];
++} UPACKED wusb_m2_data_t;
++
++typedef struct wusb_m3_data {
++ uByte pkd[384];
++ uByte nd;
++} UPACKED wusb_m3_data_t;
++
++typedef struct wusb_m4_data {
++ uDWord _attributeTypeIdAndLength_1;
++ uWord associationTypeId;
++
++ uDWord _attributeTypeIdAndLength_2;
++ uWord associationSubTypeId;
++
++ uDWord _attributeTypeIdAndLength_3;
++ uDWord length;
++
++ uDWord _attributeTypeIdAndLength_4;
++ uDWord associationStatus;
++
++ uDWord _attributeTypeIdAndLength_5;
++ uByte chid[16];
++
++ uDWord _attributeTypeIdAndLength_6;
++ uByte cdid[16];
++
++ uDWord _attributeTypeIdAndLength_7;
++ uByte bandGroups[2];
++} UPACKED wusb_m4_data_t;
++
++#ifdef _MSC_VER
++#include <poppack.h>
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _USB_H_ */
+diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile
+new file mode 100644
+index 000000000000..e7bdd12015fe
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/Makefile
+@@ -0,0 +1,82 @@
++#
++# Makefile for DWC_otg Highspeed USB controller driver
++#
++
++ifneq ($(KERNELRELEASE),)
++
++# Use the BUS_INTERFACE variable to compile the software for either
++# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus.
++ifeq ($(BUS_INTERFACE),)
++# BUS_INTERFACE = -DPCI_INTERFACE
++# BUS_INTERFACE = -DLM_INTERFACE
++ BUS_INTERFACE = -DPLATFORM_INTERFACE
++endif
++
++#ccflags-y += -DDEBUG
++#ccflags-y += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs
++
++# Use one of the following flags to compile the software in host-only or
++# device-only mode.
++#ccflags-y += -DDWC_HOST_ONLY
++#ccflags-y += -DDWC_DEVICE_ONLY
++
++ccflags-y += -Dlinux -DDWC_HS_ELECT_TST
++#ccflags-y += -DDWC_EN_ISOC
++ccflags-y += -I$(obj)/../dwc_common_port
++#ccflags-y += -I$(PORTLIB)
++ccflags-y += -DDWC_LINUX
++ccflags-y += $(CFI)
++ccflags-y += $(BUS_INTERFACE)
++#ccflags-y += -DDWC_DEV_SRPCAP
++
++obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o
++
++dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o
++dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
++dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
++dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o
++dwc_otg-objs += dwc_otg_adp.o
++dwc_otg-objs += dwc_otg_fiq_fsm.o
++dwc_otg-objs += dwc_otg_fiq_stub.o
++ifneq ($(CFI),)
++dwc_otg-objs += dwc_otg_cfi.o
++endif
++
++kernrelwd := $(subst ., ,$(KERNELRELEASE))
++kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
++
++ifneq ($(kernrel3),2.6.20)
++ccflags-y += $(CPPFLAGS)
++endif
++
++else
++
++PWD := $(shell pwd)
++PORTLIB := $(PWD)/../dwc_common_port
++
++# Command paths
++CTAGS := $(CTAGS)
++DOXYGEN := $(DOXYGEN)
++
++default: portlib
++ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
++
++install: default
++ $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install
++ $(MAKE) -C$(KDIR) M=$(PWD) modules_install
++
++portlib:
++ $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
++ cp $(PORTLIB)/Module.symvers $(PWD)/
++
++docs: $(wildcard *.[hc]) doc/doxygen.cfg
++ $(DOXYGEN) doc/doxygen.cfg
++
++tags: $(wildcard *.[hc])
++ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
++
++
++clean:
++ rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers
++
++endif
+diff --git a/drivers/usb/host/dwc_otg/doc/doxygen.cfg b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
+new file mode 100644
+index 000000000000..712b057ef7c2
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg
+@@ -0,0 +1,224 @@
++# Doxyfile 1.3.9.1
++
++#---------------------------------------------------------------------------
++# Project related configuration options
++#---------------------------------------------------------------------------
++PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver"
++PROJECT_NUMBER = v3.00a
++OUTPUT_DIRECTORY = ./doc/
++CREATE_SUBDIRS = NO
++OUTPUT_LANGUAGE = English
++BRIEF_MEMBER_DESC = YES
++REPEAT_BRIEF = YES
++ABBREVIATE_BRIEF = "The $name class" \
++ "The $name widget" \
++ "The $name file" \
++ is \
++ provides \
++ specifies \
++ contains \
++ represents \
++ a \
++ an \
++ the
++ALWAYS_DETAILED_SEC = NO
++INLINE_INHERITED_MEMB = NO
++FULL_PATH_NAMES = NO
++STRIP_FROM_PATH =
++STRIP_FROM_INC_PATH =
++SHORT_NAMES = NO
++JAVADOC_AUTOBRIEF = YES
++MULTILINE_CPP_IS_BRIEF = NO
++INHERIT_DOCS = YES
++DISTRIBUTE_GROUP_DOC = NO
++TAB_SIZE = 8
++ALIASES =
++OPTIMIZE_OUTPUT_FOR_C = YES
++OPTIMIZE_OUTPUT_JAVA = NO
++SUBGROUPING = YES
++#---------------------------------------------------------------------------
++# Build related configuration options
++#---------------------------------------------------------------------------
++EXTRACT_ALL = NO
++EXTRACT_PRIVATE = YES
++EXTRACT_STATIC = YES
++EXTRACT_LOCAL_CLASSES = YES
++EXTRACT_LOCAL_METHODS = NO
++HIDE_UNDOC_MEMBERS = NO
++HIDE_UNDOC_CLASSES = NO
++HIDE_FRIEND_COMPOUNDS = NO
++HIDE_IN_BODY_DOCS = NO
++INTERNAL_DOCS = NO
++CASE_SENSE_NAMES = NO
++HIDE_SCOPE_NAMES = NO
++SHOW_INCLUDE_FILES = YES
++INLINE_INFO = YES
++SORT_MEMBER_DOCS = NO
++SORT_BRIEF_DOCS = NO
++SORT_BY_SCOPE_NAME = NO
++GENERATE_TODOLIST = YES
++GENERATE_TESTLIST = YES
++GENERATE_BUGLIST = YES
++GENERATE_DEPRECATEDLIST= YES
++ENABLED_SECTIONS =
++MAX_INITIALIZER_LINES = 30
++SHOW_USED_FILES = YES
++SHOW_DIRECTORIES = YES
++#---------------------------------------------------------------------------
++# configuration options related to warning and progress messages
++#---------------------------------------------------------------------------
++QUIET = YES
++WARNINGS = YES
++WARN_IF_UNDOCUMENTED = NO
++WARN_IF_DOC_ERROR = YES
++WARN_FORMAT = "$file:$line: $text"
++WARN_LOGFILE =
++#---------------------------------------------------------------------------
++# configuration options related to the input files
++#---------------------------------------------------------------------------
++INPUT = .
++FILE_PATTERNS = *.c \
++ *.h \
++ ./linux/*.c \
++ ./linux/*.h
++RECURSIVE = NO
++EXCLUDE = ./test/ \
++ ./dwc_otg/.AppleDouble/
++EXCLUDE_SYMLINKS = YES
++EXCLUDE_PATTERNS = *.mod.*
++EXAMPLE_PATH =
++EXAMPLE_PATTERNS = *
++EXAMPLE_RECURSIVE = NO
++IMAGE_PATH =
++INPUT_FILTER =
++FILTER_PATTERNS =
++FILTER_SOURCE_FILES = NO
++#---------------------------------------------------------------------------
++# configuration options related to source browsing
++#---------------------------------------------------------------------------
++SOURCE_BROWSER = YES
++INLINE_SOURCES = NO
++STRIP_CODE_COMMENTS = YES
++REFERENCED_BY_RELATION = NO
++REFERENCES_RELATION = NO
++VERBATIM_HEADERS = NO
++#---------------------------------------------------------------------------
++# configuration options related to the alphabetical class index
++#---------------------------------------------------------------------------
++ALPHABETICAL_INDEX = NO
++COLS_IN_ALPHA_INDEX = 5
++IGNORE_PREFIX =
++#---------------------------------------------------------------------------
++# configuration options related to the HTML output
++#---------------------------------------------------------------------------
++GENERATE_HTML = YES
++HTML_OUTPUT = html
++HTML_FILE_EXTENSION = .html
++HTML_HEADER =
++HTML_FOOTER =
++HTML_STYLESHEET =
++HTML_ALIGN_MEMBERS = YES
++GENERATE_HTMLHELP = NO
++CHM_FILE =
++HHC_LOCATION =
++GENERATE_CHI = NO
++BINARY_TOC = NO
++TOC_EXPAND = NO
++DISABLE_INDEX = NO
++ENUM_VALUES_PER_LINE = 4
++GENERATE_TREEVIEW = YES
++TREEVIEW_WIDTH = 250
++#---------------------------------------------------------------------------
++# configuration options related to the LaTeX output
++#---------------------------------------------------------------------------
++GENERATE_LATEX = NO
++LATEX_OUTPUT = latex
++LATEX_CMD_NAME = latex
++MAKEINDEX_CMD_NAME = makeindex
++COMPACT_LATEX = NO
++PAPER_TYPE = a4wide
++EXTRA_PACKAGES =
++LATEX_HEADER =
++PDF_HYPERLINKS = NO
++USE_PDFLATEX = NO
++LATEX_BATCHMODE = NO
++LATEX_HIDE_INDICES = NO
++#---------------------------------------------------------------------------
++# configuration options related to the RTF output
++#---------------------------------------------------------------------------
++GENERATE_RTF = NO
++RTF_OUTPUT = rtf
++COMPACT_RTF = NO
++RTF_HYPERLINKS = NO
++RTF_STYLESHEET_FILE =
++RTF_EXTENSIONS_FILE =
++#---------------------------------------------------------------------------
++# configuration options related to the man page output
++#---------------------------------------------------------------------------
++GENERATE_MAN = NO
++MAN_OUTPUT = man
++MAN_EXTENSION = .3
++MAN_LINKS = NO
++#---------------------------------------------------------------------------
++# configuration options related to the XML output
++#---------------------------------------------------------------------------
++GENERATE_XML = NO
++XML_OUTPUT = xml
++XML_SCHEMA =
++XML_DTD =
++XML_PROGRAMLISTING = YES
++#---------------------------------------------------------------------------
++# configuration options for the AutoGen Definitions output
++#---------------------------------------------------------------------------
++GENERATE_AUTOGEN_DEF = NO
++#---------------------------------------------------------------------------
++# configuration options related to the Perl module output
++#---------------------------------------------------------------------------
++GENERATE_PERLMOD = NO
++PERLMOD_LATEX = NO
++PERLMOD_PRETTY = YES
++PERLMOD_MAKEVAR_PREFIX =
++#---------------------------------------------------------------------------
++# Configuration options related to the preprocessor
++#---------------------------------------------------------------------------
++ENABLE_PREPROCESSING = YES
++MACRO_EXPANSION = YES
++EXPAND_ONLY_PREDEF = YES
++SEARCH_INCLUDES = YES
++INCLUDE_PATH =
++INCLUDE_FILE_PATTERNS =
++PREDEFINED = DEVICE_ATTR DWC_EN_ISOC
++EXPAND_AS_DEFINED = DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW DWC_OTG_DEVICE_ATTR_BITFIELD_STORE DWC_OTG_DEVICE_ATTR_BITFIELD_RW DWC_OTG_DEVICE_ATTR_BITFIELD_RO DWC_OTG_DEVICE_ATTR_REG_SHOW DWC_OTG_DEVICE_ATTR_REG_STORE DWC_OTG_DEVICE_ATTR_REG32_RW DWC_OTG_DEVICE_ATTR_REG32_RO DWC_EN_ISOC
++SKIP_FUNCTION_MACROS = NO
++#---------------------------------------------------------------------------
++# Configuration::additions related to external references
++#---------------------------------------------------------------------------
++TAGFILES =
++GENERATE_TAGFILE =
++ALLEXTERNALS = NO
++EXTERNAL_GROUPS = YES
++PERL_PATH = /usr/bin/perl
++#---------------------------------------------------------------------------
++# Configuration options related to the dot tool
++#---------------------------------------------------------------------------
++CLASS_DIAGRAMS = YES
++HIDE_UNDOC_RELATIONS = YES
++HAVE_DOT = NO
++CLASS_GRAPH = YES
++COLLABORATION_GRAPH = YES
++UML_LOOK = NO
++TEMPLATE_RELATIONS = NO
++INCLUDE_GRAPH = YES
++INCLUDED_BY_GRAPH = YES
++CALL_GRAPH = NO
++GRAPHICAL_HIERARCHY = YES
++DOT_IMAGE_FORMAT = png
++DOT_PATH =
++DOTFILE_DIRS =
++MAX_DOT_GRAPH_DEPTH = 1000
++GENERATE_LEGEND = YES
++DOT_CLEANUP = YES
++#---------------------------------------------------------------------------
++# Configuration::additions related to the search engine
++#---------------------------------------------------------------------------
++SEARCHENGINE = NO
+diff --git a/drivers/usb/host/dwc_otg/dummy_audio.c b/drivers/usb/host/dwc_otg/dummy_audio.c
+new file mode 100644
+index 000000000000..f827102fa644
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dummy_audio.c
+@@ -0,0 +1,1574 @@
++/*
++ * zero.c -- Gadget Zero, for USB development
++ *
++ * Copyright (C) 2003-2004 David Brownell
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++/*
++ * Gadget Zero only needs two bulk endpoints, and is an example of how you
++ * can write a hardware-agnostic gadget driver running inside a USB device.
++ *
++ * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
++ * affect most of the driver.
++ *
++ * Use it with the Linux host/master side "usbtest" driver to get a basic
++ * functional test of your device-side usb stack, or with "usb-skeleton".
++ *
++ * It supports two similar configurations. One sinks whatever the usb host
++ * writes, and in return sources zeroes. The other loops whatever the host
++ * writes back, so the host can read it. Module options include:
++ *
++ * buflen=N default N=4096, buffer size used
++ * qlen=N default N=32, how many buffers in the loopback queue
++ * loopdefault default false, list loopback config first
++ *
++ * Many drivers will only have one configuration, letting them be much
++ * simpler if they also don't support high speed operation (like this
++ * driver does).
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/uts.h>
++#include <linux/version.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++#include <linux/proc_fs.h>
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/unaligned.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++# include <linux/usb/ch9.h>
++#else
++# include <linux/usb_ch9.h>
++#endif
++
++#include <linux/usb_gadget.h>
++
++
++/*-------------------------------------------------------------------------*/
++/*-------------------------------------------------------------------------*/
++
++
++static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++
++
++/**
++ * usb_gadget_get_string - fill out a string descriptor
++ * @table: of c strings encoded using UTF-8
++ * @id: string id, from low byte of wValue in get string descriptor
++ * @buf: at least 256 bytes
++ *
++ * Finds the UTF-8 string matching the ID, and converts it into a
++ * string descriptor in utf16-le.
++ * Returns length of descriptor (always even) or negative errno
++ *
++ * If your driver needs stings in multiple languages, you'll probably
++ * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
++ * using this routine after choosing which set of UTF-8 strings to use.
++ * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
++ * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
++ * characters (which are also widely used in C strings).
++ */
++int
++usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
++{
++ struct usb_string *s;
++ int len;
++
++ /* descriptor 0 has the language id */
++ if (id == 0) {
++ buf [0] = 4;
++ buf [1] = USB_DT_STRING;
++ buf [2] = (u8) table->language;
++ buf [3] = (u8) (table->language >> 8);
++ return 4;
++ }
++ for (s = table->strings; s && s->s; s++)
++ if (s->id == id)
++ break;
++
++ /* unrecognized: stall. */
++ if (!s || !s->s)
++ return -EINVAL;
++
++ /* string descriptors have length, tag, then UTF16-LE text */
++ len = min ((size_t) 126, strlen (s->s));
++ memset (buf + 2, 0, 2 * len); /* zero all the bytes */
++ len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
++ if (len < 0)
++ return -EINVAL;
++ buf [0] = (len + 1) * 2;
++ buf [1] = USB_DT_STRING;
++ return buf [0];
++}
++
++
++/*-------------------------------------------------------------------------*/
++/*-------------------------------------------------------------------------*/
++
++
++/**
++ * usb_descriptor_fillbuf - fill buffer with descriptors
++ * @buf: Buffer to be filled
++ * @buflen: Size of buf
++ * @src: Array of descriptor pointers, terminated by null pointer.
++ *
++ * Copies descriptors into the buffer, returning the length or a
++ * negative error code if they can't all be copied. Useful when
++ * assembling descriptors for an associated set of interfaces used
++ * as part of configuring a composite device; or in other cases where
++ * sets of descriptors need to be marshaled.
++ */
++int
++usb_descriptor_fillbuf(void *buf, unsigned buflen,
++ const struct usb_descriptor_header **src)
++{
++ u8 *dest = buf;
++
++ if (!src)
++ return -EINVAL;
++
++ /* fill buffer from src[] until null descriptor ptr */
++ for (; 0 != *src; src++) {
++ unsigned len = (*src)->bLength;
++
++ if (len > buflen)
++ return -EINVAL;
++ memcpy(dest, *src, len);
++ buflen -= len;
++ dest += len;
++ }
++ return dest - (u8 *)buf;
++}
++
++
++/**
++ * usb_gadget_config_buf - builts a complete configuration descriptor
++ * @config: Header for the descriptor, including characteristics such
++ * as power requirements and number of interfaces.
++ * @desc: Null-terminated vector of pointers to the descriptors (interface,
++ * endpoint, etc) defining all functions in this device configuration.
++ * @buf: Buffer for the resulting configuration descriptor.
++ * @length: Length of buffer. If this is not big enough to hold the
++ * entire configuration descriptor, an error code will be returned.
++ *
++ * This copies descriptors into the response buffer, building a descriptor
++ * for that configuration. It returns the buffer length or a negative
++ * status code. The config.wTotalLength field is set to match the length
++ * of the result, but other descriptor fields (including power usage and
++ * interface count) must be set by the caller.
++ *
++ * Gadget drivers could use this when constructing a config descriptor
++ * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
++ * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
++ */
++int usb_gadget_config_buf(
++ const struct usb_config_descriptor *config,
++ void *buf,
++ unsigned length,
++ const struct usb_descriptor_header **desc
++)
++{
++ struct usb_config_descriptor *cp = buf;
++ int len;
++
++ /* config descriptor first */
++ if (length < USB_DT_CONFIG_SIZE || !desc)
++ return -EINVAL;
++ *cp = *config;
++
++ /* then interface/endpoint/class/vendor/... */
++ len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
++ length - USB_DT_CONFIG_SIZE, desc);
++ if (len < 0)
++ return len;
++ len += USB_DT_CONFIG_SIZE;
++ if (len > 0xffff)
++ return -EINVAL;
++
++ /* patch up the config descriptor */
++ cp->bLength = USB_DT_CONFIG_SIZE;
++ cp->bDescriptorType = USB_DT_CONFIG;
++ cp->wTotalLength = cpu_to_le16(len);
++ cp->bmAttributes |= USB_CONFIG_ATT_ONE;
++ return len;
++}
++
++/*-------------------------------------------------------------------------*/
++/*-------------------------------------------------------------------------*/
++
++
++#define RBUF_LEN (1024*1024)
++static int rbuf_start;
++static int rbuf_len;
++static __u8 rbuf[RBUF_LEN];
++
++/*-------------------------------------------------------------------------*/
++
++#define DRIVER_VERSION "St Patrick's Day 2004"
++
++static const char shortname [] = "zero";
++static const char longname [] = "YAMAHA YST-MS35D USB Speaker ";
++
++static const char source_sink [] = "source and sink data";
++static const char loopback [] = "loop input to output";
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * driver assumes self-powered hardware, and
++ * has no way for users to trigger remote wakeup.
++ *
++ * this version autoconfigures as much as possible,
++ * which is reasonable for most "bulk-only" drivers.
++ */
++static const char *EP_IN_NAME; /* source */
++static const char *EP_OUT_NAME; /* sink */
++
++/*-------------------------------------------------------------------------*/
++
++/* big enough to hold our biggest descriptor */
++#define USB_BUFSIZ 512
++
++struct zero_dev {
++ spinlock_t lock;
++ struct usb_gadget *gadget;
++ struct usb_request *req; /* for control responses */
++
++ /* when configured, we have one of two configs:
++ * - source data (in to host) and sink it (out from host)
++ * - or loop it back (out from host back in to host)
++ */
++ u8 config;
++ struct usb_ep *in_ep, *out_ep;
++
++ /* autoresume timer */
++ struct timer_list resume;
++};
++
++#define xprintk(d,level,fmt,args...) \
++ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
++
++#ifdef DEBUG
++#define DBG(dev,fmt,args...) \
++ xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define DBG(dev,fmt,args...) \
++ do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE
++#define VDBG DBG
++#else
++#define VDBG(dev,fmt,args...) \
++ do { } while (0)
++#endif /* VERBOSE */
++
++#define ERROR(dev,fmt,args...) \
++ xprintk(dev , KERN_ERR , fmt , ## args)
++#define WARN(dev,fmt,args...) \
++ xprintk(dev , KERN_WARNING , fmt , ## args)
++#define INFO(dev,fmt,args...) \
++ xprintk(dev , KERN_INFO , fmt , ## args)
++
++/*-------------------------------------------------------------------------*/
++
++static unsigned buflen = 4096;
++static unsigned qlen = 32;
++static unsigned pattern = 0;
++
++module_param (buflen, uint, S_IRUGO|S_IWUSR);
++module_param (qlen, uint, S_IRUGO|S_IWUSR);
++module_param (pattern, uint, S_IRUGO|S_IWUSR);
++
++/*
++ * if it's nonzero, autoresume says how many seconds to wait
++ * before trying to wake up the host after suspend.
++ */
++static unsigned autoresume = 0;
++module_param (autoresume, uint, 0);
++
++/*
++ * Normally the "loopback" configuration is second (index 1) so
++ * it's not the default. Here's where to change that order, to
++ * work better with hosts where config changes are problematic.
++ * Or controllers (like superh) that only support one config.
++ */
++static int loopdefault = 0;
++
++module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
++
++/*-------------------------------------------------------------------------*/
++
++/* Thanks to NetChip Technologies for donating this product ID.
++ *
++ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
++ * Instead: allocate your own, using normal USB-IF procedures.
++ */
++#ifndef CONFIG_USB_ZERO_HNPTEST
++#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
++#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
++#else
++#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
++#define DRIVER_PRODUCT_NUM 0xbadd
++#endif
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full)
++ * configuration descriptors are built on demand.
++ */
++
++/*
++#define STRING_MANUFACTURER 25
++#define STRING_PRODUCT 42
++#define STRING_SERIAL 101
++*/
++#define STRING_MANUFACTURER 1
++#define STRING_PRODUCT 2
++#define STRING_SERIAL 3
++
++#define STRING_SOURCE_SINK 250
++#define STRING_LOOPBACK 251
++
++/*
++ * This device advertises two configurations; these numbers work
++ * on a pxa250 as well as more flexible hardware.
++ */
++#define CONFIG_SOURCE_SINK 3
++#define CONFIG_LOOPBACK 2
++
++/*
++static struct usb_device_descriptor
++device_desc = {
++ .bLength = sizeof device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++
++ .bcdUSB = __constant_cpu_to_le16 (0x0200),
++ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
++
++ .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
++ .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
++ .iManufacturer = STRING_MANUFACTURER,
++ .iProduct = STRING_PRODUCT,
++ .iSerialNumber = STRING_SERIAL,
++ .bNumConfigurations = 2,
++};
++*/
++static struct usb_device_descriptor
++device_desc = {
++ .bLength = sizeof device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = __constant_cpu_to_le16 (0x0100),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++ .bDeviceSubClass = 0,
++ .bDeviceProtocol = 0,
++ .bMaxPacketSize0 = 64,
++ .bcdDevice = __constant_cpu_to_le16 (0x0100),
++ .idVendor = __constant_cpu_to_le16 (0x0499),
++ .idProduct = __constant_cpu_to_le16 (0x3002),
++ .iManufacturer = STRING_MANUFACTURER,
++ .iProduct = STRING_PRODUCT,
++ .iSerialNumber = STRING_SERIAL,
++ .bNumConfigurations = 1,
++};
++
++static struct usb_config_descriptor
++z_config = {
++ .bLength = sizeof z_config,
++ .bDescriptorType = USB_DT_CONFIG,
++
++ /* compute wTotalLength on the fly */
++ .bNumInterfaces = 2,
++ .bConfigurationValue = 1,
++ .iConfiguration = 0,
++ .bmAttributes = 0x40,
++ .bMaxPower = 0, /* self-powered */
++};
++
++
++static struct usb_otg_descriptor
++otg_descriptor = {
++ .bLength = sizeof otg_descriptor,
++ .bDescriptorType = USB_DT_OTG,
++
++ .bmAttributes = USB_OTG_SRP,
++};
++
++/* one interface in each configuration */
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++
++/*
++ * usb 2.0 devices need to expose both high speed and full speed
++ * descriptors, unless they only run at full speed.
++ *
++ * that means alternate endpoint descriptors (bigger packets)
++ * and a "device qualifier" ... plus more construction options
++ * for the config descriptor.
++ */
++
++static struct usb_qualifier_descriptor
++dev_qualifier = {
++ .bLength = sizeof dev_qualifier,
++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
++
++ .bcdUSB = __constant_cpu_to_le16 (0x0200),
++ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
++
++ .bNumConfigurations = 2,
++};
++
++
++struct usb_cs_as_general_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++
++ __u8 bDescriptorSubType;
++ __u8 bTerminalLink;
++ __u8 bDelay;
++ __u16 wFormatTag;
++} __attribute__ ((packed));
++
++struct usb_cs_as_format_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++
++ __u8 bDescriptorSubType;
++ __u8 bFormatType;
++ __u8 bNrChannels;
++ __u8 bSubframeSize;
++ __u8 bBitResolution;
++ __u8 bSamfreqType;
++ __u8 tLowerSamFreq[3];
++ __u8 tUpperSamFreq[3];
++} __attribute__ ((packed));
++
++static const struct usb_interface_descriptor
++z_audio_control_if_desc = {
++ .bLength = sizeof z_audio_control_if_desc,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0,
++ .bAlternateSetting = 0,
++ .bNumEndpoints = 0,
++ .bInterfaceClass = USB_CLASS_AUDIO,
++ .bInterfaceSubClass = 0x1,
++ .bInterfaceProtocol = 0,
++ .iInterface = 0,
++};
++
++static const struct usb_interface_descriptor
++z_audio_if_desc = {
++ .bLength = sizeof z_audio_if_desc,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 1,
++ .bAlternateSetting = 0,
++ .bNumEndpoints = 0,
++ .bInterfaceClass = USB_CLASS_AUDIO,
++ .bInterfaceSubClass = 0x2,
++ .bInterfaceProtocol = 0,
++ .iInterface = 0,
++};
++
++static const struct usb_interface_descriptor
++z_audio_if_desc2 = {
++ .bLength = sizeof z_audio_if_desc,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 1,
++ .bAlternateSetting = 1,
++ .bNumEndpoints = 1,
++ .bInterfaceClass = USB_CLASS_AUDIO,
++ .bInterfaceSubClass = 0x2,
++ .bInterfaceProtocol = 0,
++ .iInterface = 0,
++};
++
++static const struct usb_cs_as_general_descriptor
++z_audio_cs_as_if_desc = {
++ .bLength = 7,
++ .bDescriptorType = 0x24,
++
++ .bDescriptorSubType = 0x01,
++ .bTerminalLink = 0x01,
++ .bDelay = 0x0,
++ .wFormatTag = __constant_cpu_to_le16 (0x0001)
++};
++
++
++static const struct usb_cs_as_format_descriptor
++z_audio_cs_as_format_desc = {
++ .bLength = 0xe,
++ .bDescriptorType = 0x24,
++
++ .bDescriptorSubType = 2,
++ .bFormatType = 1,
++ .bNrChannels = 1,
++ .bSubframeSize = 1,
++ .bBitResolution = 8,
++ .bSamfreqType = 0,
++ .tLowerSamFreq = {0x7e, 0x13, 0x00},
++ .tUpperSamFreq = {0xe2, 0xd6, 0x00},
++};
++
++static const struct usb_endpoint_descriptor
++z_iso_ep = {
++ .bLength = 0x09,
++ .bDescriptorType = 0x05,
++ .bEndpointAddress = 0x04,
++ .bmAttributes = 0x09,
++ .wMaxPacketSize = 0x0038,
++ .bInterval = 0x01,
++ .bRefresh = 0x00,
++ .bSynchAddress = 0x00,
++};
++
++static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
++
++// 9 bytes
++static char z_ac_interface_header_desc[] =
++{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
++
++// 12 bytes
++static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02,
++ 0x03, 0x00, 0x00, 0x00};
++// 13 bytes
++static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00,
++ 0x02, 0x00, 0x02, 0x00, 0x00};
++// 9 bytes
++static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02,
++ 0x00};
++
++static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00,
++ 0x00};
++
++static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
++
++static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00,
++ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
++
++static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
++ 0x00};
++
++static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
++
++static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
++ 0x00};
++
++static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
++
++static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
++ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
++
++static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
++ 0x00};
++
++static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
++
++static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
++ 0x00};
++
++static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
++
++static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
++ 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
++
++static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
++ 0x00};
++
++static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
++
++static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00,
++ 0x00};
++
++static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
++
++static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00,
++ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
++
++static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
++ 0x00};
++
++static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
++
++static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
++ 0x00};
++
++static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
++
++static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00,
++ 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
++
++static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
++ 0x00};
++
++static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
++
++
++
++static const struct usb_descriptor_header *z_function [] = {
++ (struct usb_descriptor_header *) &z_audio_control_if_desc,
++ (struct usb_descriptor_header *) &z_ac_interface_header_desc,
++ (struct usb_descriptor_header *) &z_0,
++ (struct usb_descriptor_header *) &z_1,
++ (struct usb_descriptor_header *) &z_2,
++ (struct usb_descriptor_header *) &z_audio_if_desc,
++ (struct usb_descriptor_header *) &z_audio_if_desc2,
++ (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
++ (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
++ (struct usb_descriptor_header *) &z_iso_ep,
++ (struct usb_descriptor_header *) &z_iso_ep2,
++ (struct usb_descriptor_header *) &za_0,
++ (struct usb_descriptor_header *) &za_1,
++ (struct usb_descriptor_header *) &za_2,
++ (struct usb_descriptor_header *) &za_3,
++ (struct usb_descriptor_header *) &za_4,
++ (struct usb_descriptor_header *) &za_5,
++ (struct usb_descriptor_header *) &za_6,
++ (struct usb_descriptor_header *) &za_7,
++ (struct usb_descriptor_header *) &za_8,
++ (struct usb_descriptor_header *) &za_9,
++ (struct usb_descriptor_header *) &za_10,
++ (struct usb_descriptor_header *) &za_11,
++ (struct usb_descriptor_header *) &za_12,
++ (struct usb_descriptor_header *) &za_13,
++ (struct usb_descriptor_header *) &za_14,
++ (struct usb_descriptor_header *) &za_15,
++ (struct usb_descriptor_header *) &za_16,
++ (struct usb_descriptor_header *) &za_17,
++ (struct usb_descriptor_header *) &za_18,
++ (struct usb_descriptor_header *) &za_19,
++ (struct usb_descriptor_header *) &za_20,
++ (struct usb_descriptor_header *) &za_21,
++ (struct usb_descriptor_header *) &za_22,
++ (struct usb_descriptor_header *) &za_23,
++ (struct usb_descriptor_header *) &za_24,
++ NULL,
++};
++
++/* maxpacket and other transfer characteristics vary by speed. */
++#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
++
++#else
++
++/* if there's no high speed support, maxpacket doesn't change. */
++#define ep_desc(g,hs,fs) fs
++
++#endif /* !CONFIG_USB_GADGET_DUALSPEED */
++
++static char manufacturer [40];
++//static char serial [40];
++static char serial [] = "Ser 00 em";
++
++/* static strings, in UTF-8 */
++static struct usb_string strings [] = {
++ { STRING_MANUFACTURER, manufacturer, },
++ { STRING_PRODUCT, longname, },
++ { STRING_SERIAL, serial, },
++ { STRING_LOOPBACK, loopback, },
++ { STRING_SOURCE_SINK, source_sink, },
++ { } /* end of list */
++};
++
++static struct usb_gadget_strings stringtab = {
++ .language = 0x0409, /* en-us */
++ .strings = strings,
++};
++
++/*
++ * config descriptors are also handcrafted. these must agree with code
++ * that sets configurations, and with code managing interfaces and their
++ * altsettings. other complexity may come from:
++ *
++ * - high speed support, including "other speed config" rules
++ * - multiple configurations
++ * - interfaces with alternate settings
++ * - embedded class or vendor-specific descriptors
++ *
++ * this handles high speed, and has a second config that could as easily
++ * have been an alternate interface setting (on most hardware).
++ *
++ * NOTE: to demonstrate (and test) more USB capabilities, this driver
++ * should include an altsetting to test interrupt transfers, including
++ * high bandwidth modes at high speed. (Maybe work like Intel's test
++ * device?)
++ */
++static int
++config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
++{
++ int len;
++ const struct usb_descriptor_header **function;
++
++ function = z_function;
++ len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
++ if (len < 0)
++ return len;
++ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
++ return len;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_request *
++alloc_ep_req (struct usb_ep *ep, unsigned length)
++{
++ struct usb_request *req;
++
++ req = usb_ep_alloc_request (ep, GFP_ATOMIC);
++ if (req) {
++ req->length = length;
++ req->buf = usb_ep_alloc_buffer (ep, length,
++ &req->dma, GFP_ATOMIC);
++ if (!req->buf) {
++ usb_ep_free_request (ep, req);
++ req = NULL;
++ }
++ }
++ return req;
++}
++
++static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
++{
++ if (req->buf)
++ usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
++ usb_ep_free_request (ep, req);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* optionally require specific source/sink data patterns */
++
++static int
++check_read_data (
++ struct zero_dev *dev,
++ struct usb_ep *ep,
++ struct usb_request *req
++)
++{
++ unsigned i;
++ u8 *buf = req->buf;
++
++ for (i = 0; i < req->actual; i++, buf++) {
++ switch (pattern) {
++ /* all-zeroes has no synchronization issues */
++ case 0:
++ if (*buf == 0)
++ continue;
++ break;
++ /* mod63 stays in sync with short-terminated transfers,
++ * or otherwise when host and gadget agree on how large
++ * each usb transfer request should be. resync is done
++ * with set_interface or set_config.
++ */
++ case 1:
++ if (*buf == (u8)(i % 63))
++ continue;
++ break;
++ }
++ ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
++ usb_ep_set_halt (ep);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void zero_reset_config (struct zero_dev *dev)
++{
++ if (dev->config == 0)
++ return;
++
++ DBG (dev, "reset config\n");
++
++ /* just disable endpoints, forcing completion of pending i/o.
++ * all our completion handlers free their requests in this case.
++ */
++ if (dev->in_ep) {
++ usb_ep_disable (dev->in_ep);
++ dev->in_ep = NULL;
++ }
++ if (dev->out_ep) {
++ usb_ep_disable (dev->out_ep);
++ dev->out_ep = NULL;
++ }
++ dev->config = 0;
++ del_timer (&dev->resume);
++}
++
++#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
++
++static void
++zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
++{
++ struct zero_dev *dev = ep->driver_data;
++ int status = req->status;
++ int i, j;
++
++ switch (status) {
++
++ case 0: /* normal completion? */
++ //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
++ for (i=0, j=rbuf_start; i<req->actual; i++) {
++ //printk ("%02x ", ((__u8*)req->buf)[i]);
++ rbuf[j] = ((__u8*)req->buf)[i];
++ j++;
++ if (j >= RBUF_LEN) j=0;
++ }
++ rbuf_start = j;
++ //printk ("\n\n");
++
++ if (rbuf_len < RBUF_LEN) {
++ rbuf_len += req->actual;
++ if (rbuf_len > RBUF_LEN) {
++ rbuf_len = RBUF_LEN;
++ }
++ }
++
++ break;
++
++ /* this endpoint is normally active while we're configured */
++ case -ECONNABORTED: /* hardware forced ep reset */
++ case -ECONNRESET: /* request dequeued */
++ case -ESHUTDOWN: /* disconnect from host */
++ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
++ req->actual, req->length);
++ if (ep == dev->out_ep)
++ check_read_data (dev, ep, req);
++ free_ep_req (ep, req);
++ return;
++
++ case -EOVERFLOW: /* buffer overrun on read means that
++ * we didn't provide a big enough
++ * buffer.
++ */
++ default:
++#if 1
++ DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
++ status, req->actual, req->length);
++#endif
++ case -EREMOTEIO: /* short read */
++ break;
++ }
++
++ status = usb_ep_queue (ep, req, GFP_ATOMIC);
++ if (status) {
++ ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
++ ep->name, req->length, status);
++ usb_ep_set_halt (ep);
++ /* FIXME recover later ... somehow */
++ }
++}
++
++static struct usb_request *
++zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
++{
++ struct usb_request *req;
++ int status;
++
++ req = alloc_ep_req (ep, 512);
++ if (!req)
++ return NULL;
++
++ req->complete = zero_isoc_complete;
++
++ status = usb_ep_queue (ep, req, gfp_flags);
++ if (status) {
++ struct zero_dev *dev = ep->driver_data;
++
++ ERROR (dev, "start %s --> %d\n", ep->name, status);
++ free_ep_req (ep, req);
++ req = NULL;
++ }
++
++ return req;
++}
++
++/* change our operational config. this code must agree with the code
++ * that returns config descriptors, and altsetting code.
++ *
++ * it's also responsible for power management interactions. some
++ * configurations might not work with our current power sources.
++ *
++ * note that some device controller hardware will constrain what this
++ * code can do, perhaps by disallowing more than one configuration or
++ * by limiting configuration choices (like the pxa2xx).
++ */
++static int
++zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
++{
++ int result = 0;
++ struct usb_gadget *gadget = dev->gadget;
++ const struct usb_endpoint_descriptor *d;
++ struct usb_ep *ep;
++
++ if (number == dev->config)
++ return 0;
++
++ zero_reset_config (dev);
++
++ gadget_for_each_ep (ep, gadget) {
++
++ if (strcmp (ep->name, "ep4") == 0) {
++
++ d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
++ result = usb_ep_enable (ep, d);
++
++ if (result == 0) {
++ ep->driver_data = dev;
++ dev->in_ep = ep;
++
++ if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
++
++ dev->in_ep = ep;
++ continue;
++ }
++
++ usb_ep_disable (ep);
++ result = -EIO;
++ }
++ }
++
++ }
++
++ dev->config = number;
++ return result;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
++{
++ if (req->status || req->actual != req->length)
++ DBG ((struct zero_dev *) ep->driver_data,
++ "setup complete --> %d, %d/%d\n",
++ req->status, req->actual, req->length);
++}
++
++/*
++ * The setup() callback implements all the ep0 functionality that's
++ * not handled lower down, in hardware or the hardware driver (like
++ * device and endpoint feature flags, and their status). It's all
++ * housekeeping for the gadget function we're implementing. Most of
++ * the work is in config-specific setup.
++ */
++static int
++zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
++{
++ struct zero_dev *dev = get_gadget_data (gadget);
++ struct usb_request *req = dev->req;
++ int value = -EOPNOTSUPP;
++
++ /* usually this stores reply data in the pre-allocated ep0 buffer,
++ * but config change events will reconfigure hardware.
++ */
++ req->zero = 0;
++ switch (ctrl->bRequest) {
++
++ case USB_REQ_GET_DESCRIPTOR:
++
++ switch (ctrl->wValue >> 8) {
++
++ case USB_DT_DEVICE:
++ value = min (ctrl->wLength, (u16) sizeof device_desc);
++ memcpy (req->buf, &device_desc, value);
++ break;
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++ case USB_DT_DEVICE_QUALIFIER:
++ if (!gadget->is_dualspeed)
++ break;
++ value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
++ memcpy (req->buf, &dev_qualifier, value);
++ break;
++
++ case USB_DT_OTHER_SPEED_CONFIG:
++ if (!gadget->is_dualspeed)
++ break;
++ // FALLTHROUGH
++#endif /* CONFIG_USB_GADGET_DUALSPEED */
++ case USB_DT_CONFIG:
++ value = config_buf (gadget, req->buf,
++ ctrl->wValue >> 8,
++ ctrl->wValue & 0xff);
++ if (value >= 0)
++ value = min (ctrl->wLength, (u16) value);
++ break;
++
++ case USB_DT_STRING:
++ /* wIndex == language code.
++ * this driver only handles one language, you can
++ * add string tables for other languages, using
++ * any UTF-8 characters
++ */
++ value = usb_gadget_get_string (&stringtab,
++ ctrl->wValue & 0xff, req->buf);
++ if (value >= 0) {
++ value = min (ctrl->wLength, (u16) value);
++ }
++ break;
++ }
++ break;
++
++ /* currently two configs, two speeds */
++ case USB_REQ_SET_CONFIGURATION:
++ if (ctrl->bRequestType != 0)
++ goto unknown;
++
++ spin_lock (&dev->lock);
++ value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
++ spin_unlock (&dev->lock);
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ if (ctrl->bRequestType != USB_DIR_IN)
++ goto unknown;
++ *(u8 *)req->buf = dev->config;
++ value = min (ctrl->wLength, (u16) 1);
++ break;
++
++ /* until we add altsetting support, or other interfaces,
++ * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
++ * and already killed pending endpoint I/O.
++ */
++ case USB_REQ_SET_INTERFACE:
++
++ if (ctrl->bRequestType != USB_RECIP_INTERFACE)
++ goto unknown;
++ spin_lock (&dev->lock);
++ if (dev->config) {
++ u8 config = dev->config;
++
++ /* resets interface configuration, forgets about
++ * previous transaction state (queued bufs, etc)
++ * and re-inits endpoint state (toggle etc)
++ * no response queued, just zero status == success.
++ * if we had more than one interface we couldn't
++ * use this "reset the config" shortcut.
++ */
++ zero_reset_config (dev);
++ zero_set_config (dev, config, GFP_ATOMIC);
++ value = 0;
++ }
++ spin_unlock (&dev->lock);
++ break;
++ case USB_REQ_GET_INTERFACE:
++ if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
++ value = ctrl->wLength;
++ break;
++ }
++ else {
++ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
++ goto unknown;
++ if (!dev->config)
++ break;
++ if (ctrl->wIndex != 0) {
++ value = -EDOM;
++ break;
++ }
++ *(u8 *)req->buf = 0;
++ value = min (ctrl->wLength, (u16) 1);
++ }
++ break;
++
++ /*
++ * These are the same vendor-specific requests supported by
++ * Intel's USB 2.0 compliance test devices. We exceed that
++ * device spec by allowing multiple-packet requests.
++ */
++ case 0x5b: /* control WRITE test -- fill the buffer */
++ if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
++ goto unknown;
++ if (ctrl->wValue || ctrl->wIndex)
++ break;
++ /* just read that many bytes into the buffer */
++ if (ctrl->wLength > USB_BUFSIZ)
++ break;
++ value = ctrl->wLength;
++ break;
++ case 0x5c: /* control READ test -- return the buffer */
++ if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
++ goto unknown;
++ if (ctrl->wValue || ctrl->wIndex)
++ break;
++ /* expect those bytes are still in the buffer; send back */
++ if (ctrl->wLength > USB_BUFSIZ
++ || ctrl->wLength != req->length)
++ break;
++ value = ctrl->wLength;
++ break;
++
++ case 0x01: // SET_CUR
++ case 0x02:
++ case 0x03:
++ case 0x04:
++ case 0x05:
++ value = ctrl->wLength;
++ break;
++ case 0x81:
++ switch (ctrl->wValue) {
++ case 0x0201:
++ case 0x0202:
++ ((u8*)req->buf)[0] = 0x00;
++ ((u8*)req->buf)[1] = 0xe3;
++ break;
++ case 0x0300:
++ case 0x0500:
++ ((u8*)req->buf)[0] = 0x00;
++ break;
++ }
++ //((u8*)req->buf)[0] = 0x81;
++ //((u8*)req->buf)[1] = 0x81;
++ value = ctrl->wLength;
++ break;
++ case 0x82:
++ switch (ctrl->wValue) {
++ case 0x0201:
++ case 0x0202:
++ ((u8*)req->buf)[0] = 0x00;
++ ((u8*)req->buf)[1] = 0xc3;
++ break;
++ case 0x0300:
++ case 0x0500:
++ ((u8*)req->buf)[0] = 0x00;
++ break;
++ }
++ //((u8*)req->buf)[0] = 0x82;
++ //((u8*)req->buf)[1] = 0x82;
++ value = ctrl->wLength;
++ break;
++ case 0x83:
++ switch (ctrl->wValue) {
++ case 0x0201:
++ case 0x0202:
++ ((u8*)req->buf)[0] = 0x00;
++ ((u8*)req->buf)[1] = 0x00;
++ break;
++ case 0x0300:
++ ((u8*)req->buf)[0] = 0x60;
++ break;
++ case 0x0500:
++ ((u8*)req->buf)[0] = 0x18;
++ break;
++ }
++ //((u8*)req->buf)[0] = 0x83;
++ //((u8*)req->buf)[1] = 0x83;
++ value = ctrl->wLength;
++ break;
++ case 0x84:
++ switch (ctrl->wValue) {
++ case 0x0201:
++ case 0x0202:
++ ((u8*)req->buf)[0] = 0x00;
++ ((u8*)req->buf)[1] = 0x01;
++ break;
++ case 0x0300:
++ case 0x0500:
++ ((u8*)req->buf)[0] = 0x08;
++ break;
++ }
++ //((u8*)req->buf)[0] = 0x84;
++ //((u8*)req->buf)[1] = 0x84;
++ value = ctrl->wLength;
++ break;
++ case 0x85:
++ ((u8*)req->buf)[0] = 0x85;
++ ((u8*)req->buf)[1] = 0x85;
++ value = ctrl->wLength;
++ break;
++
++
++ default:
++unknown:
++ printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ ctrl->wValue, ctrl->wIndex, ctrl->wLength);
++ }
++
++ /* respond with data transfer before status phase? */
++ if (value >= 0) {
++ req->length = value;
++ req->zero = value < ctrl->wLength
++ && (value % gadget->ep0->maxpacket) == 0;
++ value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
++ if (value < 0) {
++ DBG (dev, "ep_queue < 0 --> %d\n", value);
++ req->status = 0;
++ zero_setup_complete (gadget->ep0, req);
++ }
++ }
++
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static void
++zero_disconnect (struct usb_gadget *gadget)
++{
++ struct zero_dev *dev = get_gadget_data (gadget);
++ unsigned long flags;
++
++ spin_lock_irqsave (&dev->lock, flags);
++ zero_reset_config (dev);
++
++ /* a more significant application might have some non-usb
++ * activities to quiesce here, saving resources like power
++ * or pushing the notification up a network stack.
++ */
++ spin_unlock_irqrestore (&dev->lock, flags);
++
++ /* next we may get setup() calls to enumerate new connections;
++ * or an unbind() during shutdown (including removing module).
++ */
++}
++
++static void
++zero_autoresume (unsigned long _dev)
++{
++ struct zero_dev *dev = (struct zero_dev *) _dev;
++ int status;
++
++ /* normally the host would be woken up for something
++ * more significant than just a timer firing...
++ */
++ if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
++ status = usb_gadget_wakeup (dev->gadget);
++ DBG (dev, "wakeup --> %d\n", status);
++ }
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++zero_unbind (struct usb_gadget *gadget)
++{
++ struct zero_dev *dev = get_gadget_data (gadget);
++
++ DBG (dev, "unbind\n");
++
++ /* we've already been disconnected ... no i/o is active */
++ if (dev->req)
++ free_ep_req (gadget->ep0, dev->req);
++ del_timer_sync (&dev->resume);
++ kfree (dev);
++ set_gadget_data (gadget, NULL);
++}
++
++static int
++zero_bind (struct usb_gadget *gadget)
++{
++ struct zero_dev *dev;
++ //struct usb_ep *ep;
++
++ printk("binding\n");
++ /*
++ * DRIVER POLICY CHOICE: you may want to do this differently.
++ * One thing to avoid is reusing a bcdDevice revision code
++ * with different host-visible configurations or behavior
++ * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
++ */
++ //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
++
++
++ /* ok, we made sense of the hardware ... */
++ dev = kzalloc (sizeof *dev, SLAB_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++ spin_lock_init (&dev->lock);
++ dev->gadget = gadget;
++ set_gadget_data (gadget, dev);
++
++ /* preallocate control response and buffer */
++ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
++ if (!dev->req)
++ goto enomem;
++ dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
++ &dev->req->dma, GFP_KERNEL);
++ if (!dev->req->buf)
++ goto enomem;
++
++ dev->req->complete = zero_setup_complete;
++
++ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
++
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++ /* assume ep0 uses the same value for both speeds ... */
++ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
++
++ /* and that all endpoints are dual-speed */
++ //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
++ //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
++#endif
++
++ usb_gadget_set_selfpowered (gadget);
++
++ init_timer (&dev->resume);
++ dev->resume.function = zero_autoresume;
++ dev->resume.data = (unsigned long) dev;
++
++ gadget->ep0->driver_data = dev;
++
++ INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
++ INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
++ EP_OUT_NAME, EP_IN_NAME);
++
++ snprintf (manufacturer, sizeof manufacturer,
++ UTS_SYSNAME " " UTS_RELEASE " with %s",
++ gadget->name);
++
++ return 0;
++
++enomem:
++ zero_unbind (gadget);
++ return -ENOMEM;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++zero_suspend (struct usb_gadget *gadget)
++{
++ struct zero_dev *dev = get_gadget_data (gadget);
++
++ if (gadget->speed == USB_SPEED_UNKNOWN)
++ return;
++
++ if (autoresume) {
++ mod_timer (&dev->resume, jiffies + (HZ * autoresume));
++ DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
++ } else
++ DBG (dev, "suspend\n");
++}
++
++static void
++zero_resume (struct usb_gadget *gadget)
++{
++ struct zero_dev *dev = get_gadget_data (gadget);
++
++ DBG (dev, "resume\n");
++ del_timer (&dev->resume);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver zero_driver = {
++#ifdef CONFIG_USB_GADGET_DUALSPEED
++ .speed = USB_SPEED_HIGH,
++#else
++ .speed = USB_SPEED_FULL,
++#endif
++ .function = (char *) longname,
++ .bind = zero_bind,
++ .unbind = zero_unbind,
++
++ .setup = zero_setup,
++ .disconnect = zero_disconnect,
++
++ .suspend = zero_suspend,
++ .resume = zero_resume,
++
++ .driver = {
++ .name = (char *) shortname,
++ // .shutdown = ...
++ // .suspend = ...
++ // .resume = ...
++ },
++};
++
++MODULE_AUTHOR ("David Brownell");
++MODULE_LICENSE ("Dual BSD/GPL");
++
++static struct proc_dir_entry *pdir, *pfile;
++
++static int isoc_read_data (char *page, char **start,
++ off_t off, int count,
++ int *eof, void *data)
++{
++ int i;
++ static int c = 0;
++ static int done = 0;
++ static int s = 0;
++
++/*
++ printk ("\ncount: %d\n", count);
++ printk ("rbuf_start: %d\n", rbuf_start);
++ printk ("rbuf_len: %d\n", rbuf_len);
++ printk ("off: %d\n", off);
++ printk ("start: %p\n\n", *start);
++*/
++ if (done) {
++ c = 0;
++ done = 0;
++ *eof = 1;
++ return 0;
++ }
++
++ if (c == 0) {
++ if (rbuf_len == RBUF_LEN)
++ s = rbuf_start;
++ else s = 0;
++ }
++
++ for (i=0; i<count && c<rbuf_len; i++, c++) {
++ page[i] = rbuf[(c+s) % RBUF_LEN];
++ }
++ *start = page;
++
++ if (c >= rbuf_len) {
++ *eof = 1;
++ done = 1;
++ }
++
++
++ return i;
++}
++
++static int __init init (void)
++{
++
++ int retval = 0;
++
++ pdir = proc_mkdir("isoc_test", NULL);
++ if(pdir == NULL) {
++ retval = -ENOMEM;
++ printk("Error creating dir\n");
++ goto done;
++ }
++ pdir->owner = THIS_MODULE;
++
++ pfile = create_proc_read_entry("isoc_data",
++ 0444, pdir,
++ isoc_read_data,
++ NULL);
++ if (pfile == NULL) {
++ retval = -ENOMEM;
++ printk("Error creating file\n");
++ goto no_file;
++ }
++ pfile->owner = THIS_MODULE;
++
++ return usb_gadget_register_driver (&zero_driver);
++
++ no_file:
++ remove_proc_entry("isoc_data", NULL);
++ done:
++ return retval;
++}
++module_init (init);
++
++static void __exit cleanup (void)
++{
++
++ usb_gadget_unregister_driver (&zero_driver);
++
++ remove_proc_entry("isoc_data", pdir);
++ remove_proc_entry("isoc_test", NULL);
++}
++module_exit (cleanup);
+diff --git a/drivers/usb/host/dwc_otg/dwc_cfi_common.h b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
+new file mode 100644
+index 000000000000..7770e201ad3b
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h
+@@ -0,0 +1,142 @@
++/* ==========================================================================
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#if !defined(__DWC_CFI_COMMON_H__)
++#define __DWC_CFI_COMMON_H__
++
++//#include <linux/types.h>
++
++/**
++ * @file
++ *
++ * This file contains the CFI specific common constants, interfaces
++ * (functions and macros) and structures for Linux. No PCD specific
++ * data structure or definition is to be included in this file.
++ *
++ */
++
++/** This is a request for all Core Features */
++#define VEN_CORE_GET_FEATURES 0xB1
++
++/** This is a request to get the value of a specific Core Feature */
++#define VEN_CORE_GET_FEATURE 0xB2
++
++/** This command allows the host to set the value of a specific Core Feature */
++#define VEN_CORE_SET_FEATURE 0xB3
++
++/** This command allows the host to set the default values of
++ * either all or any specific Core Feature
++ */
++#define VEN_CORE_RESET_FEATURES 0xB4
++
++/** This command forces the PCD to write the deferred values of a Core Features */
++#define VEN_CORE_ACTIVATE_FEATURES 0xB5
++
++/** This request reads a DWORD value from a register at the specified offset */
++#define VEN_CORE_READ_REGISTER 0xB6
++
++/** This request writes a DWORD value into a register at the specified offset */
++#define VEN_CORE_WRITE_REGISTER 0xB7
++
++/** This structure is the header of the Core Features dataset returned to
++ * the Host
++ */
++struct cfi_all_features_header {
++/** The features header structure length is */
++#define CFI_ALL_FEATURES_HDR_LEN 8
++ /**
++ * The total length of the features dataset returned to the Host
++ */
++ uint16_t wTotalLen;
++
++ /**
++ * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
++ * This field identifies the version of the CFI Specification with which
++ * the device is compliant.
++ */
++ uint16_t wVersion;
++
++ /** The ID of the Core */
++ uint16_t wCoreID;
++#define CFI_CORE_ID_UDC 1
++#define CFI_CORE_ID_OTG 2
++#define CFI_CORE_ID_WUDEV 3
++
++ /** Number of features returned by VEN_CORE_GET_FEATURES request */
++ uint16_t wNumFeatures;
++} UPACKED;
++
++typedef struct cfi_all_features_header cfi_all_features_header_t;
++
++/** This structure is a header of the Core Feature descriptor dataset returned to
++ * the Host after the VEN_CORE_GET_FEATURES request
++ */
++struct cfi_feature_desc_header {
++#define CFI_FEATURE_DESC_HDR_LEN 8
++
++ /** The feature ID */
++ uint16_t wFeatureID;
++
++ /** Length of this feature descriptor in bytes - including the
++ * length of the feature name string
++ */
++ uint16_t wLength;
++
++ /** The data length of this feature in bytes */
++ uint16_t wDataLength;
++
++ /**
++ * Attributes of this features
++ * D0: Access rights
++ * 0 - Read/Write
++ * 1 - Read only
++ */
++ uint8_t bmAttributes;
++#define CFI_FEATURE_ATTR_RO 1
++#define CFI_FEATURE_ATTR_RW 0
++
++ /** Length of the feature name in bytes */
++ uint8_t bNameLen;
++
++ /** The feature name buffer */
++ //uint8_t *name;
++} UPACKED;
++
++typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
++
++/**
++ * This structure describes a NULL terminated string referenced by its id field.
++ * It is very similar to usb_string structure but has the id field type set to 16-bit.
++ */
++struct cfi_string {
++ uint16_t id;
++ const uint8_t *s;
++};
++typedef struct cfi_string cfi_string_t;
++
++#endif
+diff --git a/drivers/usb/host/dwc_otg/dwc_otg_adp.c b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
+new file mode 100644
+index 000000000000..ce0618dd3f4a
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.c
+@@ -0,0 +1,854 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
++ * $Revision: #12 $
++ * $Date: 2011/10/26 $
++ * $Change: 1873028 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#include "dwc_os.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++#include "dwc_otg_adp.h"
++
++/** @file
++ *
++ * This file contains the most of the Attach Detect Protocol implementation for
++ * the driver to support OTG Rev2.0.
++ *
++ */
++
++void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
++{
++ adpctl_data_t adpctl;
++
++ adpctl.d32 = value;
++ adpctl.b.ar = 0x2;
++
++ DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
++
++ while (adpctl.b.ar) {
++ adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
++ }
++
++}
++
++/**
++ * Function is called to read ADP registers
++ */
++uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
++{
++ adpctl_data_t adpctl;
++
++ adpctl.d32 = 0;
++ adpctl.b.ar = 0x1;
++
++ DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
++
++ while (adpctl.b.ar) {
++ adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
++ }
++
++ return adpctl.d32;
++}
++
++/**
++ * Function is called to read ADPCTL register and filter Write-clear bits
++ */
++uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
++{
++ adpctl_data_t adpctl;
++
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ adpctl.b.adp_tmout_int = 0;
++ adpctl.b.adp_prb_int = 0;
++ adpctl.b.adp_tmout_int = 0;
++
++ return adpctl.d32;
++}
++
++/**
++ * Function is called to write ADP registers
++ */
++void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
++ uint32_t set)
++{
++ dwc_otg_adp_write_reg(core_if,
++ (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
++}
++
++static void adp_sense_timeout(void *ptr)
++{
++ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++ core_if->adp.sense_timer_started = 0;
++ DWC_PRINTF("ADP SENSE TIMEOUT\n");
++ if (core_if->adp_enable) {
++ dwc_otg_adp_sense_stop(core_if);
++ dwc_otg_adp_probe_start(core_if);
++ }
++}
++
++/**
++ * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
++ */
++static void adp_vbuson_timeout(void *ptr)
++{
++ gpwrdn_data_t gpwrdn;
++ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
++ hprt0_data_t hprt0 = {.d32 = 0 };
++ pcgcctl_data_t pcgcctl = {.d32 = 0 };
++ DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
++ if (core_if) {
++ core_if->adp.vbuson_timer_started = 0;
++ /* Turn off vbus */
++ hprt0.b.prtpwr = 1;
++ DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
++ gpwrdn.d32 = 0;
++
++ /* Power off the core */
++ if (core_if->power_down == 2) {
++ /* Enable Wakeup Logic */
++// gpwrdn.b.wkupactiv = 1;
++ gpwrdn.b.pmuactv = 0;
++ gpwrdn.b.pwrdnrstn = 1;
++ gpwrdn.b.pwrdnclmp = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++ gpwrdn.d32);
++
++ /* Suspend the Phy Clock */
++ pcgcctl.b.stoppclk = 1;
++ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
++
++ /* Switch on VDD */
++// gpwrdn.b.wkupactiv = 1;
++ gpwrdn.b.pmuactv = 1;
++ gpwrdn.b.pwrdnrstn = 1;
++ gpwrdn.b.pwrdnclmp = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++ gpwrdn.d32);
++ } else {
++ /* Enable Power Down Logic */
++ gpwrdn.b.pmuintsel = 1;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++ }
++
++ /* Power off the core */
++ if (core_if->power_down == 2) {
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pwrdnswtch = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
++ gpwrdn.d32, 0);
++ }
++
++ /* Unmask SRP detected interrupt from Power Down Logic */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.srp_det_msk = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++
++ dwc_otg_adp_probe_start(core_if);
++ dwc_otg_dump_global_registers(core_if);
++ dwc_otg_dump_host_registers(core_if);
++ }
++
++}
++
++/**
++ * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
++ * not asserted within 1.1 seconds.
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
++{
++ core_if->adp.vbuson_timer_started = 1;
++ if (core_if->adp.vbuson_timer)
++ {
++ DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
++ /* 1.1 secs + 60ms necessary for cil_hcd_start*/
++ DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
++ } else {
++ DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
++ }
++}
++
++#if 0
++/**
++ * Masks all DWC OTG core interrupts
++ *
++ */
++static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
++{
++ int i;
++ gahbcfg_data_t ahbcfg = {.d32 = 0 };
++
++ /* Mask Host Interrupts */
++
++ /* Clear and disable HCINTs */
++ for (i = 0; i < core_if->core_params->host_channels; i++) {
++ DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
++ DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
++
++ }
++
++ /* Clear and disable HAINT */
++ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
++ DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
++
++ /* Mask Device Interrupts */
++ if (!core_if->multiproc_int_enable) {
++ /* Clear and disable IN Endpoint interrupts */
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
++ for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
++ diepint, 0xFFFFFFFF);
++ }
++
++ /* Clear and disable OUT Endpoint interrupts */
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
++ for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
++ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
++ doepint, 0xFFFFFFFF);
++ }
++
++ /* Clear and disable DAINT */
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
++ 0xFFFFFFFF);
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
++ } else {
++ for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++ diepeachintmsk[i], 0);
++ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
++ diepint, 0xFFFFFFFF);
++ }
++
++ for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++ doepeachintmsk[i], 0);
++ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
++ doepint, 0xFFFFFFFF);
++ }
++
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
++ 0);
++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
++ 0xFFFFFFFF);
++
++ }
++
++ /* Disable interrupts */
++ ahbcfg.b.glblintrmsk = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
++
++ /* Disable all interrupts. */
++ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
++
++ /* Clear any pending interrupts */
++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++ /* Clear any pending OTG Interrupts */
++ DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
++}
++
++/**
++ * Unmask Port Connection Detected interrupt
++ *
++ */
++static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
++{
++ gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
++
++ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
++}
++#endif
++
++/**
++ * Starts the ADP Probing
++ *
++ * @param core_if the pointer to core_if structure.
++ */
++uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
++{
++
++ adpctl_data_t adpctl = {.d32 = 0};
++ gpwrdn_data_t gpwrdn;
++#if 0
++ adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
++ .b.adp_sns_int = 1, b.adp_tmout_int};
++#endif
++ dwc_otg_disable_global_interrupts(core_if);
++ DWC_PRINTF("ADP Probe Start\n");
++ core_if->adp.probe_enabled = 1;
++
++ adpctl.b.adpres = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ while (adpctl.b.adpres) {
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ }
++
++ adpctl.d32 = 0;
++ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++
++ /* In Host mode unmask SRP detected interrupt */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.sts_chngint_msk = 1;
++ if (!gpwrdn.b.idsts) {
++ gpwrdn.b.srp_det_msk = 1;
++ }
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++
++ adpctl.b.adp_tmout_int_msk = 1;
++ adpctl.b.adp_prb_int_msk = 1;
++ adpctl.b.prb_dschg = 1;
++ adpctl.b.prb_delta = 1;
++ adpctl.b.prb_per = 1;
++ adpctl.b.adpen = 1;
++ adpctl.b.enaprb = 1;
++
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++ DWC_PRINTF("ADP Probe Finish\n");
++ return 0;
++}
++
++/**
++ * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
++ * within 3 seconds.
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
++{
++ core_if->adp.sense_timer_started = 1;
++ DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
++}
++
++/**
++ * Starts the ADP Sense
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
++{
++ adpctl_data_t adpctl;
++
++ DWC_PRINTF("ADP Sense Start\n");
++
++ /* Unmask ADP sense interrupt and mask all other from the core */
++ adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
++ adpctl.b.adp_sns_int_msk = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++ dwc_otg_disable_global_interrupts(core_if); // vahrama
++
++ /* Set ADP reset bit*/
++ adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
++ adpctl.b.adpres = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ while (adpctl.b.adpres) {
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ }
++
++ adpctl.b.adpres = 0;
++ adpctl.b.adpen = 1;
++ adpctl.b.enasns = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ dwc_otg_adp_sense_timer_start(core_if);
++
++ return 0;
++}
++
++/**
++ * Stops the ADP Probing
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
++{
++
++ adpctl_data_t adpctl;
++ DWC_PRINTF("Stop ADP probe\n");
++ core_if->adp.probe_enabled = 0;
++ core_if->adp.probe_counter = 0;
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++
++ adpctl.b.adpen = 0;
++ adpctl.b.adp_prb_int = 1;
++ adpctl.b.adp_tmout_int = 1;
++ adpctl.b.adp_sns_int = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ return 0;
++}
++
++/**
++ * Stops the ADP Sensing
++ *
++ * @param core_if the pointer to core_if strucure.
++ */
++uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
++{
++ adpctl_data_t adpctl;
++
++ core_if->adp.sense_enabled = 0;
++
++ adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
++ adpctl.b.enasns = 0;
++ adpctl.b.adp_sns_int = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ return 0;
++}
++
++/**
++ * Called to turn on the VBUS after initial ADP probe in host mode.
++ * If port power was already enabled in cil_hcd_start function then
++ * only schedule a timer.
++ *
++ * @param core_if the pointer to core_if structure.
++ */
++void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
++{
++ hprt0_data_t hprt0 = {.d32 = 0 };
++ hprt0.d32 = dwc_otg_read_hprt0(core_if);
++ DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
++
++ if (hprt0.b.prtpwr == 0) {
++ hprt0.b.prtpwr = 1;
++ //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++ }
++
++ dwc_otg_adp_vbuson_timer_start(core_if);
++}
++
++/**
++ * Called right after driver is loaded
++ * to perform initial actions for ADP
++ *
++ * @param core_if the pointer to core_if structure.
++ * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
++ */
++void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
++{
++ gpwrdn_data_t gpwrdn;
++
++ DWC_PRINTF("ADP Initial Start\n");
++ core_if->adp.adp_started = 1;
++
++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++ dwc_otg_disable_global_interrupts(core_if);
++ if (is_host) {
++ DWC_PRINTF("HOST MODE\n");
++ /* Enable Power Down Logic Interrupt*/
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pmuintsel = 1;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++ /* Initialize first ADP probe to obtain Ramp Time value */
++ core_if->adp.initial_probe = 1;
++ dwc_otg_adp_probe_start(core_if);
++ } else {
++ gotgctl_data_t gotgctl;
++ gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++ DWC_PRINTF("DEVICE MODE\n");
++ if (gotgctl.b.bsesvld == 0) {
++ /* Enable Power Down Logic Interrupt*/
++ gpwrdn.d32 = 0;
++ DWC_PRINTF("VBUS is not valid - start ADP probe\n");
++ gpwrdn.b.pmuintsel = 1;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++ core_if->adp.initial_probe = 1;
++ dwc_otg_adp_probe_start(core_if);
++ } else {
++ DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
++ core_if->op_state = B_PERIPHERAL;
++ dwc_otg_core_init(core_if);
++ dwc_otg_enable_global_interrupts(core_if);
++ cil_pcd_start(core_if);
++ dwc_otg_dump_global_registers(core_if);
++ dwc_otg_dump_dev_registers(core_if);
++ }
++ }
++}
++
++void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
++{
++ core_if->adp.adp_started = 0;
++ core_if->adp.initial_probe = 0;
++ core_if->adp.probe_timer_values[0] = -1;
++ core_if->adp.probe_timer_values[1] = -1;
++ core_if->adp.probe_enabled = 0;
++ core_if->adp.sense_enabled = 0;
++ core_if->adp.sense_timer_started = 0;
++ core_if->adp.vbuson_timer_started = 0;
++ core_if->adp.probe_counter = 0;
++ core_if->adp.gpwrdn = 0;
++ core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
++ /* Initialize timers */
++ core_if->adp.sense_timer =
++ DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
++ core_if->adp.vbuson_timer =
++ DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
++ if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
++ {
++ DWC_ERROR("Could not allocate memory for ADP timers\n");
++ }
++}
++
++void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
++{
++ gpwrdn_data_t gpwrdn = { .d32 = 0 };
++ gpwrdn.b.pmuintsel = 1;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++ if (core_if->adp.probe_enabled)
++ dwc_otg_adp_probe_stop(core_if);
++ if (core_if->adp.sense_enabled)
++ dwc_otg_adp_sense_stop(core_if);
++ if (core_if->adp.sense_timer_started)
++ DWC_TIMER_CANCEL(core_if->adp.sense_timer);
++ if (core_if->adp.vbuson_timer_started)
++ DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
++ DWC_TIMER_FREE(core_if->adp.sense_timer);
++ DWC_TIMER_FREE(core_if->adp.vbuson_timer);
++}
++
++/////////////////////////////////////////////////////////////////////
++////////////// ADP Interrupt Handlers ///////////////////////////////
++/////////////////////////////////////////////////////////////////////
++/**
++ * This function sets Ramp Timer values
++ */
++static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
++{
++ if (core_if->adp.probe_timer_values[0] == -1) {
++ core_if->adp.probe_timer_values[0] = val;
++ core_if->adp.probe_timer_values[1] = -1;
++ return 1;
++ } else {
++ core_if->adp.probe_timer_values[1] =
++ core_if->adp.probe_timer_values[0];
++ core_if->adp.probe_timer_values[0] = val;
++ return 0;
++ }
++}
++
++/**
++ * This function compares Ramp Timer values
++ */
++static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
++{
++ uint32_t diff;
++ if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
++ diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
++ else
++ diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
++ if(diff < 2) {
++ return 0;
++ } else {
++ return 1;
++ }
++}
++
++/**
++ * This function handles ADP Probe Interrupts
++ */
++static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
++ uint32_t val)
++{
++ adpctl_data_t adpctl = {.d32 = 0 };
++ gpwrdn_data_t gpwrdn, temp;
++ adpctl.d32 = val;
++
++ temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++ core_if->adp.probe_counter++;
++ core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++ if (adpctl.b.rtim == 0 && !temp.b.idsts){
++ DWC_PRINTF("RTIM value is 0\n");
++ goto exit;
++ }
++ if (set_timer_value(core_if, adpctl.b.rtim) &&
++ core_if->adp.initial_probe) {
++ core_if->adp.initial_probe = 0;
++ dwc_otg_adp_probe_stop(core_if);
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pmuactv = 1;
++ gpwrdn.b.pmuintsel = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++ /* check which value is for device mode and which for Host mode */
++ if (!temp.b.idsts) { /* considered host mode value is 0 */
++ /*
++ * Turn on VBUS after initial ADP probe.
++ */
++ core_if->op_state = A_HOST;
++ dwc_otg_enable_global_interrupts(core_if);
++ DWC_SPINUNLOCK(core_if->lock);
++ cil_hcd_start(core_if);
++ dwc_otg_adp_turnon_vbus(core_if);
++ DWC_SPINLOCK(core_if->lock);
++ } else {
++ /*
++ * Initiate SRP after initial ADP probe.
++ */
++ dwc_otg_enable_global_interrupts(core_if);
++ dwc_otg_initiate_srp(core_if);
++ }
++ } else if (core_if->adp.probe_counter > 2){
++ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++ if (compare_timer_values(core_if)) {
++ DWC_PRINTF("Difference in timer values !!! \n");
++// core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
++ dwc_otg_adp_probe_stop(core_if);
++
++ /* Power on the core */
++ if (core_if->power_down == 2) {
++ gpwrdn.b.pwrdnswtch = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->
++ gpwrdn, 0, gpwrdn.d32);
++ }
++
++ /* check which value is for device mode and which for Host mode */
++ if (!temp.b.idsts) { /* considered host mode value is 0 */
++ /* Disable Interrupt from Power Down Logic */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pmuintsel = 1;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->
++ gpwrdn, gpwrdn.d32, 0);
++
++ /*
++ * Initialize the Core for Host mode.
++ */
++ core_if->op_state = A_HOST;
++ dwc_otg_core_init(core_if);
++ dwc_otg_enable_global_interrupts(core_if);
++ cil_hcd_start(core_if);
++ } else {
++ gotgctl_data_t gotgctl;
++ /* Mask SRP detected interrupt from Power Down Logic */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.srp_det_msk = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->
++ gpwrdn, gpwrdn.d32, 0);
++
++ /* Disable Power Down Logic */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pmuintsel = 1;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->
++ gpwrdn, gpwrdn.d32, 0);
++
++ /*
++ * Initialize the Core for Device mode.
++ */
++ core_if->op_state = B_PERIPHERAL;
++ dwc_otg_core_init(core_if);
++ dwc_otg_enable_global_interrupts(core_if);
++ cil_pcd_start(core_if);
++
++ gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++ if (!gotgctl.b.bsesvld) {
++ dwc_otg_initiate_srp(core_if);
++ }
++ }
++ }
++ if (core_if->power_down == 2) {
++ if (gpwrdn.b.bsessvld) {
++ /* Mask SRP detected interrupt from Power Down Logic */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.srp_det_msk = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++ /* Disable Power Down Logic */
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pmuactv = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++ /*
++ * Initialize the Core for Device mode.
++ */
++ core_if->op_state = B_PERIPHERAL;
++ dwc_otg_core_init(core_if);
++ dwc_otg_enable_global_interrupts(core_if);
++ cil_pcd_start(core_if);
++ }
++ }
++ }
++exit:
++ /* Clear interrupt */
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ adpctl.b.adp_prb_int = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ return 0;
++}
++
++/**
++ * This function hadles ADP Sense Interrupt
++ */
++static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
++{
++ adpctl_data_t adpctl;
++ /* Stop ADP Sense timer */
++ DWC_TIMER_CANCEL(core_if->adp.sense_timer);
++
++ /* Restart ADP Sense timer */
++ dwc_otg_adp_sense_timer_start(core_if);
++
++ /* Clear interrupt */
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ adpctl.b.adp_sns_int = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ return 0;
++}
++
++/**
++ * This function handles ADP Probe Interrupts
++ */
++static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
++ uint32_t val)
++{
++ adpctl_data_t adpctl = {.d32 = 0 };
++ adpctl.d32 = val;
++ set_timer_value(core_if, adpctl.b.rtim);
++
++ /* Clear interrupt */
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ adpctl.b.adp_tmout_int = 1;
++ dwc_otg_adp_write_reg(core_if, adpctl.d32);
++
++ return 0;
++}
++
++/**
++ * ADP Interrupt handler.
++ *
++ */
++int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
++{
++ int retval = 0;
++ adpctl_data_t adpctl = {.d32 = 0};
++
++ adpctl.d32 = dwc_otg_adp_read_reg(core_if);
++ DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
++
++ if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
++ DWC_PRINTF("ADP Sense interrupt\n");
++ retval |= dwc_otg_adp_handle_sns_intr(core_if);
++ }
++ if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
++ DWC_PRINTF("ADP timeout interrupt\n");
++ retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
++ }
++ if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
++ DWC_PRINTF("ADP Probe interrupt\n");
++ adpctl.b.adp_prb_int = 1;
++ retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
++ }
++
++// dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
++ //dwc_otg_adp_write_reg(core_if, adpctl.d32);
++ DWC_PRINTF("RETURN FROM ADP ISR\n");
++
++ return retval;
++}
++
++/**
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
++{
++
++#ifndef DWC_HOST_ONLY
++ hprt0_data_t hprt0;
++ gpwrdn_data_t gpwrdn;
++ DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
++
++ gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
++ /* check which value is for device mode and which for Host mode */
++ if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
++ DWC_PRINTF("SRP: Host mode\n");
++
++ if (core_if->adp_enable) {
++ dwc_otg_adp_probe_stop(core_if);
++
++ /* Power on the core */
++ if (core_if->power_down == 2) {
++ gpwrdn.b.pwrdnswtch = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->
++ gpwrdn, 0, gpwrdn.d32);
++ }
++
++ core_if->op_state = A_HOST;
++ dwc_otg_core_init(core_if);
++ dwc_otg_enable_global_interrupts(core_if);
++ cil_hcd_start(core_if);
++ }
++
++ /* Turn on the port power bit. */
++ hprt0.d32 = dwc_otg_read_hprt0(core_if);
++ hprt0.b.prtpwr = 1;
++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++ /* Start the Connection timer. So a message can be displayed
++ * if connect does not occur within 10 seconds. */
++ cil_hcd_session_start(core_if);
++ } else {
++ DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
++ if (core_if->adp_enable) {
++ dwc_otg_adp_probe_stop(core_if);
++
++ /* Power on the core */
++ if (core_if->power_down == 2) {
++ gpwrdn.b.pwrdnswtch = 1;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->
++ gpwrdn, 0, gpwrdn.d32);
++ }
++
++ gpwrdn.d32 = 0;
++ gpwrdn.b.pmuactv = 0;
++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
++ gpwrdn.d32);
++
++ core_if->op_state = B_PERIPHERAL;
++ dwc_otg_core_init(core_if);
++ dwc_otg_enable_global_interrupts(core_if);
++ cil_pcd_start(core_if);
++ }
++ }
++#endif
++ return 1;
++}
+diff --git a/drivers/usb/host/dwc_otg/dwc_otg_adp.h b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
+new file mode 100644
+index 000000000000..4110b25d2002
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_adp.h
+@@ -0,0 +1,80 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.h $
++ * $Revision: #7 $
++ * $Date: 2011/10/24 $
++ * $Change: 1871159 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#ifndef __DWC_OTG_ADP_H__
++#define __DWC_OTG_ADP_H__
++
++/**
++ * @file
++ *
++ * This file contains the Attach Detect Protocol interfaces and defines
++ * (functions) and structures for Linux.
++ *
++ */
++
++#define DWC_OTG_ADP_UNATTACHED 0
++#define DWC_OTG_ADP_ATTACHED 1
++#define DWC_OTG_ADP_UNKOWN 2
++
++typedef struct dwc_otg_adp {
++ uint32_t adp_started;
++ uint32_t initial_probe;
++ int32_t probe_timer_values[2];
++ uint32_t probe_enabled;
++ uint32_t sense_enabled;
++ dwc_timer_t *sense_timer;
++ uint32_t sense_timer_started;
++ dwc_timer_t *vbuson_timer;
++ uint32_t vbuson_timer_started;
++ uint32_t attached;
++ uint32_t probe_counter;
++ uint32_t gpwrdn;
++} dwc_otg_adp_t;
++
++/**
++ * Attach Detect Protocol functions
++ */
++
++extern void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value);
++extern uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if);
++extern uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host);
++extern void dwc_otg_adp_init(dwc_otg_core_if_t * core_if);
++extern void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if);
++extern int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if);
++extern int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if);
++
++#endif //__DWC_OTG_ADP_H__
+diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
+new file mode 100644
+index 000000000000..2f8ea77c3892
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
+@@ -0,0 +1,1212 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
++ * $Revision: #44 $
++ * $Date: 2010/11/29 $
++ * $Change: 1636033 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++/** @file
++ *
++ * The diagnostic interface will provide access to the controller for
++ * bringing up the hardware and testing. The Linux driver attributes
++ * feature will be used to provide the Linux Diagnostic
++ * Interface. These attributes are accessed through sysfs.
++ */
++
++/** @page "Linux Module Attributes"
++ *
++ * The Linux module attributes feature is used to provide the Linux
++ * Diagnostic Interface. These attributes are accessed through sysfs.
++ * The diagnostic interface will provide access to the controller for
++ * bringing up the hardware and testing.
++
++ The following table shows the attributes.
++ <table>
++ <tr>
++ <td><b> Name</b></td>
++ <td><b> Description</b></td>
++ <td><b> Access</b></td>
++ </tr>
++
++ <tr>
++ <td> mode </td>
++ <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hnpcapable </td>
++ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> srpcapable </td>
++ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> hsic_connect </td>
++ <td> Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> inv_sel_hsic </td>
++ <td> Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register.
++ Read returns the current value.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> hnp </td>
++ <td> Initiates the Host Negotiation Protocol. Read returns the status.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> srp </td>
++ <td> Initiates the Session Request Protocol. Read returns the status.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> buspower </td>
++ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> bussuspend </td>
++ <td> Suspends the USB bus.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> busconnected </td>
++ <td> Gets the connection status of the bus</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> gotgctl </td>
++ <td> Gets or sets the Core Control Status Register.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gusbcfg </td>
++ <td> Gets or sets the Core USB Configuration Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> grxfsiz </td>
++ <td> Gets or sets the Receive FIFO Size Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gnptxfsiz </td>
++ <td> Gets or sets the non-periodic Transmit Size Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gpvndctl </td>
++ <td> Gets or sets the PHY Vendor Control Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> ggpio </td>
++ <td> Gets the value in the lower 16-bits of the General Purpose IO Register
++ or sets the upper 16 bits.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> guid </td>
++ <td> Gets or sets the value of the User ID Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> gsnpsid </td>
++ <td> Gets the value of the Synopsys ID Regester</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> devspeed </td>
++ <td> Gets or sets the device speed setting in the DCFG register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> enumspeed </td>
++ <td> Gets the device enumeration Speed.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hptxfsiz </td>
++ <td> Gets the value of the Host Periodic Transmit FIFO</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hprt0 </td>
++ <td> Gets or sets the value in the Host Port Control and Status Register</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regoffset </td>
++ <td> Sets the register offset for the next Register Access</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regvalue </td>
++ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> remote_wakeup </td>
++ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
++ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
++ Wakeup signalling bit in the Device Control Register is set for 1
++ milli-second.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> rem_wakeup_pwrdn </td>
++ <td> On read, shows the status core - hibernated or not. On write, initiates
++ a remote wakeup of the device from Hibernation. </td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> mode_ch_tim_en </td>
++ <td> This bit is used to enable or disable the host core to wait for 200 PHY
++ clock cycles at the end of Resume to change the opmode signal to the PHY to 00
++ after Suspend or LPM. </td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> fr_interval </td>
++ <td> On read, shows the value of HFIR Frame Interval. On write, dynamically
++ reload HFIR register during runtime. The application can write a value to this
++ register only after the Port Enable bit of the Host Port Control and Status
++ register (HPRT.PrtEnaPort) has been set </td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> disconnect_us </td>
++ <td> On read, shows the status of disconnect_device_us. On write, sets disconnect_us
++ which causes soft disconnect for 100us. Applicable only for device mode of operation.</td>
++ <td> Read/Write</td>
++ </tr>
++
++ <tr>
++ <td> regdump </td>
++ <td> Dumps the contents of core registers.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> spramdump </td>
++ <td> Dumps the contents of core registers.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hcddump </td>
++ <td> Dumps the current HCD state.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> hcd_frrem </td>
++ <td> Shows the average value of the Frame Remaining
++ field in the Host Frame Number/Frame Remaining register when an SOF interrupt
++ occurs. This can be used to determine the average interrupt latency. Also
++ shows the average Frame Remaining value for start_transfer and the "a" and
++ "b" sample points. The "a" and "b" sample points may be used during debugging
++ bto determine how long it takes to execute a section of the HCD code.</td>
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> rd_reg_test </td>
++ <td> Displays the time required to read the GNPTXFSIZ register many times
++ (the output shows the number of times the register is read).
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> wr_reg_test </td>
++ <td> Displays the time required to write the GNPTXFSIZ register many times
++ (the output shows the number of times the register is written).
++ <td> Read</td>
++ </tr>
++
++ <tr>
++ <td> lpm_response </td>
++ <td> Gets or sets lpm_response mode. Applicable only in device mode.
++ <td> Write</td>
++ </tr>
++
++ <tr>
++ <td> sleep_status </td>
++ <td> Shows sleep status of device.
++ <td> Read</td>
++ </tr>
++
++ </table>
++
++ Example usage:
++ To get the current mode:
++ cat /sys/devices/lm0/mode
++
++ To power down the USB:
++ echo 0 > /sys/devices/lm0/buspower
++ */
++
++#include "dwc_otg_os_dep.h"
++#include "dwc_os.h"
++#include "dwc_otg_driver.h"
++#include "dwc_otg_attr.h"
++#include "dwc_otg_core_if.h"
++#include "dwc_otg_pcd_if.h"
++#include "dwc_otg_hcd_if.h"
++
++/*
++ * MACROs for defining sysfs attribute
++ */
++#ifdef LM_INTERFACE
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
++ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
++ uint32_t val; \
++ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
++ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
++ uint32_t set = simple_strtoul(buf, NULL, 16); \
++ dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
++ return count; \
++}
++
++#elif defined(PCI_INTERFACE)
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
++ uint32_t val; \
++ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
++ uint32_t set = simple_strtoul(buf, NULL, 16); \
++ dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
++ return count; \
++}
++
++#elif defined(PLATFORM_INTERFACE)
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++ struct platform_device *platform_dev = \
++ container_of(_dev, struct platform_device, dev); \
++ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
++ uint32_t val; \
++ DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
++ __func__, _dev, platform_dev, otg_dev); \
++ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++ return sprintf (buf, "%s = 0x%x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
++ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
++ uint32_t set = simple_strtoul(buf, NULL, 16); \
++ dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
++ return count; \
++}
++#endif
++
++/*
++ * MACROs for defining sysfs attribute for 32-bit registers
++ */
++#ifdef LM_INTERFACE
++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
++ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
++ uint32_t val; \
++ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
++ dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
++ uint32_t val = simple_strtoul(buf, NULL, 16); \
++ dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
++ return count; \
++}
++#elif defined(PCI_INTERFACE)
++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
++ uint32_t val; \
++ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \
++ uint32_t val = simple_strtoul(buf, NULL, 16); \
++ dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
++ return count; \
++}
++
++#elif defined(PLATFORM_INTERFACE)
++#include "dwc_otg_dbg.h"
++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
++{ \
++ struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
++ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
++ uint32_t val; \
++ DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \
++ __func__, _dev, platform_dev, otg_dev); \
++ val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
++ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
++}
++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
++ const char *buf, size_t count) \
++{ \
++ struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \
++ dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \
++ uint32_t val = simple_strtoul(buf, NULL, 16); \
++ dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
++ return count; \
++}
++
++#endif
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
++
++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
++
++#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
++
++#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
++
++/** @name Functions for Show/Store of Attributes */
++/**@{*/
++
++/**
++ * Helper function returning the otg_device structure of the given device
++ */
++static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev)
++{
++ dwc_otg_device_t *otg_dev;
++ DWC_OTG_GETDRVDEV(otg_dev, _dev);
++ return otg_dev;
++}
++
++/**
++ * Show the register offset of the Register Access.
++ */
++static ssize_t regoffset_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
++ otg_dev->os_dep.reg_offset);
++}
++
++/**
++ * Set the register offset for the next Register Access Read/Write
++ */
++static ssize_t regoffset_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t offset = simple_strtoul(buf, NULL, 16);
++#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
++ if (offset < SZ_256K) {
++#elif defined(PCI_INTERFACE)
++ if (offset < 0x00040000) {
++#endif
++ otg_dev->os_dep.reg_offset = offset;
++ } else {
++ dev_err(_dev, "invalid offset\n");
++ }
++
++ return count;
++}
++
++DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
++
++/**
++ * Show the value of the register at the offset in the reg_offset
++ * attribute.
++ */
++static ssize_t regvalue_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t val;
++ volatile uint32_t *addr;
++
++ if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
++ /* Calculate the address */
++ addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
++ (uint8_t *) otg_dev->os_dep.base);
++ val = DWC_READ_REG32(addr);
++ return snprintf(buf,
++ sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
++ "Reg@0x%06x = 0x%08x\n", otg_dev->os_dep.reg_offset,
++ val);
++ } else {
++ dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->os_dep.reg_offset);
++ return sprintf(buf, "invalid offset\n");
++ }
++}
++
++/**
++ * Store the value in the register at the offset in the reg_offset
++ * attribute.
++ *
++ */
++static ssize_t regvalue_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ volatile uint32_t *addr;
++ uint32_t val = simple_strtoul(buf, NULL, 16);
++ //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
++ if (otg_dev->os_dep.reg_offset != 0xFFFFFFFF && 0 != otg_dev->os_dep.base) {
++ /* Calculate the address */
++ addr = (uint32_t *) (otg_dev->os_dep.reg_offset +
++ (uint8_t *) otg_dev->os_dep.base);
++ DWC_WRITE_REG32(addr, val);
++ } else {
++ dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
++ otg_dev->os_dep.reg_offset);
++ }
++ return count;
++}
++
++DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
++
++/*
++ * Attributes
++ */
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
++
++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
++
++DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
++ &(otg_dev->core_if->core_global_regs->gusbcfg),
++ "GUSBCFG");
++DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
++ &(otg_dev->core_if->core_global_regs->grxfsiz),
++ "GRXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
++ &(otg_dev->core_if->core_global_regs->gnptxfsiz),
++ "GNPTXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
++ &(otg_dev->core_if->core_global_regs->gpvndctl),
++ "GPVNDCTL");
++DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
++ &(otg_dev->core_if->core_global_regs->ggpio),
++ "GGPIO");
++DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
++ "GUID");
++DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
++ &(otg_dev->core_if->core_global_regs->gsnpsid),
++ "GSNPSID");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
++
++DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
++ &(otg_dev->core_if->core_global_regs->hptxfsiz),
++ "HPTXFSIZ");
++DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
++
++/**
++ * @todo Add code to initiate the HNP.
++ */
++/**
++ * Show the HNP status bit
++ */
++static ssize_t hnp_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "HstNegScs = 0x%x\n",
++ dwc_otg_get_hnpstatus(otg_dev->core_if));
++}
++
++/**
++ * Set the HNP Request bit
++ */
++static ssize_t hnp_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t in = simple_strtoul(buf, NULL, 16);
++ dwc_otg_set_hnpreq(otg_dev->core_if, in);
++ return count;
++}
++
++DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
++
++/**
++ * @todo Add code to initiate the SRP.
++ */
++/**
++ * Show the SRP status bit
++ */
++static ssize_t srp_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "SesReqScs = 0x%x\n",
++ dwc_otg_get_srpstatus(otg_dev->core_if));
++#else
++ return sprintf(buf, "Host Only Mode!\n");
++#endif
++}
++
++/**
++ * Set the SRP Request bit
++ */
++static ssize_t srp_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ dwc_otg_pcd_initiate_srp(otg_dev->pcd);
++#endif
++ return count;
++}
++
++DEVICE_ATTR(srp, 0644, srp_show, srp_store);
++
++/**
++ * @todo Need to do more for power on/off?
++ */
++/**
++ * Show the Bus Power status
++ */
++static ssize_t buspower_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "Bus Power = 0x%x\n",
++ dwc_otg_get_prtpower(otg_dev->core_if));
++}
++
++/**
++ * Set the Bus Power status
++ */
++static ssize_t buspower_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t on = simple_strtoul(buf, NULL, 16);
++ dwc_otg_set_prtpower(otg_dev->core_if, on);
++ return count;
++}
++
++DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
++
++/**
++ * @todo Need to do more for suspend?
++ */
++/**
++ * Show the Bus Suspend status
++ */
++static ssize_t bussuspend_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "Bus Suspend = 0x%x\n",
++ dwc_otg_get_prtsuspend(otg_dev->core_if));
++}
++
++/**
++ * Set the Bus Suspend status
++ */
++static ssize_t bussuspend_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t in = simple_strtoul(buf, NULL, 16);
++ dwc_otg_set_prtsuspend(otg_dev->core_if, in);
++ return count;
++}
++
++DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
++
++/**
++ * Show the Mode Change Ready Timer status
++ */
++static ssize_t mode_ch_tim_en_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "Mode Change Ready Timer Enable = 0x%x\n",
++ dwc_otg_get_mode_ch_tim(otg_dev->core_if));
++}
++
++/**
++ * Set the Mode Change Ready Timer status
++ */
++static ssize_t mode_ch_tim_en_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t in = simple_strtoul(buf, NULL, 16);
++ dwc_otg_set_mode_ch_tim(otg_dev->core_if, in);
++ return count;
++}
++
++DEVICE_ATTR(mode_ch_tim_en, 0644, mode_ch_tim_en_show, mode_ch_tim_en_store);
++
++/**
++ * Show the value of HFIR Frame Interval bitfield
++ */
++static ssize_t fr_interval_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "Frame Interval = 0x%x\n",
++ dwc_otg_get_fr_interval(otg_dev->core_if));
++}
++
++/**
++ * Set the HFIR Frame Interval value
++ */
++static ssize_t fr_interval_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t in = simple_strtoul(buf, NULL, 10);
++ dwc_otg_set_fr_interval(otg_dev->core_if, in);
++ return count;
++}
++
++DEVICE_ATTR(fr_interval, 0644, fr_interval_show, fr_interval_store);
++
++/**
++ * Show the status of Remote Wakeup.
++ */
++static ssize_t remote_wakeup_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++ return sprintf(buf,
++ "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
++ dwc_otg_get_remotewakesig(otg_dev->core_if),
++ dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
++ dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
++#else
++ return sprintf(buf, "Host Only Mode!\n");
++#endif /* DWC_HOST_ONLY */
++}
++
++/**
++ * Initiate a remote wakeup of the host. The Device control register
++ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
++ * flag is set.
++ *
++ */
++static ssize_t remote_wakeup_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t val = simple_strtoul(buf, NULL, 16);
++
++ if (val & 1) {
++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
++ } else {
++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
++ }
++#endif /* DWC_HOST_ONLY */
++ return count;
++}
++
++DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
++ remote_wakeup_store);
++
++/**
++ * Show the whether core is hibernated or not.
++ */
++static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++ if (dwc_otg_get_core_state(otg_dev->core_if)) {
++ DWC_PRINTF("Core is in hibernation\n");
++ } else {
++ DWC_PRINTF("Core is not in hibernation\n");
++ }
++#endif /* DWC_HOST_ONLY */
++ return 0;
++}
++
++extern int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
++ int rem_wakeup, int reset);
++
++/**
++ * Initiate a remote wakeup of the device to exit from hibernation.
++ */
++static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
++#endif
++ return count;
++}
++
++DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
++ rem_wakeup_pwrdn_store);
++
++static ssize_t disconnect_us(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++
++#ifndef DWC_HOST_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t val = simple_strtoul(buf, NULL, 16);
++ DWC_PRINTF("The Passed value is %04x\n", val);
++
++ dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);
++
++#endif /* DWC_HOST_ONLY */
++ return count;
++}
++
++DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);
++
++/**
++ * Dump global registers and either host or device registers (depending on the
++ * current mode of the core).
++ */
++static ssize_t regdump_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++ dwc_otg_dump_global_registers(otg_dev->core_if);
++ if (dwc_otg_is_host_mode(otg_dev->core_if)) {
++ dwc_otg_dump_host_registers(otg_dev->core_if);
++ } else {
++ dwc_otg_dump_dev_registers(otg_dev->core_if);
++
++ }
++ return sprintf(buf, "Register Dump\n");
++}
++
++DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0);
++
++/**
++ * Dump global registers and either host or device registers (depending on the
++ * current mode of the core).
++ */
++static ssize_t spramdump_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++#if 0
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++ dwc_otg_dump_spram(otg_dev->core_if);
++#endif
++
++ return sprintf(buf, "SPRAM Dump\n");
++}
++
++DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0);
++
++/**
++ * Dump the current hcd state.
++ */
++static ssize_t hcddump_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_DEVICE_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ dwc_otg_hcd_dump_state(otg_dev->hcd);
++#endif /* DWC_DEVICE_ONLY */
++ return sprintf(buf, "HCD Dump\n");
++}
++
++DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0);
++
++/**
++ * Dump the average frame remaining at SOF. This can be used to
++ * determine average interrupt latency. Frame remaining is also shown for
++ * start transfer and two additional sample points.
++ */
++static ssize_t hcd_frrem_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++#ifndef DWC_DEVICE_ONLY
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++ dwc_otg_hcd_dump_frrem(otg_dev->hcd);
++#endif /* DWC_DEVICE_ONLY */
++ return sprintf(buf, "HCD Dump Frame Remaining\n");
++}
++
++DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0);
++
++/**
++ * Displays the time required to read the GNPTXFSIZ register many times (the
++ * output shows the number of times the register is read).
++ */
++#define RW_REG_COUNT 10000000
++#define MSEC_PER_JIFFIE 1000/HZ
++static ssize_t rd_reg_test_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ int i;
++ int time;
++ int start_jiffies;
++
++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
++ start_jiffies = jiffies;
++ for (i = 0; i < RW_REG_COUNT; i++) {
++ dwc_otg_get_gnptxfsiz(otg_dev->core_if);
++ }
++ time = jiffies - start_jiffies;
++ return sprintf(buf,
++ "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
++}
++
++DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0);
++
++/**
++ * Displays the time required to write the GNPTXFSIZ register many times (the
++ * output shows the number of times the register is written).
++ */
++static ssize_t wr_reg_test_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t reg_val;
++ int i;
++ int time;
++ int start_jiffies;
++
++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
++ reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
++ start_jiffies = jiffies;
++ for (i = 0; i < RW_REG_COUNT; i++) {
++ dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
++ }
++ time = jiffies - start_jiffies;
++ return sprintf(buf,
++ "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
++}
++
++DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0);
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++
++/**
++* Show the lpm_response attribute.
++*/
++static ssize_t lpmresp_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++ if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
++ return sprintf(buf, "** LPM is DISABLED **\n");
++
++ if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++ return sprintf(buf, "** Current mode is not device mode\n");
++ }
++ return sprintf(buf, "lpm_response = %d\n",
++ dwc_otg_get_lpmresponse(otg_dev->core_if));
++}
++
++/**
++* Store the lpm_response attribute.
++*/
++static ssize_t lpmresp_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ uint32_t val = simple_strtoul(buf, NULL, 16);
++
++ if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
++ return 0;
++ }
++
++ if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
++ return 0;
++ }
++
++ dwc_otg_set_lpmresponse(otg_dev->core_if, val);
++ return count;
++}
++
++DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
++
++/**
++* Show the sleep_status attribute.
++*/
++static ssize_t sleepstatus_show(struct device *_dev,
++ struct device_attribute *attr, char *buf)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ return sprintf(buf, "Sleep Status = %d\n",
++ dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
++}
++
++/**
++ * Store the sleep_status attribure.
++ */
++static ssize_t sleepstatus_store(struct device *_dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++ dwc_otg_core_if_t *core_if = otg_dev->core_if;
++
++ if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
++ if (dwc_otg_is_host_mode(core_if)) {
++
++ DWC_PRINTF("Host initiated resume\n");
++ dwc_otg_set_prtresume(otg_dev->core_if, 1);
++ }
++ }
++
++ return count;
++}
++
++DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
++ sleepstatus_store);
++
++#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
++
++/**@}*/
++
++/**
++ * Create the device files
++ */
++void dwc_otg_attr_create(
++#ifdef LM_INTERFACE
++ struct lm_device *dev
++#elif defined(PCI_INTERFACE)
++ struct pci_dev *dev
++#elif defined(PLATFORM_INTERFACE)
++ struct platform_device *dev
++#endif
++ )
++{
++ int error;
++
++ error = device_create_file(&dev->dev, &dev_attr_regoffset);
++ error = device_create_file(&dev->dev, &dev_attr_regvalue);
++ error = device_create_file(&dev->dev, &dev_attr_mode);
++ error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
++ error = device_create_file(&dev->dev, &dev_attr_srpcapable);
++ error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
++ error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
++ error = device_create_file(&dev->dev, &dev_attr_hnp);
++ error = device_create_file(&dev->dev, &dev_attr_srp);
++ error = device_create_file(&dev->dev, &dev_attr_buspower);
++ error = device_create_file(&dev->dev, &dev_attr_bussuspend);
++ error = device_create_file(&dev->dev, &dev_attr_mode_ch_tim_en);
++ error = device_create_file(&dev->dev, &dev_attr_fr_interval);
++ error = device_create_file(&dev->dev, &dev_attr_busconnected);
++ error = device_create_file(&dev->dev, &dev_attr_gotgctl);
++ error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
++ error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
++ error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
++ error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
++ error = device_create_file(&dev->dev, &dev_attr_ggpio);
++ error = device_create_file(&dev->dev, &dev_attr_guid);
++ error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
++ error = device_create_file(&dev->dev, &dev_attr_devspeed);
++ error = device_create_file(&dev->dev, &dev_attr_enumspeed);
++ error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
++ error = device_create_file(&dev->dev, &dev_attr_hprt0);
++ error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
++ error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
++ error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
++ error = device_create_file(&dev->dev, &dev_attr_regdump);
++ error = device_create_file(&dev->dev, &dev_attr_spramdump);
++ error = device_create_file(&dev->dev, &dev_attr_hcddump);
++ error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
++ error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
++ error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++ error = device_create_file(&dev->dev, &dev_attr_lpm_response);
++ error = device_create_file(&dev->dev, &dev_attr_sleep_status);
++#endif
++}
++
++/**
++ * Remove the device files
++ */
++void dwc_otg_attr_remove(
++#ifdef LM_INTERFACE
++ struct lm_device *dev
++#elif defined(PCI_INTERFACE)
++ struct pci_dev *dev
++#elif defined(PLATFORM_INTERFACE)
++ struct platform_device *dev
++#endif
++ )
++{
++ device_remove_file(&dev->dev, &dev_attr_regoffset);
++ device_remove_file(&dev->dev, &dev_attr_regvalue);
++ device_remove_file(&dev->dev, &dev_attr_mode);
++ device_remove_file(&dev->dev, &dev_attr_hnpcapable);
++ device_remove_file(&dev->dev, &dev_attr_srpcapable);
++ device_remove_file(&dev->dev, &dev_attr_hsic_connect);
++ device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
++ device_remove_file(&dev->dev, &dev_attr_hnp);
++ device_remove_file(&dev->dev, &dev_attr_srp);
++ device_remove_file(&dev->dev, &dev_attr_buspower);
++ device_remove_file(&dev->dev, &dev_attr_bussuspend);
++ device_remove_file(&dev->dev, &dev_attr_mode_ch_tim_en);
++ device_remove_file(&dev->dev, &dev_attr_fr_interval);
++ device_remove_file(&dev->dev, &dev_attr_busconnected);
++ device_remove_file(&dev->dev, &dev_attr_gotgctl);
++ device_remove_file(&dev->dev, &dev_attr_gusbcfg);
++ device_remove_file(&dev->dev, &dev_attr_grxfsiz);
++ device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
++ device_remove_file(&dev->dev, &dev_attr_gpvndctl);
++ device_remove_file(&dev->dev, &dev_attr_ggpio);
++ device_remove_file(&dev->dev, &dev_attr_guid);
++ device_remove_file(&dev->dev, &dev_attr_gsnpsid);
++ device_remove_file(&dev->dev, &dev_attr_devspeed);
++ device_remove_file(&dev->dev, &dev_attr_enumspeed);
++ device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
++ device_remove_file(&dev->dev, &dev_attr_hprt0);
++ device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
++ device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
++ device_remove_file(&dev->dev, &dev_attr_disconnect_us);
++ device_remove_file(&dev->dev, &dev_attr_regdump);
++ device_remove_file(&dev->dev, &dev_attr_spramdump);
++ device_remove_file(&dev->dev, &dev_attr_hcddump);
++ device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
++ device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
++ device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++ device_remove_file(&dev->dev, &dev_attr_lpm_response);
++ device_remove_file(&dev->dev, &dev_attr_sleep_status);
++#endif
++}
+diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.h b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
+new file mode 100644
+index 000000000000..e10b67f97c52
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
+@@ -0,0 +1,89 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
++ * $Revision: #13 $
++ * $Date: 2010/06/21 $
++ * $Change: 1532021 $
++ *
++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================== */
++
++#if !defined(__DWC_OTG_ATTR_H__)
++#define __DWC_OTG_ATTR_H__
++
++/** @file
++ * This file contains the interface to the Linux device attributes.
++ */
++extern struct device_attribute dev_attr_regoffset;
++extern struct device_attribute dev_attr_regvalue;
++
++extern struct device_attribute dev_attr_mode;
++extern struct device_attribute dev_attr_hnpcapable;
++extern struct device_attribute dev_attr_srpcapable;
++extern struct device_attribute dev_attr_hnp;
++extern struct device_attribute dev_attr_srp;
++extern struct device_attribute dev_attr_buspower;
++extern struct device_attribute dev_attr_bussuspend;
++extern struct device_attribute dev_attr_mode_ch_tim_en;
++extern struct device_attribute dev_attr_fr_interval;
++extern struct device_attribute dev_attr_busconnected;
++extern struct device_attribute dev_attr_gotgctl;
++extern struct device_attribute dev_attr_gusbcfg;
++extern struct device_attribute dev_attr_grxfsiz;
++extern struct device_attribute dev_attr_gnptxfsiz;
++extern struct device_attribute dev_attr_gpvndctl;
++extern struct device_attribute dev_attr_ggpio;<