[OpenWrt-Devel] [PATCH] brcm2708: add linux 4.4 support

Álvaro Fernández Rojas noltari at gmail.com
Fri Jan 15 18:18:38 EST 2016


- random-bcm2708 and spi-bcm2708 have been removed.
- sound-soc-bcm2708-i2s has been upstreamed as sound-soc-bcm2835-i2s.

Let's keep linux 4.1 for a while, since linux 4.4 appears to have some issues
with multicast traffic on RPi ethernet:
https://gist.github.com/Noltari/5b1cfdecce5ed4bc08fd

Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
---
 target/linux/brcm2708/bcm2708/config-4.4           |   355 +
 target/linux/brcm2708/bcm2709/config-4.4           |   387 +
 target/linux/brcm2708/modules.mk                   |    65 +-
 ...0001-smsx95xx-fix-crimes-against-truesize.patch |    33 +
 ...02-smsc95xx-Disable-turbo-mode-by-default.patch |    20 +
 ...around-for-issue-where-dirty-page-count-g.patch |    27 +
 .../0004-BCM2835_DT-Fix-I2S-register-map.patch     |    50 +
 ...-Prevent-spurious-interrupts-and-trap-the.patch |    31 +
 .../0006-irqchip-bcm2835-Add-FIQ-support.patch     |   127 +
 ...-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch |    96 +
 ...erial-8250-Don-t-crash-when-nr_uarts-is-0.patch |    20 +
 ...2835-Set-base-to-0-give-expected-gpio-num.patch |    22 +
 ...2835-Fix-interrupt-handling-for-GPIOs-28-.patch |   146 +
 ...2835-Only-request-the-interrupts-listed-i.patch |    27 +
 ...cm2835-Support-pin-groups-other-than-7-11.patch |    80 +
 ...RM-bcm2835-Set-Serial-number-and-Revision.patch |    58 +
 ...-get-base-address-for-DMA-from-devicetree.patch |    65 +
 ...-add-24bit-support-update-bclk_ratio-to-m.patch |    79 +
 ...s-setup-clock-only-if-CPU-is-clock-master.patch |    54 +
 ...835-i2s-Eliminate-debugfs-directory-error.patch |    36 +
 .../0018-bcm2835-i2s-Register-PCM-device.patch     |    63 +
 ...i2s-Enable-MMAP-support-via-a-DT-property.patch |    44 +
 ...0-dmaengine-bcm2835-Add-slave-dma-support.patch |   320 +
 ...ine-bcm2835-set-residue_granularity-field.patch |    29 +
 ...cm2835-Load-driver-early-and-support-lega.patch |    98 +
 ...-dma-Fix-dreq-not-set-for-slave-transfers.patch |    21 +
 ...-Limit-cyclic-transfers-on-lite-channels-.patch |    37 +
 .../0025-bcm2835-Add-support-for-uart1.patch       |    57 +
 ...irmware-bcm2835-Add-missing-property-tags.patch |    62 +
 .../0027-Main-bcm2708-bcm2709-linux-port.patch     |  2418 +
 ...-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch |   138 +
 .../patches-4.4/0029-Add-dwc_otg-driver.patch      | 60780 +++++++++++++++++++
 .../0030-bcm2708-framebuffer-driver.patch          |  3455 ++
 .../0031-dmaengine-Add-support-for-BCM2708.patch   |   612 +
 ...-parameter-to-mmc-multi_io_quirk-callback.patch |    75 +
 .../0033-MMC-added-alternative-MMC-driver.patch    |  1691 +
 ...835-sdhost-driver-and-an-overlay-to-enabl.patch |  2022 +
 ...ma-Add-vc_cma-driver-to-enable-use-of-CMA.patch |  1326 +
 .../0036-bcm2708-alsa-sound-driver.patch           |  2678 +
 .../patches-4.4/0037-bcm2708-vchiq-driver.patch    | 13200 ++++
 .../0038-vc_mem-Add-vc_mem-driver.patch            |   991 +
 ...deoCore-shared-memory-service-for-BCM2835.patch |  4393 ++
 ...omem-device-for-rootless-user-GPIO-access.patch |   306 +
 .../brcm2708/patches-4.4/0041-Add-SMI-driver.patch |  1930 +
 .../patches-4.4/0042-Add-SMI-NAND-driver.patch     |   358 +
 ...3-lirc-added-support-for-RaspberryPi-GPIO.patch |   841 +
 .../patches-4.4/0044-Add-cpufreq-driver.patch      |   257 +
 ...-thermal-driver-for-reporting-core-temper.patch |   193 +
 .../0046-Add-Chris-Boot-s-i2c-driver.patch         |   635 +
 .../0047-char-broadcom-Add-vcio-module.patch       |   221 +
 ...048-firmware-bcm2835-Support-ARCH_BCM270x.patch |   106 +
 .../0049-bcm2835-add-v4l2-camera-device.patch      |  7338 +++
 ...-mkknlimg-and-knlinfo-scripts-from-tools-.patch |   461 +
 ...port-for-the-CONFIG_CMDLINE_EXTEND-option.patch |    58 +
 ...0052-BCM2708-Add-core-Device-Tree-support.patch |  4564 ++
 ...3-bcm2835-Match-with-BCM2708-Device-Trees.patch |   515 +
 .../0054-fbdev-add-FBIOCOPYAREA-ioctl.patch        |    91 +
 ...up-console-framebuffer-imageblit-function.patch |   209 +
 ...9-Allow-mac-address-to-be-set-in-smsc95xx.patch |    91 +
 ...e-realtime-clock-1-wire-chip-DS1307-and-1.patch |   242 +
 ...061-Added-Device-IDs-for-August-DVB-T-205.patch |    22 +
 ...le-CONFIG_MEMCG-but-leave-it-disabled-due.patch |    49 +
 .../0063-ASoC-Add-support-for-PCM5102A-codec.patch |   128 +
 .../0064-ASoC-Add-support-for-HifiBerry-DAC.patch  |   165 +
 .../0065-ASoC-Add-support-for-Rpi-DAC.patch        |   275 +
 ...-Implement-MCLK-configuration-options-add.patch |    40 +
 ...d-support-for-HiFiBerry-Digi.-Driver-is-b.patch |   282 +
 ...-Set-idle_bias_off-to-false-Idle-bias-has.patch |    22 +
 ...audIO-Sound-Card-support-for-Raspberry-Pi.patch |   178 +
 ...ce-default-mouse-polling-interval-to-60Hz.patch |    36 +
 .../0071-Added-support-for-HiFiBerry-DAC.patch     |   190 +
 ...r-for-HiFiBerry-Amp-amplifier-add-on-boar.patch |   816 +
 ...ate-ds1307-driver-for-device-tree-support.patch |    27 +
 ...Add-pwr_led-and-the-required-input-trigge.patch |   170 +
 ...d-device-tree-compatible-string-and-an-ov.patch |    29 +
 .../0076-Add-driver-for-rpi-proto.patch            |   210 +
 .../0077-config-Add-default-configs.patch          |  2537 +
 .../0078-bcm2835-bcm2835_defconfig.patch           |  1426 +
 ...Add-touchscreen-driver-for-pi-LCD-display.patch |   290 +
 ...opy_to_user-and-__copy_from_user-performa.patch |  1510 +
 ...poweroff-Allow-it-to-work-on-Raspberry-Pi.patch |    35 +
 ...spidev-compatible-string-to-silence-warni.patch |    21 +
 .../0083-scripts-dtc-Add-overlay-support.patch     |  4389 ++
 ...fd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch |   838 +
 .../patches-4.4/0085-RaspiDAC3-support.patch       |   243 +
 ...86-tpa6130a2-Add-headphone-switch-control.patch |    91 +
 .../0087-irq-bcm2835-Fix-building-with-2708.patch  |    28 +
 ..._display-add-backlight-driver-and-overlay.patch |   250 +
 ...89-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch |    85 +
 ...ti-platform-support-for-mkknlimg-and-knli.patch |   247 +
 ...-suport-for-3D-rendering-using-the-V3D-en.patch |  5558 ++
 .../0092-drm-vc4-Force-HDMI-to-connected.patch     |    23 +
 .../0093-drm-vc4-bo-cache-locking-fixes.patch      |   147 +
 .../0094-drm-vc4-bo-cache-locking-cleanup.patch    |    92 +
 ...vc4-Use-job_lock-to-protect-seqno_cb_list.patch |    54 +
 ...c4-Drop-struct_mutex-around-CL-validation.patch |    63 +
 ...c4-Drop-struct_mutex-around-CL-validation.patch |    74 +
 ...dd-support-for-more-display-plane-formats.patch |    35 +
 ...m-vc4-No-need-to-stop-the-stopped-threads.patch |    26 +
 ...ove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch |    33 +
 ...rm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch |    33 +
 ...ble-VC4-modules-and-increase-CMA-size-wit.patch |   153 +
 .../brcm2708/patches-4.4/0103-squash-fixups.patch  |    43 +
 ...missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch |    20 +
 ...-Also-build-the-driver-for-downstream-ker.patch |    22 +
 ...dts-Added-overlay-for-gpio_ir_recv-driver.patch |   104 +
 ...pio-module-and-add-a-device-tree-overlay-.patch |   100 +
 .../0108-New-overlay-for-PiScreen2r.patch          |   148 +
 ...verlay-for-Adafruit-PiTFT-2.8-capacitive-.patch |   145 +
 ...110-Add-support-for-the-HiFiBerry-DAC-Pro.patch |   539 +
 .../0111-BCM270X_DT-Add-at86rf233-overlay.patch    |   130 +
 .../0112-mm-Remove-the-PFN-busy-warning.patch      |    25 +
 ...optional-field-in-the-driver-struct-for-G.patch |    40 +
 ...-an-interface-for-capturing-the-GPU-state.patch |   333 +
 ...ate-a-bunch-of-code-to-match-upstream-sub.patch |  1894 +
 ...-driver-s-gem_object_free-function-from-C.patch |    59 +
 ...17-drm-vc4-Add-support-for-MSAA-rendering.patch |   518 +
 ...ew-more-non-functional-changes-to-sync-to.patch |   345 +
 ...-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch |    22 +
 ...chronize-validation-code-for-v2-submissio.patch |   612 +
 ...use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch |    37 +
 ...k-timeout-fix-modprobe-baudrate-parameter.patch |   108 +
 ...-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch |   110 +
 ...Add-the-sdtweak-overlay-for-tuning-sdhost.patch |    74 +
 ...-Don-t-override-bus-width-capabilities-fr.patch |    24 +
 ...0126-SDIO-overlay-add-bus_width-parameter.patch |    42 +
 ...-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch |    23 +
 127 files changed, 141130 insertions(+), 11 deletions(-)
 create mode 100644 target/linux/brcm2708/bcm2708/config-4.4
 create mode 100644 target/linux/brcm2708/bcm2709/config-4.4
 create mode 100644 target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0030-bcm2708-framebuffer-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0031-dmaengine-Add-support-for-BCM2708.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0032-Add-blk_pos-parameter-to-mmc-multi_io_quirk-callback.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0033-MMC-added-alternative-MMC-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0034-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0035-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0036-bcm2708-alsa-sound-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0037-bcm2708-vchiq-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0038-vc_mem-Add-vc_mem-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0039-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0040-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0041-Add-SMI-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0042-Add-SMI-NAND-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0043-lirc-added-support-for-RaspberryPi-GPIO.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0044-Add-cpufreq-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0045-Added-hwmon-thermal-driver-for-reporting-core-temper.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0046-Add-Chris-Boot-s-i2c-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0047-char-broadcom-Add-vcio-module.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0048-firmware-bcm2835-Support-ARCH_BCM270x.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0049-bcm2835-add-v4l2-camera-device.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0050-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0051-fdt-Add-support-for-the-CONFIG_CMDLINE_EXTEND-option.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0052-BCM2708-Add-core-Device-Tree-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0053-bcm2835-Match-with-BCM2708-Device-Trees.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0054-fbdev-add-FBIOCOPYAREA-ioctl.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0058-Speed-up-console-framebuffer-imageblit-function.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0059-Allow-mac-address-to-be-set-in-smsc95xx.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0060-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0061-Added-Device-IDs-for-August-DVB-T-205.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0062-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0063-ASoC-Add-support-for-PCM5102A-codec.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0064-ASoC-Add-support-for-HifiBerry-DAC.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0065-ASoC-Add-support-for-Rpi-DAC.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0066-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0067-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0068-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0069-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0070-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0071-Added-support-for-HiFiBerry-DAC.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0073-Update-ds1307-driver-for-device-tree-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0074-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0075-enc28j60-Add-device-tree-compatible-string-and-an-ov.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0076-Add-driver-for-rpi-proto.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0077-config-Add-default-configs.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0078-bcm2835-bcm2835_defconfig.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0079-rpi-ft5406-Add-touchscreen-driver-for-pi-LCD-display.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0080-Improve-__copy_to_user-and-__copy_from_user-performa.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0081-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0082-spidev-Add-spidev-compatible-string-to-silence-warni.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0083-scripts-dtc-Add-overlay-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0084-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0085-RaspiDAC3-support.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0086-tpa6130a2-Add-headphone-switch-control.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0087-irq-bcm2835-Fix-building-with-2708.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0088-rpi_display-add-backlight-driver-and-overlay.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0089-bcm2835-dma-Fix-up-convert-to-DMA-pool.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0090-scripts-Multi-platform-support-for-mkknlimg-and-knli.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0091-drm-vc4-Add-suport-for-3D-rendering-using-the-V3D-en.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0092-drm-vc4-Force-HDMI-to-connected.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0093-drm-vc4-bo-cache-locking-fixes.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0094-drm-vc4-bo-cache-locking-cleanup.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0095-drm-vc4-Use-job_lock-to-protect-seqno_cb_list.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0096-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0097-drm-vc4-Drop-struct_mutex-around-CL-validation.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0098-drm-vc4-Add-support-for-more-display-plane-formats.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0099-drm-vc4-No-need-to-stop-the-stopped-threads.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0100-drm-vc4-Remove-extra-barrier-s-aroudn-CTnCA-CTnEA-se.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0101-drm-vc4-Fix-a-typo-in-a-V3D-debug-register.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0102-drm-vc4-Enable-VC4-modules-and-increase-CMA-size-wit.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0103-squash-fixups.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0104-squash-add-missing-vc4-kms-v3d-overlay.dtb-to-makefi.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0105-clk-bcm2835-Also-build-the-driver-for-downstream-ker.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0106-dts-Added-overlay-for-gpio_ir_recv-driver.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0107-Build-i2c_gpio-module-and-add-a-device-tree-overlay-.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0108-New-overlay-for-PiScreen2r.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0109-dts-Added-overlay-for-Adafruit-PiTFT-2.8-capacitive-.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0110-Add-support-for-the-HiFiBerry-DAC-Pro.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0111-BCM270X_DT-Add-at86rf233-overlay.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0112-mm-Remove-the-PFN-busy-warning.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0113-drm-Put-an-optional-field-in-the-driver-struct-for-G.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0114-drm-vc4-Add-an-interface-for-capturing-the-GPU-state.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0115-drm-vc4-Update-a-bunch-of-code-to-match-upstream-sub.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0116-drm-Use-the-driver-s-gem_object_free-function-from-C.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0117-drm-vc4-Add-support-for-MSAA-rendering.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0118-drm-vc4-A-few-more-non-functional-changes-to-sync-to.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0119-drm-vc4-Use-hpd-gpios-for-HDMI-GPIO-like-what-landed.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0120-drm-vc4-Synchronize-validation-code-for-v2-submissio.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0121-MMC-Do-not-use-mmc_debug-if-CONFIG_MMC_BCM2835-is-no.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0122-Extend-clock-timeout-fix-modprobe-baudrate-parameter.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0123-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0124-BCM270X_DT-Add-the-sdtweak-overlay-for-tuning-sdhost.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0125-bcm2835-mmc-Don-t-override-bus-width-capabilities-fr.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0126-SDIO-overlay-add-bus_width-parameter.patch
 create mode 100644 target/linux/brcm2708/patches-4.4/0127-fixup-bcm270x_dt-Add-dwc2-and-dwc-otg-overlays.patch

diff --git a/target/linux/brcm2708/bcm2708/config-4.4 b/target/linux/brcm2708/bcm2708/config-4.4
new file mode 100644
index 0000000..22b8995
--- /dev/null
+++ b/target/linux/brcm2708/bcm2708/config-4.4
@@ -0,0 +1,355 @@
+# CONFIG_AIO is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_BCM2708=y
+# CONFIG_ARCH_BCM2709 is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_ERRATA_411920=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_BCM2708_NOL2CACHE is not set
+CONFIG_BCM2708_VCHIQ=y
+CONFIG_BCM2708_VCMEM=y
+# CONFIG_BCM2835_DEVGPIOMEM is not set
+CONFIG_BCM2835_MBOX=y
+# CONFIG_BCM2835_SMI is not set
+CONFIG_BCM2835_WDT=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM_VC_CMA=y
+CONFIG_BCM_VC_SM=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_SD=y
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BUILD_BIN2C=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMA=y
+CONFIG_CMA_ALIGNMENT=8
+CONFIG_CMA_AREAS=7
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+CONFIG_CMA_SIZE_MBYTES=16
+# CONFIG_CMA_SIZE_SEL_MAX is not set
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+# CONFIG_CMA_SIZE_SEL_MIN is not set
+# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_COMMON_CLK=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_V6=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_V6=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEVTMPFS=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMA_BCM2708 is not set
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_CMA=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_RPISENSE is not set
+CONFIG_FIQ=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HW_CONSOLE=y
+CONFIG_HZ_FIXED=0
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LIBFDT=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_MACH_BCM2708=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAILBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BCM2835=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD is not set
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_MACH_IO_H=y
+CONFIG_NEED_MACH_MEMORY_H=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_OABI_COMPAT=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYS_OFFSET=0
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_BCM2835=y
+# CONFIG_PL330_DMA is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RATIONAL=y
+CONFIG_RAW_DRIVER=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SQUASHFS is not set
+CONFIG_SRCU=y
+# CONFIG_STAGING is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_SUNXI_SRAM is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWIOTLB=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TEXTSEARCH is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_BCM2835=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_OF=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UID16 is not set
+CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_DWCOTG=y
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_UAS=y
+CONFIG_USB_USBNET=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/brcm2708/bcm2709/config-4.4 b/target/linux/brcm2708/bcm2709/config-4.4
new file mode 100644
index 0000000..99603a0
--- /dev/null
+++ b/target/linux/brcm2708/bcm2709/config-4.4
@@ -0,0 +1,387 @@
+# CONFIG_AIO is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_APM_EMULATION is not set
+# CONFIG_ARCH_BCM2708 is not set
+CONFIG_ARCH_BCM2709=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BCM2708_NOL2CACHE=y
+CONFIG_BCM2708_VCHIQ=y
+CONFIG_BCM2708_VCMEM=y
+# CONFIG_BCM2835_DEVGPIOMEM is not set
+CONFIG_BCM2835_MBOX=y
+# CONFIG_BCM2835_SMI is not set
+CONFIG_BCM2835_WDT=y
+CONFIG_BCM_VCIO=y
+CONFIG_BCM_VC_CMA=y
+CONFIG_BCM_VC_SM=y
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_SD=y
+CONFIG_BRCM_CHAR_DRIVERS=y
+CONFIG_BUILD_BIN2C=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMA=y
+CONFIG_CMA_ALIGNMENT=8
+CONFIG_CMA_AREAS=7
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+CONFIG_CMA_SIZE_MBYTES=16
+# CONFIG_CMA_SIZE_SEL_MAX is not set
+CONFIG_CMA_SIZE_SEL_MBYTES=y
+# CONFIG_CMA_SIZE_SEL_MIN is not set
+# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_COMMON_CLK=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DEVTMPFS=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMA_BCM2708 is not set
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_CMA=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_RPISENSE is not set
+CONFIG_FIQ=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x16=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_SUPPORT=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_HW_CONSOLE=y
+CONFIG_HZ_FIXED=0
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_INPUT=y
+CONFIG_LIBFDT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MACH_BCM2709=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAILBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BCM2835=y
+CONFIG_MMC_BCM2835_DMA=y
+CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
+CONFIG_MMC_BCM2835_SDHOST=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD is not set
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_MACH_IO_H=y
+CONFIG_NEED_MACH_MEMORY_H=y
+CONFIG_NEON=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NLS=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_OABI_COMPAT=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGE_OFFSET=0x80000000
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYS_OFFSET=0
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_BCM2835=y
+# CONFIG_PL330_DMA is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_RATIONAL=y
+CONFIG_RAW_DRIVER=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_SQUASHFS is not set
+CONFIG_SRCU=y
+# CONFIG_STAGING is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_SUNXI_SRAM is not set
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_TEXTSEARCH is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_BCM2835=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_OF=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TREE_RCU=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_UID16 is not set
+CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_DWCOTG=y
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_NET_DRIVERS=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_UAS=y
+CONFIG_USB_USBNET=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VMSPLIT_2G=y
+# CONFIG_VMSPLIT_3G is not set
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/brcm2708/modules.mk b/target/linux/brcm2708/modules.mk
index 3bc592c..4a00152 100644
--- a/target/linux/brcm2708/modules.mk
+++ b/target/linux/brcm2708/modules.mk
@@ -36,7 +36,7 @@ define KernelPackage/sound-soc-bcm2708-i2s
   FILES:= \
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-bcm2708-i2s.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-bcm2708-i2s)
-  DEPENDS:=@TARGET_brcm2708 +kmod-regmap +kmod-sound-soc-core
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_1 +kmod-regmap +kmod-sound-soc-core
   $(call AddDepends/sound)
 endef
 
@@ -46,6 +46,25 @@ endef
 
 $(eval $(call KernelPackage,sound-soc-bcm2708-i2s))
 
+define KernelPackage/sound-soc-bcm2835-i2s
+  TITLE:=SoC Audio support for the Broadcom 2835 I2S module
+  KCONFIG:= \
+	CONFIG_SND_BCM2835_SOC_I2S \
+	CONFIG_SND_SOC_DMAENGINE_PCM=y \
+	CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+  FILES:= \
+	$(LINUX_DIR)/sound/soc/bcm/snd-soc-bcm2835-i2s.ko
+  AUTOLOAD:=$(call AutoLoad,68,snd-soc-bcm2835-i2s)
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_4 +kmod-regmap +kmod-sound-soc-core
+  $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-bcm2835-i2s/description
+  This package contains support for codecs attached to the Broadcom 2835 I2S interface
+endef
+
+$(eval $(call KernelPackage,sound-soc-bcm2835-i2s))
+
 define KernelPackage/sound-soc-hifiberry-dac
   TITLE:=Support for HifiBerry DAC
   KCONFIG:= \
@@ -55,7 +74,10 @@ define KernelPackage/sound-soc-hifiberry-dac
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dac.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm5102a.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm5102a snd-soc-hifiberry-dac)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -75,7 +97,10 @@ define KernelPackage/sound-soc-hifiberry-dacplus
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dacplus.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko
   AUTOLOAD:=$(call AutoLoad,68,clk-hifiberry-dacpro snd-soc-pcm512x snd-soc-hifiberry-dacplus)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -94,7 +119,10 @@ define KernelPackage/sound-soc-hifiberry-digi
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-digi.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8804 snd-soc-hifiberry-digi)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -113,7 +141,10 @@ define KernelPackage/sound-soc-hifiberry-amp
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-amp.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-tas5713.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-tas5713 snd-soc-hifiberry-amp)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -132,7 +163,10 @@ define KernelPackage/sound-soc-rpi-dac
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-dac.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm1794a.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm1794a snd-soc-rpi-dac)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -151,7 +185,10 @@ define KernelPackage/sound-soc-rpi-proto
 	$(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-proto.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8731.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8731 snd-soc-rpi-proto)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -172,7 +209,10 @@ define KernelPackage/sound-soc-iqaudio-dac
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x-i2c.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c snd-soc-iqaudio-dac)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -195,7 +235,10 @@ define KernelPackage/sound-soc-raspidac3
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x-i2c.ko \
 	$(LINUX_DIR)/sound/soc/codecs/snd-soc-tpa6130a2.ko
   AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c snd-soc-tpa6130a2 snd-soc-raspidac3)
-  DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
+  DEPENDS:= \
+	LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
+	LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
+	+kmod-i2c-bcm2708
   $(call AddDepends/sound)
 endef
 
@@ -212,7 +255,7 @@ define KernelPackage/random-bcm2708
   KCONFIG:=CONFIG_HW_RANDOM_BCM2708
   FILES:=$(LINUX_DIR)/drivers/char/hw_random/bcm2708-rng.ko
   AUTOLOAD:=$(call AutoLoad,11,bcm2708-rng)
-  DEPENDS:=@TARGET_brcm2708 +kmod-random-core
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_1 +kmod-random-core
 endef
 
 define KernelPackage/random-bcm2708/description
@@ -281,7 +324,7 @@ define KernelPackage/spi-bcm2708
     CONFIG_SPI_MASTER=y
   FILES:=$(LINUX_DIR)/drivers/spi/spi-bcm2708.ko
   AUTOLOAD:=$(call AutoLoad,89,spi-bcm2708)
-  DEPENDS:=@TARGET_brcm2708
+  DEPENDS:=@TARGET_brcm2708 @LINUX_4_1
 endef
 
 define KernelPackage/spi-bcm2708/description
diff --git a/target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch b/target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch
new file mode 100644
index 0000000..48cb813
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0001-smsx95xx-fix-crimes-against-truesize.patch
@@ -0,0 +1,33 @@
+From 8c2c0f30ef9ee0eccd3e56c6aeb110097569d5aa Mon Sep 17 00:00:00 2001
+From: Steve Glendinning <steve.glendinning at smsc.com>
+Date: Thu, 19 Feb 2015 18:47:12 +0000
+Subject: [PATCH 001/127] smsx95xx: fix crimes against truesize
+
+smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings.
+
+This patch stops smsc95xx from changing truesize.
+
+Signed-off-by: Steve Glendinning <steve.glendinning at smsc.com>
+---
+ drivers/net/usb/smsc95xx.c | 2 --
+ 1 file changed, 2 deletions(-)
+ mode change 100644 => 100755 drivers/net/usb/smsc95xx.c
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -1785,7 +1785,6 @@ static int smsc95xx_rx_fixup(struct usbn
+ 				if (dev->net->features & NETIF_F_RXCSUM)
+ 					smsc95xx_rx_csum_offload(skb);
+ 				skb_trim(skb, skb->len - 4); /* remove fcs */
+-				skb->truesize = size + sizeof(struct sk_buff);
+ 
+ 				return 1;
+ 			}
+@@ -1803,7 +1802,6 @@ static int smsc95xx_rx_fixup(struct usbn
+ 			if (dev->net->features & NETIF_F_RXCSUM)
+ 				smsc95xx_rx_csum_offload(ax_skb);
+ 			skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
+-			ax_skb->truesize = size + sizeof(struct sk_buff);
+ 
+ 			usbnet_skb_return(dev, ax_skb);
+ 		}
diff --git a/target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch b/target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch
new file mode 100644
index 0000000..185da76
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0002-smsc95xx-Disable-turbo-mode-by-default.patch
@@ -0,0 +1,20 @@
+From 96f6fc6f990423f39b73013cd91f00a615315a90 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix at gmail.com>
+Date: Fri, 17 Apr 2015 16:58:45 +0100
+Subject: [PATCH 002/127] smsc95xx: Disable turbo mode by default
+
+---
+ drivers/net/usb/smsc95xx.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -70,7 +70,7 @@ struct smsc95xx_priv {
+ 	u8 suspend_flags;
+ };
+ 
+-static bool turbo_mode = true;
++static bool turbo_mode = false;
+ module_param(turbo_mode, bool, 0644);
+ MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+ 
diff --git a/target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch b/target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch
new file mode 100644
index 0000000..4361b54
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0003-vmstat-Workaround-for-issue-where-dirty-page-count-g.patch
@@ -0,0 +1,27 @@
+From 3ea06ff9ba42a29f37b46ced2fb90ff9e06da445 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix at gmail.com>
+Date: Wed, 18 Jun 2014 13:42:01 +0100
+Subject: [PATCH 003/127] vmstat: Workaround for issue where dirty page count
+ goes negative
+
+See:
+https://github.com/raspberrypi/linux/issues/617
+http://www.spinics.net/lists/linux-mm/msg72236.html
+---
+ include/linux/vmstat.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/include/linux/vmstat.h
++++ b/include/linux/vmstat.h
+@@ -219,7 +219,11 @@ static inline void __inc_zone_state(stru
+ static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
+ {
+ 	atomic_long_dec(&zone->vm_stat[item]);
++	if (item == NR_FILE_DIRTY && unlikely(atomic_long_read(&zone->vm_stat[item]) < 0))
++		atomic_long_set(&zone->vm_stat[item], 0);
+ 	atomic_long_dec(&vm_stat[item]);
++	if (item == NR_FILE_DIRTY && unlikely(atomic_long_read(&vm_stat[item]) < 0))
++		atomic_long_set(&vm_stat[item], 0);
+ }
+ 
+ static inline void __inc_zone_page_state(struct page *page,
diff --git a/target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch b/target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch
new file mode 100644
index 0000000..1b4a086
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0004-BCM2835_DT-Fix-I2S-register-map.patch
@@ -0,0 +1,50 @@
+From 6c72a609c205138b739a1484aa1a4ce6dd395c43 Mon Sep 17 00:00:00 2001
+From: Robert Tiemann <rtie at gmx.de>
+Date: Mon, 20 Jul 2015 11:01:25 +0200
+Subject: [PATCH 004/127] BCM2835_DT: Fix I2S register map
+
+---
+ Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt   | 4 ++--
+ Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt | 4 ++--
+ arch/arm/boot/dts/bcm2835.dtsi                               | 4 ++--
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt
++++ b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt
+@@ -48,8 +48,8 @@ Example:
+ 
+ bcm2835_i2s: i2s at 7e203000 {
+ 	compatible = "brcm,bcm2835-i2s";
+-	reg = <	0x7e203000 0x20>,
+-	      < 0x7e101098 0x02>;
++	reg = <	0x7e203000 0x24>,
++	      < 0x7e101098 0x08>;
+ 
+ 	dmas = <&dma 2>,
+ 	       <&dma 3>;
+--- a/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt
++++ b/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt
+@@ -16,8 +16,8 @@ Example:
+ 
+ bcm2835_i2s: i2s at 7e203000 {
+ 	compatible = "brcm,bcm2835-i2s";
+-	reg = <0x7e203000 0x20>,
+-	      <0x7e101098 0x02>;
++	reg = <0x7e203000 0x24>,
++	      <0x7e101098 0x08>;
+ 
+ 	dmas = <&dma 2>,
+ 	       <&dma 3>;
+--- a/arch/arm/boot/dts/bcm2835.dtsi
++++ b/arch/arm/boot/dts/bcm2835.dtsi
+@@ -120,8 +120,8 @@
+ 
+ 		i2s: i2s at 7e203000 {
+ 			compatible = "brcm,bcm2835-i2s";
+-			reg = <0x7e203000 0x20>,
+-			      <0x7e101098 0x02>;
++			reg = <0x7e203000 0x24>,
++			      <0x7e101098 0x08>;
+ 
+ 			dmas = <&dma 2>,
+ 			       <&dma 3>;
diff --git a/target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch b/target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch
new file mode 100644
index 0000000..a0dc4e7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0005-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch
@@ -0,0 +1,31 @@
+From 38395f1ae1258743c3e0081c86bb4b65ad06dd69 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil at raspberrypi.org>
+Date: Fri, 4 Dec 2015 17:41:50 +0000
+Subject: [PATCH 005/127] irq-bcm2836: Prevent spurious interrupts, and trap
+ them early
+
+The old arch-specific IRQ macros included a dsb to ensure the
+write to clear the mailbox interrupt completed before returning
+from the interrupt. The BCM2836 irqchip driver needs the same
+precaution to avoid spurious interrupts.
+
+Spurious interrupts are still possible for other reasons,
+though, so trap them early.
+---
+ drivers/irqchip/irq-bcm2836.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/irqchip/irq-bcm2836.c
++++ b/drivers/irqchip/irq-bcm2836.c
+@@ -170,9 +170,10 @@ __exception_irq_entry bcm2836_arm_irqchi
+ 		u32 ipi = ffs(mbox_val) - 1;
+ 
+ 		writel(1 << ipi, mailbox0);
++		dsb();
+ 		handle_IPI(ipi, regs);
+ #endif
+-	} else {
++	} else if (stat) {
+ 		u32 hwirq = ffs(stat) - 1;
+ 
+ 		handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
diff --git a/target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch b/target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch
new file mode 100644
index 0000000..28ba48b
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0006-irqchip-bcm2835-Add-FIQ-support.patch
@@ -0,0 +1,127 @@
+From 44b5e890373665231d9a5876966ef3a670b9efd7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Fri, 12 Jun 2015 19:01:05 +0200
+Subject: [PATCH 006/127] irqchip: bcm2835: Add FIQ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a duplicate irq range with an offset on the hwirq's so the
+driver can detect that enable_fiq() is used.
+Tested with downstream dwc_otg USB controller driver.
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+Reviewed-by: Eric Anholt <eric at anholt.net>
+Acked-by: Stephen Warren <swarren at wwwdotorg.org>
+---
+ arch/arm/mach-bcm/Kconfig     |  1 +
+ drivers/irqchip/irq-bcm2835.c | 51 ++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 47 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -128,6 +128,7 @@ config ARCH_BCM2835
+ 	select ARM_ERRATA_411920
+ 	select ARM_TIMER_SP804
+ 	select CLKSRC_OF
++	select FIQ
+ 	select PINCTRL
+ 	select PINCTRL_BCM2835
+ 	help
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -55,7 +55,7 @@
+ #include <asm/mach/irq.h>
+ 
+ /* Put the bank and irq (32 bits) into the hwirq */
+-#define MAKE_HWIRQ(b, n)	((b << 5) | (n))
++#define MAKE_HWIRQ(b, n)	(((b) << 5) | (n))
+ #define HWIRQ_BANK(i)		(i >> 5)
+ #define HWIRQ_BIT(i)		BIT(i & 0x1f)
+ 
+@@ -71,9 +71,13 @@
+ 					| SHORTCUT1_MASK | SHORTCUT2_MASK)
+ 
+ #define REG_FIQ_CONTROL		0x0c
++#define REG_FIQ_ENABLE		0x80
++#define REG_FIQ_DISABLE		0
+ 
+ #define NR_BANKS		3
+ #define IRQS_PER_BANK		32
++#define NUMBER_IRQS		MAKE_HWIRQ(NR_BANKS, 0)
++#define FIQ_START		(NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
+ 
+ static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
+ static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
+@@ -98,14 +102,38 @@ static void __exception_irq_entry bcm283
+ 	struct pt_regs *regs);
+ static void bcm2836_chained_handle_irq(struct irq_desc *desc);
+ 
++static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
++{
++	hwirq -= NUMBER_IRQS;
++	/*
++	 * The hwirq numbering used in this driver is:
++	 *   BASE (0-7) GPU1 (32-63) GPU2 (64-95).
++	 * This differ from the one used in the FIQ register:
++	 *   GPU1 (0-31) GPU2 (32-63) BASE (64-71)
++	 */
++	if (hwirq >= 32)
++		return hwirq - 32;
++
++	return hwirq + 64;
++}
++
+ static void armctrl_mask_irq(struct irq_data *d)
+ {
+-	writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
++	if (d->hwirq >= NUMBER_IRQS)
++		writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
++	else
++		writel_relaxed(HWIRQ_BIT(d->hwirq),
++			       intc.disable[HWIRQ_BANK(d->hwirq)]);
+ }
+ 
+ static void armctrl_unmask_irq(struct irq_data *d)
+ {
+-	writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
++	if (d->hwirq >= NUMBER_IRQS)
++		writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
++			       intc.base + REG_FIQ_CONTROL);
++	else
++		writel_relaxed(HWIRQ_BIT(d->hwirq),
++			       intc.enable[HWIRQ_BANK(d->hwirq)]);
+ }
+ 
+ static struct irq_chip armctrl_chip = {
+@@ -151,8 +179,9 @@ static int __init armctrl_of_init(struct
+ 		panic("%s: unable to map IC registers\n",
+ 			node->full_name);
+ 
+-	intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
+-			&armctrl_ops, NULL);
++	intc.base = base;
++	intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
++					    &armctrl_ops, NULL);
+ 	if (!intc.domain)
+ 		panic("%s: unable to create IRQ domain\n", node->full_name);
+ 
+@@ -182,6 +211,18 @@ static int __init armctrl_of_init(struct
+ 		set_handle_irq(bcm2835_handle_irq);
+ 	}
+ 
++	/* Make a duplicate irq range which is used to enable FIQ */
++	for (b = 0; b < NR_BANKS; b++) {
++		for (i = 0; i < bank_irqs[b]; i++) {
++			irq = irq_create_mapping(intc.domain,
++					MAKE_HWIRQ(b, i) + NUMBER_IRQS);
++			BUG_ON(irq <= 0);
++			irq_set_chip(irq, &armctrl_chip);
++			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		}
++	}
++	init_FIQ(FIQ_START);
++
+ 	return 0;
+ }
+ 
diff --git a/target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch b/target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch
new file mode 100644
index 0000000..9fa768c
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0007-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch
@@ -0,0 +1,96 @@
+From e3e8c56abfe6a036025f75908b63ae69d8eaed11 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Fri, 23 Oct 2015 16:26:55 +0200
+Subject: [PATCH 007/127] irqchip: irq-bcm2835: Add 2836 FIQ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ drivers/irqchip/irq-bcm2835.c | 42 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 40 insertions(+), 2 deletions(-)
+
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -50,6 +50,8 @@
+ #include <linux/of_irq.h>
+ #include <linux/irqchip.h>
+ #include <linux/irqdomain.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
+ 
+ #include <asm/exception.h>
+ #include <asm/mach/irq.h>
+@@ -70,6 +72,9 @@
+ #define BANK0_VALID_MASK	(BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
+ 					| SHORTCUT1_MASK | SHORTCUT2_MASK)
+ 
++#undef ARM_LOCAL_GPU_INT_ROUTING
++#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
++
+ #define REG_FIQ_CONTROL		0x0c
+ #define REG_FIQ_ENABLE		0x80
+ #define REG_FIQ_DISABLE		0
+@@ -95,6 +100,7 @@ struct armctrl_ic {
+ 	void __iomem *enable[NR_BANKS];
+ 	void __iomem *disable[NR_BANKS];
+ 	struct irq_domain *domain;
++	struct regmap *local_regmap;
+ };
+ 
+ static struct armctrl_ic intc __read_mostly;
+@@ -128,12 +134,35 @@ static void armctrl_mask_irq(struct irq_
+ 
+ static void armctrl_unmask_irq(struct irq_data *d)
+ {
+-	if (d->hwirq >= NUMBER_IRQS)
++	if (d->hwirq >= NUMBER_IRQS) {
++		if (num_online_cpus() > 1) {
++			unsigned int data;
++			int ret;
++
++			if (!intc.local_regmap) {
++				pr_err("FIQ is disabled due to missing regmap\n");
++				return;
++			}
++
++			ret = regmap_read(intc.local_regmap,
++					  ARM_LOCAL_GPU_INT_ROUTING, &data);
++			if (ret) {
++				pr_err("Failed to read int routing %d\n", ret);
++				return;
++			}
++
++			data &= ~0xc;
++			data |= (1 << 2);
++			regmap_write(intc.local_regmap,
++				     ARM_LOCAL_GPU_INT_ROUTING, data);
++		}
++
+ 		writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
+ 			       intc.base + REG_FIQ_CONTROL);
+-	else
++	} else {
+ 		writel_relaxed(HWIRQ_BIT(d->hwirq),
+ 			       intc.enable[HWIRQ_BANK(d->hwirq)]);
++	}
+ }
+ 
+ static struct irq_chip armctrl_chip = {
+@@ -211,6 +240,15 @@ static int __init armctrl_of_init(struct
+ 		set_handle_irq(bcm2835_handle_irq);
+ 	}
+ 
++	if (is_2836) {
++		intc.local_regmap =
++			syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
++		if (IS_ERR(intc.local_regmap)) {
++			pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
++			intc.local_regmap = NULL;
++		}
++	}
++
+ 	/* Make a duplicate irq range which is used to enable FIQ */
+ 	for (b = 0; b < NR_BANKS; b++) {
+ 		for (i = 0; i < bank_irqs[b]; i++) {
diff --git a/target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch b/target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch
new file mode 100644
index 0000000..46bc447
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0008-serial-8250-Don-t-crash-when-nr_uarts-is-0.patch
@@ -0,0 +1,20 @@
+From 4bff078f28e6a2d55d18e06c0a92b0b78b8ea6cb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil at raspberrypi.org>
+Date: Tue, 30 Jun 2015 14:12:42 +0100
+Subject: [PATCH 008/127] serial: 8250: Don't crash when nr_uarts is 0
+
+---
+ drivers/tty/serial/8250/8250_core.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/tty/serial/8250/8250_core.c
++++ b/drivers/tty/serial/8250/8250_core.c
+@@ -509,6 +509,8 @@ static void __init serial8250_isa_init_p
+ 
+ 	if (nr_uarts > UART_NR)
+ 		nr_uarts = UART_NR;
++	if (!nr_uarts)
++		return;
+ 
+ 	for (i = 0; i < nr_uarts; i++) {
+ 		struct uart_8250_port *up = &serial8250_ports[i];
diff --git a/target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch b/target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch
new file mode 100644
index 0000000..96381b6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0009-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch
@@ -0,0 +1,22 @@
+From 91ea61bbf9285586d27442dc3b85ea34805ccf38 Mon Sep 17 00:00:00 2001
+From: notro <notro at tronnes.org>
+Date: Thu, 10 Jul 2014 13:59:47 +0200
+Subject: [PATCH 009/127] pinctrl-bcm2835: Set base to 0 give expected gpio
+ numbering
+
+Signed-off-by: Noralf Tronnes <notro at tronnes.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -373,7 +373,7 @@ static struct gpio_chip bcm2835_gpio_chi
+ 	.get = bcm2835_gpio_get,
+ 	.set = bcm2835_gpio_set,
+ 	.to_irq = bcm2835_gpio_to_irq,
+-	.base = -1,
++	.base = 0,
+ 	.ngpio = BCM2835_NUM_GPIOS,
+ 	.can_sleep = false,
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch b/target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
new file mode 100644
index 0000000..c3a051f
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0010-pinctrl-bcm2835-Fix-interrupt-handling-for-GPIOs-28-.patch
@@ -0,0 +1,146 @@
+From 15367f46e17775c4d736ed1cfc318218362c6a4d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil at raspberrypi.org>
+Date: Tue, 24 Feb 2015 13:40:50 +0000
+Subject: [PATCH 010/127] pinctrl-bcm2835: Fix interrupt handling for GPIOs
+ 28-31 and 46-53
+
+Contrary to the documentation, the BCM2835 GPIO controller actually has
+four interrupt lines - one each for the three IRQ groups and one common. Rather
+confusingly, the GPIO interrupt groups don't correspond directly with the GPIO
+control banks. Instead, GPIOs 0-27 generate IRQ GPIO0, 28-45 GPIO1 and
+46-53 GPIO2.
+
+Awkwardly, the GPIOS for IRQ GPIO1 straddle two 32-entry GPIO banks, so it is
+cleaner to split out a function to process the interrupts for a single GPIO
+bank.
+
+This bug has only just been observed because GPIOs above 27 can only be
+accessed on an old Raspberry Pi with the optional P5 header fitted, where
+the pins are often used for I2S instead.
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 51 ++++++++++++++++++++++++++---------
+ 1 file changed, 39 insertions(+), 12 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -47,6 +47,7 @@
+ #define MODULE_NAME "pinctrl-bcm2835"
+ #define BCM2835_NUM_GPIOS 54
+ #define BCM2835_NUM_BANKS 2
++#define BCM2835_NUM_IRQS  3
+ 
+ #define BCM2835_PIN_BITMAP_SZ \
+ 	DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8)
+@@ -88,13 +89,13 @@ enum bcm2835_pinconf_pull {
+ 
+ struct bcm2835_gpio_irqdata {
+ 	struct bcm2835_pinctrl *pc;
+-	int bank;
++	int irqgroup;
+ };
+ 
+ struct bcm2835_pinctrl {
+ 	struct device *dev;
+ 	void __iomem *base;
+-	int irq[BCM2835_NUM_BANKS];
++	int irq[BCM2835_NUM_IRQS];
+ 
+ 	/* note: locking assumes each bank will have its own unsigned long */
+ 	unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
+@@ -105,7 +106,7 @@ struct bcm2835_pinctrl {
+ 	struct gpio_chip gpio_chip;
+ 	struct pinctrl_gpio_range gpio_range;
+ 
+-	struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_BANKS];
++	struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS];
+ 	spinlock_t irq_lock[BCM2835_NUM_BANKS];
+ };
+ 
+@@ -378,17 +379,16 @@ static struct gpio_chip bcm2835_gpio_chi
+ 	.can_sleep = false,
+ };
+ 
+-static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
++static int bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
++					unsigned int bank, u32 mask)
+ {
+-	struct bcm2835_gpio_irqdata *irqdata = dev_id;
+-	struct bcm2835_pinctrl *pc = irqdata->pc;
+-	int bank = irqdata->bank;
+ 	unsigned long events;
+ 	unsigned offset;
+ 	unsigned gpio;
+ 	unsigned int type;
+ 
+ 	events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
++	events &= mask;
+ 	events &= pc->enabled_irq_map[bank];
+ 	for_each_set_bit(offset, &events, 32) {
+ 		gpio = (32 * bank) + offset;
+@@ -396,7 +396,30 @@ static irqreturn_t bcm2835_gpio_irq_hand
+ 
+ 		generic_handle_irq(irq_linear_revmap(pc->irq_domain, gpio));
+ 	}
+-	return events ? IRQ_HANDLED : IRQ_NONE;
++
++	return (events != 0);
++}
++
++static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
++{
++	struct bcm2835_gpio_irqdata *irqdata = dev_id;
++	struct bcm2835_pinctrl *pc = irqdata->pc;
++	int handled = 0;
++
++	switch (irqdata->irqgroup) {
++	case 0: /* IRQ0 covers GPIOs 0-27 */
++		handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff);
++		break;
++	case 1: /* IRQ1 covers GPIOs 28-45 */
++		handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000) |
++			  bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
++		break;
++	case 2: /* IRQ2 covers GPIOs 46-53 */
++		handled = bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
++		break;
++	}
++
++	return handled ? IRQ_HANDLED : IRQ_NONE;
+ }
+ 
+ static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
+@@ -985,8 +1008,6 @@ static int bcm2835_pinctrl_probe(struct
+ 	for (i = 0; i < BCM2835_NUM_BANKS; i++) {
+ 		unsigned long events;
+ 		unsigned offset;
+-		int len;
+-		char *name;
+ 
+ 		/* clear event detection flags */
+ 		bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0);
+@@ -1001,10 +1022,15 @@ static int bcm2835_pinctrl_probe(struct
+ 		for_each_set_bit(offset, &events, 32)
+ 			bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
+ 
++		spin_lock_init(&pc->irq_lock[i]);
++	}
++
++	for (i = 0; i < BCM2835_NUM_IRQS; i++) {
++		int len;
++		char *name;
+ 		pc->irq[i] = irq_of_parse_and_map(np, i);
+ 		pc->irq_data[i].pc = pc;
+-		pc->irq_data[i].bank = i;
+-		spin_lock_init(&pc->irq_lock[i]);
++		pc->irq_data[i].irqgroup = i;
+ 
+ 		len = strlen(dev_name(pc->dev)) + 16;
+ 		name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
+@@ -1062,6 +1088,7 @@ static struct platform_driver bcm2835_pi
+ 	.remove = bcm2835_pinctrl_remove,
+ 	.driver = {
+ 		.name = MODULE_NAME,
++		.owner = THIS_MODULE,
+ 		.of_match_table = bcm2835_pinctrl_match,
+ 	},
+ };
diff --git a/target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch b/target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch
new file mode 100644
index 0000000..0ef4ba2
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0011-pinctrl-bcm2835-Only-request-the-interrupts-listed-i.patch
@@ -0,0 +1,27 @@
+From 167da31b9a7d3111c83993e4d614bb95bbefdcbb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil at raspberrypi.org>
+Date: Thu, 26 Feb 2015 09:58:22 +0000
+Subject: [PATCH 011/127] pinctrl-bcm2835: Only request the interrupts listed
+ in the DTB
+
+Although the GPIO controller can generate three interrupts (four counting
+the common one), the device tree files currently only specify two. In the
+absence of the third, simply don't register that interrupt (as opposed to
+registering 0), which has the effect of making it impossible to generate
+interrupts for GPIOs 46-53 which, since they share pins with the SD card
+interface, is unlikely to be a problem.
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1029,6 +1029,8 @@ static int bcm2835_pinctrl_probe(struct
+ 		int len;
+ 		char *name;
+ 		pc->irq[i] = irq_of_parse_and_map(np, i);
++		if (pc->irq[i] == 0)
++			break;
+ 		pc->irq_data[i].pc = pc;
+ 		pc->irq_data[i].irqgroup = i;
+ 
diff --git a/target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch b/target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch
new file mode 100644
index 0000000..73e2781
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0012-spi-bcm2835-Support-pin-groups-other-than-7-11.patch
@@ -0,0 +1,80 @@
+From bc9d2c297e886dfcc340414a61de970942ad7319 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil at raspberrypi.org>
+Date: Wed, 24 Jun 2015 14:10:44 +0100
+Subject: [PATCH 012/127] spi-bcm2835: Support pin groups other than 7-11
+
+The spi-bcm2835 driver automatically uses GPIO chip-selects due to
+some unreliability of the native ones. In doing so it chooses the
+same pins as the native chip-selects would use, but the existing
+code always uses pins 7 and 8, wherever the SPI function is mapped.
+
+Search the pinctrl group assigned to the driver for pins that
+correspond to native chip-selects, and use those for GPIO chip-
+selects.
+
+Signed-off-by: Phil Elwell <phil at raspberrypi.org>
+---
+ drivers/spi/spi-bcm2835.c | 45 +++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 37 insertions(+), 8 deletions(-)
+
+--- a/drivers/spi/spi-bcm2835.c
++++ b/drivers/spi/spi-bcm2835.c
+@@ -688,6 +688,8 @@ static int bcm2835_spi_setup(struct spi_
+ {
+ 	int err;
+ 	struct gpio_chip *chip;
++	struct device_node *pins;
++	u32 pingroup_index;
+ 	/*
+ 	 * sanity checking the native-chipselects
+ 	 */
+@@ -704,15 +706,42 @@ static int bcm2835_spi_setup(struct spi_
+ 			"setup: only two native chip-selects are supported\n");
+ 		return -EINVAL;
+ 	}
+-	/* now translate native cs to GPIO */
+ 
+-	/* get the gpio chip for the base */
+-	chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
+-	if (!chip)
+-		return 0;
++	/* now translate native cs to GPIO */
++	/* first look for chip select pins in the devices pin groups */
++	for (pingroup_index = 0;
++	     (pins = of_parse_phandle(spi->master->dev.of_node,
++				     "pinctrl-0",
++				      pingroup_index)) != 0;
++	     pingroup_index++) {
++		u32 pin;
++		u32 pin_index;
++		for (pin_index = 0;
++		     of_property_read_u32_index(pins,
++						"brcm,pins",
++						pin_index,
++						&pin) == 0;
++		     pin_index++) {
++			if (((spi->chip_select == 0) &&
++			     ((pin == 8) || (pin == 36) || (pin == 46))) ||
++			    ((spi->chip_select == 1) &&
++			     ((pin == 7) || (pin == 35)))) {
++				spi->cs_gpio = pin;
++				break;
++			}
++		}
++		of_node_put(pins);
++	}
++	/* if that fails, assume GPIOs 7-11 are used */
++	if (!gpio_is_valid(spi->cs_gpio) ) {
++		/* get the gpio chip for the base */
++		chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
++		if (!chip)
++			return 0;
+ 
+-	/* and calculate the real CS */
+-	spi->cs_gpio = chip->base + 8 - spi->chip_select;
++		/* and calculate the real CS */
++		spi->cs_gpio = chip->base + 8 - spi->chip_select;
++	}
+ 
+ 	/* and set up the "mode" and level */
+ 	dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n",
diff --git a/target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch b/target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch
new file mode 100644
index 0000000..e2b55b6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0013-ARM-bcm2835-Set-Serial-number-and-Revision.patch
@@ -0,0 +1,58 @@
+From e04c4837cde13f4782fc5a274599f580d8a29715 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Wed, 3 Jun 2015 12:26:13 +0200
+Subject: [PATCH 013/127] ARM: bcm2835: Set Serial number and Revision
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The VideoCore bootloader passes in Serial number and
+Revision number through Device Tree. Make these available to
+userspace through /proc/cpuinfo.
+
+Mainline status:
+
+There is a commit in linux-next that standardize passing the serial
+number through Device Tree (string: /serial-number):
+ARM: 8355/1: arch: Show the serial number from devicetree in cpuinfo
+
+There was an attempt to do the same with the revision number, but it
+didn't get in:
+[PATCH v2 1/2] arm: devtree: Set system_rev from DT revision
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -17,12 +17,16 @@
+ #include <linux/of_address.h>
+ #include <linux/of_platform.h>
+ #include <linux/clk/bcm2835.h>
++#include <asm/system_info.h>
+ 
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ 
+ static void __init bcm2835_init(void)
+ {
++	struct device_node *np = of_find_node_by_path("/system");
++	u32 val;
++	u64 val64;
+ 	int ret;
+ 
+ 	bcm2835_init_clocks();
+@@ -33,6 +37,11 @@ static void __init bcm2835_init(void)
+ 		pr_err("of_platform_populate failed: %d\n", ret);
+ 		BUG();
+ 	}
++
++	if (!of_property_read_u32(np, "linux,revision", &val))
++		system_rev = val;
++	if (!of_property_read_u64(np, "linux,serial", &val64))
++		system_serial_low = val64;
+ }
+ 
+ static const char * const bcm2835_compat[] = {
diff --git a/target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch b/target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch
new file mode 100644
index 0000000..0c36bda
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0014-bcm2835-i2s-get-base-address-for-DMA-from-devicetree.patch
@@ -0,0 +1,65 @@
+From c8225021ad8a8e8d2b4560bed644c5552f9f6684 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 16:44:05 +0200
+Subject: [PATCH 014/127] bcm2835-i2s: get base address for DMA from devicetree
+
+Code copied from spi-bcm2835. Get physical address from devicetree
+instead of using hardcoded constant.
+
+Signed-off-by: Matthias Reichl <hias at horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -38,6 +38,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/clk.h>
++#include <linux/of_address.h>
+ 
+ #include <sound/core.h>
+ #include <sound/pcm.h>
+@@ -158,10 +159,6 @@ static const unsigned int bcm2835_clk_fr
+ #define BCM2835_I2S_INT_RXR		BIT(1)
+ #define BCM2835_I2S_INT_TXW		BIT(0)
+ 
+-/* I2S DMA interface */
+-/* FIXME: Needs IOMMU support */
+-#define BCM2835_VCMMU_SHIFT		(0x7E000000 - 0x20000000)
+-
+ /* General device struct */
+ struct bcm2835_i2s_dev {
+ 	struct device				*dev;
+@@ -791,6 +788,15 @@ static int bcm2835_i2s_probe(struct plat
+ 	int ret;
+ 	struct regmap *regmap[2];
+ 	struct resource *mem[2];
++	const __be32 *addr;
++	dma_addr_t dma_reg_base;
++
++	addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
++	if (!addr) {
++		dev_err(&pdev->dev, "could not get DMA-register address\n");
++		return -ENODEV;
++	}
++	dma_reg_base = be32_to_cpup(addr);
+ 
+ 	/* Request both ioareas */
+ 	for (i = 0; i <= 1; i++) {
+@@ -817,12 +823,10 @@ static int bcm2835_i2s_probe(struct plat
+ 
+ 	/* Set the DMA address */
+ 	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+-		(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+-					  + BCM2835_VCMMU_SHIFT;
++		dma_reg_base + BCM2835_I2S_FIFO_A_REG;
+ 
+ 	dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+-		(dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+-					  + BCM2835_VCMMU_SHIFT;
++		dma_reg_base + BCM2835_I2S_FIFO_A_REG;
+ 
+ 	/* Set the bus width */
+ 	dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
diff --git a/target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch b/target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch
new file mode 100644
index 0000000..b627327
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0015-bcm2835-i2s-add-24bit-support-update-bclk_ratio-to-m.patch
@@ -0,0 +1,79 @@
+From 328b2e8b8a38fe62431c2ad5ae22cee31740b10d Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 15:21:16 +0200
+Subject: [PATCH 015/127] bcm2835-i2s: add 24bit support, update bclk_ratio to
+ more correct values
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit 62c05a0b5328d9376d39c9e74da10b8a2465c234 ("ASoC: BCM2708:
+Add 24 bit support")
+
+This adds 24 bit support to the I2S driver of the BCM2708.
+Besides enabling the 24 bit flags, it includes two bug fixes:
+
+MMAP is not supported. Claiming this leads to strange issues
+when the format of driver and file do not match.
+
+The datasheet states that the width extension bit should be set
+for widths greater than 24, but greater or equal would be correct.
+This follows from the definition of the width field.
+
+Signed-off-by: Florian Meier <florian.meier at koalo.de>
+
+RPi commit 3e8c672bc4e92d457aa4654bbb4cfd79a18a2327 ("bcm2708-i2s:
+Update bclk_ratio to more correct values")
+
+Discussion about blck_ratio affecting sound quality:
+https://github.com/raspberrypi/linux/issues/681
+
+Signed-off-by: Matthias Reichl <hias at horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -340,11 +340,15 @@ static int bcm2835_i2s_hw_params(struct
+ 	switch (params_format(params)) {
+ 	case SNDRV_PCM_FORMAT_S16_LE:
+ 		data_length = 16;
+-		bclk_ratio = 40;
++		bclk_ratio = 50;
++		break;
++	case SNDRV_PCM_FORMAT_S24_LE:
++		data_length = 24;
++		bclk_ratio = 50;
+ 		break;
+ 	case SNDRV_PCM_FORMAT_S32_LE:
+ 		data_length = 32;
+-		bclk_ratio = 80;
++		bclk_ratio = 100;
+ 		break;
+ 	default:
+ 		return -EINVAL;
+@@ -420,7 +424,7 @@ static int bcm2835_i2s_hw_params(struct
+ 	/* Setup the frame format */
+ 	format = BCM2835_I2S_CHEN;
+ 
+-	if (data_length > 24)
++	if (data_length >= 24)
+ 		format |= BCM2835_I2S_CHWEX;
+ 
+ 	format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
+@@ -711,6 +715,7 @@ static struct snd_soc_dai_driver bcm2835
+ 		.channels_max = 2,
+ 		.rates =	SNDRV_PCM_RATE_8000_192000,
+ 		.formats =	SNDRV_PCM_FMTBIT_S16_LE
++				| SNDRV_PCM_FMTBIT_S24_LE
+ 				| SNDRV_PCM_FMTBIT_S32_LE
+ 		},
+ 	.capture = {
+@@ -718,6 +723,7 @@ static struct snd_soc_dai_driver bcm2835
+ 		.channels_max = 2,
+ 		.rates =	SNDRV_PCM_RATE_8000_192000,
+ 		.formats =	SNDRV_PCM_FMTBIT_S16_LE
++				| SNDRV_PCM_FMTBIT_S24_LE
+ 				| SNDRV_PCM_FMTBIT_S32_LE
+ 		},
+ 	.ops = &bcm2835_i2s_dai_ops,
diff --git a/target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch b/target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch
new file mode 100644
index 0000000..e096656
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0016-bcm2835-i2s-setup-clock-only-if-CPU-is-clock-master.patch
@@ -0,0 +1,54 @@
+From fce554c6331b34458db54722cb06eb517a32b305 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 15:25:51 +0200
+Subject: [PATCH 016/127] bcm2835-i2s: setup clock only if CPU is clock master
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit c14827ecdaa36607f6110f9ce8df96e698672191 ("bcm2708: Allow
+option card devices to be configured via DT")
+
+Original work by Zoltan Szenczi, committed to RPi tree by
+Phil Elwell.
+
+Signed-off-by: Matthias Reichl <hias at horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -411,15 +411,25 @@ static int bcm2835_i2s_hw_params(struct
+ 		divf = dividend & BCM2835_CLK_DIVF_MASK;
+ 	}
+ 
+-	/* Set clock divider */
+-	regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
+-			| BCM2835_CLK_DIVI(divi)
+-			| BCM2835_CLK_DIVF(divf));
++	/* Clock should only be set up here if CPU is clock master */
++	switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++	case SND_SOC_DAIFMT_CBS_CFS:
++	case SND_SOC_DAIFMT_CBS_CFM:
++		/* Set clock divider */
++		regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG,
++				  BCM2835_CLK_PASSWD
++				| BCM2835_CLK_DIVI(divi)
++				| BCM2835_CLK_DIVF(divf));
+ 
+-	/* Setup clock, but don't start it yet */
+-	regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
+-			| BCM2835_CLK_MASH(mash)
+-			| BCM2835_CLK_SRC(clk_src));
++		/* Setup clock, but don't start it yet */
++		regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
++				  BCM2835_CLK_PASSWD
++				| BCM2835_CLK_MASH(mash)
++				| BCM2835_CLK_SRC(clk_src));
++		break;
++	default:
++		break;
++	}
+ 
+ 	/* Setup the frame format */
+ 	format = BCM2835_I2S_CHEN;
diff --git a/target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch b/target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch
new file mode 100644
index 0000000..1caa347
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0017-bcm2835-i2s-Eliminate-debugfs-directory-error.patch
@@ -0,0 +1,36 @@
+From 45995262bd8d5194e9430d2a826c84ed28c408eb Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 15:49:51 +0200
+Subject: [PATCH 017/127] bcm2835-i2s: Eliminate debugfs directory error
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit fd7d7a3dbe9262d16971ef81c234ed28c6499dd7 ("bcm2708:
+Eliminate i2s debugfs directory error")
+
+Qualify the two regmap ranges uses by bcm2708-i2s ('-i2s' and '-clk')
+to avoid the name clash when registering debugfs entries.
+
+Signed-off-by: Matthias Reichl <hias at horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -782,6 +782,7 @@ static const struct regmap_config bcm283
+ 		.precious_reg = bcm2835_i2s_precious_reg,
+ 		.volatile_reg = bcm2835_i2s_volatile_reg,
+ 		.cache_type = REGCACHE_RBTREE,
++		.name = "i2s",
+ 	},
+ 	{
+ 		.reg_bits = 32,
+@@ -790,6 +791,7 @@ static const struct regmap_config bcm283
+ 		.max_register = BCM2835_CLK_PCMDIV_REG,
+ 		.volatile_reg = bcm2835_clk_volatile_reg,
+ 		.cache_type = REGCACHE_RBTREE,
++		.name = "clk",
+ 	},
+ };
+ 
diff --git a/target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch b/target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch
new file mode 100644
index 0000000..eeb7d61
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0018-bcm2835-i2s-Register-PCM-device.patch
@@ -0,0 +1,63 @@
+From b58d4ef09eca4674d1530f0c8e1ca074b269ebea Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 15:35:20 +0200
+Subject: [PATCH 018/127] bcm2835-i2s: Register PCM device
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit ba46b4935a23aa2caac1855ead52a035d4776680 ("ASoC: Add
+support for BCM2708")
+
+This driver adds support for digital audio (I2S)
+for the BCM2708 SoC that is used by the
+Raspberry Pi. External audio codecs can be
+connected to the Raspberry Pi via P5 header.
+
+It relies on cyclic DMA engine support for BCM2708.
+
+Signed-off-by: Florian Meier <florian.meier at koalo.de>
+
+Signed-off-by: Matthias Reichl <hias at horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -799,6 +799,25 @@ static const struct snd_soc_component_dr
+ 	.name		= "bcm2835-i2s-comp",
+ };
+ 
++static const struct snd_pcm_hardware bcm2835_pcm_hardware = {
++	.info			= SNDRV_PCM_INFO_INTERLEAVED |
++				  SNDRV_PCM_INFO_JOINT_DUPLEX,
++	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
++				  SNDRV_PCM_FMTBIT_S24_LE |
++				  SNDRV_PCM_FMTBIT_S32_LE,
++	.period_bytes_min	= 32,
++	.period_bytes_max	= 64 * PAGE_SIZE,
++	.periods_min		= 2,
++	.periods_max		= 255,
++	.buffer_bytes_max	= 128 * PAGE_SIZE,
++};
++
++static const struct snd_dmaengine_pcm_config bcm2835_dmaengine_pcm_config = {
++	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
++	.pcm_hardware = &bcm2835_pcm_hardware,
++	.prealloc_buffer_size = 256 * PAGE_SIZE,
++};
++
+ static int bcm2835_i2s_probe(struct platform_device *pdev)
+ {
+ 	struct bcm2835_i2s_dev *dev;
+@@ -870,7 +889,9 @@ static int bcm2835_i2s_probe(struct plat
+ 		return ret;
+ 	}
+ 
+-	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
++	ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
++			&bcm2835_dmaengine_pcm_config,
++			SND_DMAENGINE_PCM_FLAG_COMPAT);
+ 	if (ret) {
+ 		dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ 		return ret;
diff --git a/target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch b/target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch
new file mode 100644
index 0000000..c422cc7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0019-bcm2835-i2s-Enable-MMAP-support-via-a-DT-property.patch
@@ -0,0 +1,44 @@
+From 61f155e164c5dbfa5cec9a099e4aa802c2155423 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 15:55:21 +0200
+Subject: [PATCH 019/127] bcm2835-i2s: Enable MMAP support via a DT property
+
+Code ported from bcm2708-i2s driver in Raspberry Pi tree.
+
+RPi commit 7ee829fd77a30127db5d0b3c7d79b8718166e568 ("bcm2708-i2s:
+Enable MMAP support via a DT property and overlay")
+
+The i2s driver used to claim to support MMAP, but that feature was disabled
+when some problems were found. Add the ability to enable this feature
+through Device Tree, using the i2s-mmap overlay.
+
+See: #1004
+
+Signed-off-by: Matthias Reichl <hias at horus.com>
+---
+ sound/soc/bcm/bcm2835-i2s.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/bcm/bcm2835-i2s.c
++++ b/sound/soc/bcm/bcm2835-i2s.c
+@@ -799,7 +799,7 @@ static const struct snd_soc_component_dr
+ 	.name		= "bcm2835-i2s-comp",
+ };
+ 
+-static const struct snd_pcm_hardware bcm2835_pcm_hardware = {
++static struct snd_pcm_hardware bcm2835_pcm_hardware = {
+ 	.info			= SNDRV_PCM_INFO_INTERLEAVED |
+ 				  SNDRV_PCM_INFO_JOINT_DUPLEX,
+ 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+@@ -835,6 +835,11 @@ static int bcm2835_i2s_probe(struct plat
+ 	}
+ 	dma_reg_base = be32_to_cpup(addr);
+ 
++	if (of_property_read_bool(pdev->dev.of_node, "brcm,enable-mmap"))
++		bcm2835_pcm_hardware.info |=
++			SNDRV_PCM_INFO_MMAP |
++			SNDRV_PCM_INFO_MMAP_VALID;
++
+ 	/* Request both ioareas */
+ 	for (i = 0; i <= 1; i++) {
+ 		void __iomem *base;
diff --git a/target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch b/target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch
new file mode 100644
index 0000000..c49e482
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0020-dmaengine-bcm2835-Add-slave-dma-support.patch
@@ -0,0 +1,320 @@
+From 780a1039ccfd293d583742a4f2326997b15f5aff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Thu, 9 Apr 2015 12:34:11 +0200
+Subject: [PATCH 020/127] dmaengine: bcm2835: Add slave dma support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add slave transfer capability to BCM2835 dmaengine driver.
+This patch is pulled from the bcm2708-dmaengine driver in the
+Raspberry Pi repo. The work was done by Gellert Weisz.
+
+Tested using the bcm2835-mmc driver from the same repo.
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ drivers/dma/bcm2835-dma.c | 206 ++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 192 insertions(+), 14 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -1,11 +1,10 @@
+ /*
+  * BCM2835 DMA engine support
+  *
+- * This driver only supports cyclic DMA transfers
+- * as needed for the I2S module.
+- *
+  * Author:      Florian Meier <florian.meier at koalo.de>
+  *              Copyright 2013
++ *              Gellert Weisz <gellert at raspberrypi.org>
++ *              Copyright 2013-2014
+  *
+  * Based on
+  *	OMAP DMAengine support by Russell King
+@@ -95,6 +94,8 @@ struct bcm2835_desc {
+ 	size_t size;
+ };
+ 
++#define BCM2835_DMA_WAIT_CYCLES	0  /* Slow down DMA transfers: 0-31 */
++
+ #define BCM2835_DMA_CS		0x00
+ #define BCM2835_DMA_ADDR	0x04
+ #define BCM2835_DMA_SOURCE_AD	0x0c
+@@ -111,12 +112,16 @@ struct bcm2835_desc {
+ #define BCM2835_DMA_RESET	BIT(31) /* WO, self clearing */
+ 
+ #define BCM2835_DMA_INT_EN	BIT(0)
++#define BCM2835_DMA_WAIT_RESP	BIT(3)
+ #define BCM2835_DMA_D_INC	BIT(4)
++#define BCM2835_DMA_D_WIDTH	BIT(5)
+ #define BCM2835_DMA_D_DREQ	BIT(6)
+ #define BCM2835_DMA_S_INC	BIT(8)
++#define BCM2835_DMA_S_WIDTH	BIT(9)
+ #define BCM2835_DMA_S_DREQ	BIT(10)
+ 
+ #define BCM2835_DMA_PER_MAP(x)	((x) << 16)
++#define BCM2835_DMA_WAITS(x)	(((x) & 0x1f) << 21)
+ 
+ #define BCM2835_DMA_DATA_TYPE_S8	1
+ #define BCM2835_DMA_DATA_TYPE_S16	2
+@@ -130,6 +135,14 @@ struct bcm2835_desc {
+ #define BCM2835_DMA_CHAN(n)	((n) << 8) /* Base address */
+ #define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
+ 
++#define MAX_NORMAL_TRANSFER	SZ_1G
++/*
++ * Max length on a Lite channel is 65535 bytes.
++ * DMA handles byte-enables on SDRAM reads and writes even on 128-bit accesses,
++ * but byte-enables don't exist on peripheral addresses, so align to 32-bit.
++ */
++#define MAX_LITE_TRANSFER	(SZ_64K - 4)
++
+ static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
+ {
+ 	return container_of(d, struct bcm2835_dmadev, ddev);
+@@ -226,12 +239,18 @@ static irqreturn_t bcm2835_dma_callback(
+ 	d = c->desc;
+ 
+ 	if (d) {
+-		/* TODO Only works for cyclic DMA */
+-		vchan_cyclic_callback(&d->vd);
+-	}
++		if (c->cyclic) {
++			vchan_cyclic_callback(&d->vd);
+ 
+-	/* Keep the DMA engine running */
+-	writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
++			/* Keep the DMA engine running */
++			writel(BCM2835_DMA_ACTIVE,
++			       c->chan_base + BCM2835_DMA_CS);
++
++		} else {
++			vchan_cookie_complete(&c->desc->vd);
++			bcm2835_dma_start_desc(c);
++		}
++	}
+ 
+ 	spin_unlock_irqrestore(&c->vc.lock, flags);
+ 
+@@ -339,8 +358,6 @@ static void bcm2835_dma_issue_pending(st
+ 	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ 	unsigned long flags;
+ 
+-	c->cyclic = true; /* Nothing else is implemented */
+-
+ 	spin_lock_irqsave(&c->vc.lock, flags);
+ 	if (vchan_issue_pending(&c->vc) && !c->desc)
+ 		bcm2835_dma_start_desc(c);
+@@ -358,7 +375,7 @@ static struct dma_async_tx_descriptor *b
+ 	struct bcm2835_desc *d;
+ 	dma_addr_t dev_addr;
+ 	unsigned int es, sync_type;
+-	unsigned int frame;
++	unsigned int frame, max_size;
+ 	int i;
+ 
+ 	/* Grab configuration */
+@@ -393,7 +410,12 @@ static struct dma_async_tx_descriptor *b
+ 
+ 	d->c = c;
+ 	d->dir = direction;
+-	d->frames = buf_len / period_len;
++	if (c->ch >= 8) /* LITE channel */
++		max_size = MAX_LITE_TRANSFER;
++	else
++		max_size = MAX_NORMAL_TRANSFER;
++	period_len = min(period_len, max_size);
++	d->frames = (buf_len - 1) / (period_len + 1);
+ 
+ 	d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
+ 	if (!d->cb_list) {
+@@ -441,17 +463,171 @@ static struct dma_async_tx_descriptor *b
+ 				BCM2835_DMA_PER_MAP(c->dreq);
+ 
+ 		/* Length of a frame */
+-		control_block->length = period_len;
++		if (frame != d->frames - 1)
++			control_block->length = period_len;
++		else
++			control_block->length = buf_len - (d->frames - 1) *
++						period_len;
+ 		d->size += control_block->length;
+ 
+ 		/*
+ 		 * Next block is the next frame.
+-		 * This DMA engine driver currently only supports cyclic DMA.
++		 * This function is called on cyclic DMA transfers.
+ 		 * Therefore, wrap around at number of frames.
+ 		 */
+ 		control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr;
+ 	}
+ 
++	c->cyclic = true;
++
++	return vchan_tx_prep(&c->vc, &d->vd, flags);
++}
++
++static struct dma_async_tx_descriptor *
++bcm2835_dma_prep_slave_sg(struct dma_chan *chan,
++			  struct scatterlist *sgl,
++			  unsigned int sg_len,
++			  enum dma_transfer_direction direction,
++			  unsigned long flags, void *context)
++{
++	struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
++	enum dma_slave_buswidth dev_width;
++	struct bcm2835_desc *d;
++	dma_addr_t dev_addr;
++	struct scatterlist *sgent;
++	unsigned int i, sync_type, split_cnt, max_size;
++
++	if (!is_slave_direction(direction)) {
++		dev_err(chan->device->dev, "direction not supported\n");
++		return NULL;
++	}
++
++	if (direction == DMA_DEV_TO_MEM) {
++		dev_addr = c->cfg.src_addr;
++		dev_width = c->cfg.src_addr_width;
++		sync_type = BCM2835_DMA_S_DREQ;
++	} else {
++		dev_addr = c->cfg.dst_addr;
++		dev_width = c->cfg.dst_addr_width;
++		sync_type = BCM2835_DMA_D_DREQ;
++	}
++
++	/* Bus width translates to the element size (ES) */
++	switch (dev_width) {
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		break;
++	default:
++		dev_err(chan->device->dev, "buswidth not supported: %i\n",
++			dev_width);
++		return NULL;
++	}
++
++	/* Allocate and setup the descriptor. */
++	d = kzalloc(sizeof(*d), GFP_NOWAIT);
++	if (!d)
++		return NULL;
++
++	d->dir = direction;
++
++	if (c->ch >= 8) /* LITE channel */
++		max_size = MAX_LITE_TRANSFER;
++	else
++		max_size = MAX_NORMAL_TRANSFER;
++
++	/*
++	 * Store the length of the SG list in d->frames
++	 * taking care to account for splitting up transfers
++	 * too large for a LITE channel
++	 */
++	d->frames = 0;
++	for_each_sg(sgl, sgent, sg_len, i) {
++		unsigned int len = sg_dma_len(sgent);
++
++		d->frames += len / max_size + 1;
++	}
++
++	/* Allocate memory for control blocks */
++	d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
++	d->control_block_base = dma_zalloc_coherent(chan->device->dev,
++			d->control_block_size, &d->control_block_base_phys,
++			GFP_NOWAIT);
++	if (!d->control_block_base) {
++		kfree(d);
++		return NULL;
++	}
++
++	/*
++	 * Iterate over all SG entries, create a control block
++	 * for each frame and link them together.
++	 * Count the number of times an SG entry had to be split
++	 * as a result of using a LITE channel
++	 */
++	split_cnt = 0;
++
++	for_each_sg(sgl, sgent, sg_len, i) {
++		unsigned int j;
++		dma_addr_t addr = sg_dma_address(sgent);
++		unsigned int len = sg_dma_len(sgent);
++
++		for (j = 0; j < len; j += max_size) {
++			struct bcm2835_dma_cb *control_block =
++				&d->control_block_base[i + split_cnt];
++
++			/* Setup addresses */
++			if (d->dir == DMA_DEV_TO_MEM) {
++				control_block->info = BCM2835_DMA_D_INC |
++						      BCM2835_DMA_D_WIDTH |
++						      BCM2835_DMA_S_DREQ;
++				control_block->src = dev_addr;
++				control_block->dst = addr + (dma_addr_t)j;
++			} else {
++				control_block->info = BCM2835_DMA_S_INC |
++						      BCM2835_DMA_S_WIDTH |
++						      BCM2835_DMA_D_DREQ;
++				control_block->src = addr + (dma_addr_t)j;
++				control_block->dst = dev_addr;
++			}
++
++			/* Common part */
++			control_block->info |=
++				BCM2835_DMA_WAITS(BCM2835_DMA_WAIT_CYCLES);
++			control_block->info |= BCM2835_DMA_WAIT_RESP;
++
++			/* Enable */
++			if (i == sg_len - 1 && len - j <= max_size)
++				control_block->info |= BCM2835_DMA_INT_EN;
++
++			/* Setup synchronization */
++			if (sync_type)
++				control_block->info |= sync_type;
++
++			/* Setup DREQ channel */
++			if (c->dreq)
++				control_block->info |=
++					BCM2835_DMA_PER_MAP(c->dreq);
++
++			/* Length of a frame */
++			control_block->length = min(len - j, max_size);
++			d->size += control_block->length;
++
++			if (i < sg_len - 1 || len - j > max_size) {
++				/* Next block is the next frame. */
++				control_block->next =
++					d->control_block_base_phys +
++					sizeof(struct bcm2835_dma_cb) *
++					(i + split_cnt + 1);
++			} else {
++				/* Next block is empty. */
++				control_block->next = 0;
++			}
++
++			if (len - j > max_size)
++				split_cnt++;
++		}
++	}
++
++	c->cyclic = false;
++
+ 	return vchan_tx_prep(&c->vc, &d->vd, flags);
+ error_cb:
+ 	i--;
+@@ -620,6 +796,7 @@ static int bcm2835_dma_probe(struct plat
+ 	od->ddev.device_tx_status = bcm2835_dma_tx_status;
+ 	od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
+ 	od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
++	od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg;
+ 	od->ddev.device_config = bcm2835_dma_slave_config;
+ 	od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
+ 	od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+@@ -708,4 +885,5 @@ module_platform_driver(bcm2835_dma_drive
+ MODULE_ALIAS("platform:bcm2835-dma");
+ MODULE_DESCRIPTION("BCM2835 DMA engine driver");
+ MODULE_AUTHOR("Florian Meier <florian.meier at koalo.de>");
++MODULE_AUTHOR("Gellert Weisz <gellert at raspberrypi.org>");
+ MODULE_LICENSE("GPL v2");
diff --git a/target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch b/target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch
new file mode 100644
index 0000000..1e562ce
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0021-dmaengine-bcm2835-set-residue_granularity-field.patch
@@ -0,0 +1,29 @@
+From 6ff0d626e7d84df71f6bc75e2c5ed35c42858bcc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Sat, 3 Oct 2015 15:58:59 +0200
+Subject: [PATCH 021/127] dmaengine: bcm2835: set residue_granularity field
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+bcm2835-dma supports residue reporting at burst level but didn't report
+this via the residue_granularity field.
+
+Without this field set properly we get playback issues with I2S cards.
+
+[by HiassofT, taken from bcm2708-dmaengine]
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ drivers/dma/bcm2835-dma.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -802,6 +802,7 @@ static int bcm2835_dma_probe(struct plat
+ 	od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ 	od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ 	od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
++	od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ 	od->ddev.dev = &pdev->dev;
+ 	INIT_LIST_HEAD(&od->ddev.channels);
+ 	spin_lock_init(&od->lock);
diff --git a/target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch b/target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch
new file mode 100644
index 0000000..e3c9595
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0022-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch
@@ -0,0 +1,98 @@
+From 16dc5e0535e48ce3e9c6995c87118e9e7b5b775a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Sat, 3 Oct 2015 22:22:55 +0200
+Subject: [PATCH 022/127] dmaengine: bcm2835: Load driver early and support
+ legacy API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Load driver early since at least bcm2708_fb doesn't support deferred
+probing and even if it did, we don't want the video driver deferred.
+Support the legacy DMA API which is needed by bcm2708_fb.
+Don't mask out channel 2.
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ drivers/dma/Kconfig       |  2 +-
+ drivers/dma/bcm2835-dma.c | 30 ++++++++++++++++++++++++------
+ 2 files changed, 25 insertions(+), 7 deletions(-)
+
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -108,7 +108,7 @@ config COH901318
+ 
+ config DMA_BCM2835
+ 	tristate "BCM2835 DMA engine support"
+-	depends on ARCH_BCM2835
++	depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ 	select DMA_ENGINE
+ 	select DMA_VIRTUAL_CHANNELS
+ 
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -36,6 +36,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/list.h>
+ #include <linux/module.h>
++#include <linux/platform_data/dma-bcm2708.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <linux/io.h>
+@@ -786,6 +787,10 @@ static int bcm2835_dma_probe(struct plat
+ 	if (IS_ERR(base))
+ 		return PTR_ERR(base);
+ 
++	rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
++	if (rc)
++		dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
++
+ 	od->base = base;
+ 
+ 	dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
+@@ -818,11 +823,8 @@ static int bcm2835_dma_probe(struct plat
+ 		goto err_no_dma;
+ 	}
+ 
+-	/*
+-	 * Do not use the FIQ and BULK channels,
+-	 * because they are used by the GPU.
+-	 */
+-	chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK);
++	/* Channel 0 is used by the legacy API */
++	chans_available &= ~BCM2835_DMA_BULK_MASK;
+ 
+ 	for (i = 0; i < pdev->num_resources; i++) {
+ 		irq = platform_get_irq(pdev, i);
+@@ -866,6 +868,7 @@ static int bcm2835_dma_remove(struct pla
+ {
+ 	struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
+ 
++	bcm_dmaman_remove(pdev);
+ 	dma_async_device_unregister(&od->ddev);
+ 	bcm2835_dma_free(od);
+ 
+@@ -881,7 +884,22 @@ static struct platform_driver bcm2835_dm
+ 	},
+ };
+ 
+-module_platform_driver(bcm2835_dma_driver);
++static int bcm2835_dma_init(void)
++{
++	return platform_driver_register(&bcm2835_dma_driver);
++}
++
++static void bcm2835_dma_exit(void)
++{
++	platform_driver_unregister(&bcm2835_dma_driver);
++}
++
++/*
++ * Load after serial driver (arch_initcall) so we see the messages if it fails,
++ * but before drivers (module_init) that need a DMA channel.
++ */
++subsys_initcall(bcm2835_dma_init);
++module_exit(bcm2835_dma_exit);
+ 
+ MODULE_ALIAS("platform:bcm2835-dma");
+ MODULE_DESCRIPTION("BCM2835 DMA engine driver");
diff --git a/target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch b/target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch
new file mode 100644
index 0000000..42cf9fd
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0023-bcm2835-dma-Fix-dreq-not-set-for-slave-transfers.patch
@@ -0,0 +1,21 @@
+From 50eef5c715b894683aebf81332c82426dc10f8cb Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sat, 10 Oct 2015 12:29:18 +0200
+Subject: [PATCH 023/127] bcm2835-dma: Fix dreq not set for slave transfers
+
+Set dreq to slave_id if it is not set like in bcm2708-dmaengine.
+---
+ drivers/dma/bcm2835-dma.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -657,6 +657,8 @@ static int bcm2835_dma_slave_config(stru
+ 	}
+ 
+ 	c->cfg = *cfg;
++	if (!c->dreq)
++		c->dreq = cfg->slave_id;
+ 
+ 	return 0;
+ }
diff --git a/target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch b/target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch
new file mode 100644
index 0000000..4461fec
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0024-bcm2835-dma-Limit-cyclic-transfers-on-lite-channels-.patch
@@ -0,0 +1,37 @@
+From c7e464c38d38ad59899c94dfad6c3455c18f7d76 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias at horus.com>
+Date: Sun, 11 Oct 2015 12:28:30 +0200
+Subject: [PATCH 024/127] bcm2835-dma: Limit cyclic transfers on lite channels
+ to 32k
+
+Transfers larger than 32k cause repeated clicking with I2S soundcards.
+The exact reason is yet unknown, so limit to 32k as bcm2708-dmaengine
+did as an intermediate fix.
+---
+ drivers/dma/bcm2835-dma.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -144,6 +144,12 @@ struct bcm2835_desc {
+  */
+ #define MAX_LITE_TRANSFER	(SZ_64K - 4)
+ 
++/*
++ * Transfers larger than 32k cause issues with the bcm2708-i2s driver,
++ * so limit transfer size to 32k as bcm2708-dmaengine did.
++ */
++#define MAX_CYCLIC_LITE_TRANSFER	SZ_32K
++
+ static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
+ {
+ 	return container_of(d, struct bcm2835_dmadev, ddev);
+@@ -412,7 +418,7 @@ static struct dma_async_tx_descriptor *b
+ 	d->c = c;
+ 	d->dir = direction;
+ 	if (c->ch >= 8) /* LITE channel */
+-		max_size = MAX_LITE_TRANSFER;
++		max_size = MAX_CYCLIC_LITE_TRANSFER;
+ 	else
+ 		max_size = MAX_NORMAL_TRANSFER;
+ 	period_len = min(period_len, max_size);
diff --git a/target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch b/target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch
new file mode 100644
index 0000000..cd7f242
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0025-bcm2835-Add-support-for-uart1.patch
@@ -0,0 +1,57 @@
+From 34cb40cb97cd3080d3d0f314b2b063939b90c069 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Sat, 15 Aug 2015 20:50:02 +0200
+Subject: [PATCH 025/127] bcm2835: Add support for uart1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is a hack until a proper solution is agreed upon.
+Martin Sperl is doing some work in this area.
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ arch/arm/mach-bcm/board_bcm2835.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/arch/arm/mach-bcm/board_bcm2835.c
++++ b/arch/arm/mach-bcm/board_bcm2835.c
+@@ -22,6 +22,29 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ 
++/* Use this hack until a proper solution is agreed upon */
++static void __init bcm2835_init_uart1(void)
++{
++	struct device_node *np;
++
++	np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
++	if (of_device_is_available(np)) {
++		np = of_find_compatible_node(NULL, NULL,
++					     "bcrm,bcm2835-aux-enable");
++		if (np) {
++			void __iomem *base = of_iomap(np, 0);
++
++			if (!base) {
++				pr_err("bcm2835: Failed enabling Mini UART\n");
++				return;
++			}
++
++			writel(1, base);
++			pr_info("bcm2835: Mini UART enabled\n");
++		}
++	}
++}
++
+ static void __init bcm2835_init(void)
+ {
+ 	struct device_node *np = of_find_node_by_path("/system");
+@@ -42,6 +65,8 @@ static void __init bcm2835_init(void)
+ 		system_rev = val;
+ 	if (!of_property_read_u64(np, "linux,serial", &val64))
+ 		system_serial_low = val64;
++
++	bcm2835_init_uart1();
+ }
+ 
+ static const char * const bcm2835_compat[] = {
diff --git a/target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch b/target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch
new file mode 100644
index 0000000..8bd7be9
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0026-firmware-bcm2835-Add-missing-property-tags.patch
@@ -0,0 +1,62 @@
+From 40946ea47dd52c827b30d3601f7b393c46fbfcf3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf at tronnes.org>
+Date: Fri, 26 Jun 2015 14:21:20 +0200
+Subject: [PATCH 026/127] firmware: bcm2835: Add missing property tags
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
+ 	RPI_FIRMWARE_GET_MIN_VOLTAGE =                        0x00030008,
+ 	RPI_FIRMWARE_GET_TURBO =                              0x00030009,
+ 	RPI_FIRMWARE_GET_MAX_TEMPERATURE =                    0x0003000a,
++	RPI_FIRMWARE_GET_STC =                                0x0003000b,
+ 	RPI_FIRMWARE_ALLOCATE_MEMORY =                        0x0003000c,
+ 	RPI_FIRMWARE_LOCK_MEMORY =                            0x0003000d,
+ 	RPI_FIRMWARE_UNLOCK_MEMORY =                          0x0003000e,
+@@ -72,10 +73,12 @@ enum rpi_firmware_property_tag {
+ 	RPI_FIRMWARE_SET_ENABLE_QPU =                         0x00030012,
+ 	RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE =       0x00030014,
+ 	RPI_FIRMWARE_GET_EDID_BLOCK =                         0x00030020,
++	RPI_FIRMWARE_GET_CUSTOMER_OTP =                       0x00030021,
+ 	RPI_FIRMWARE_SET_CLOCK_STATE =                        0x00038001,
+ 	RPI_FIRMWARE_SET_CLOCK_RATE =                         0x00038002,
+ 	RPI_FIRMWARE_SET_VOLTAGE =                            0x00038003,
+ 	RPI_FIRMWARE_SET_TURBO =                              0x00038009,
++	RPI_FIRMWARE_SET_CUSTOMER_OTP =                       0x00038021,
+ 
+ 	/* Dispmanx TAGS */
+ 	RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE =                   0x00040001,
+@@ -89,6 +92,7 @@ enum rpi_firmware_property_tag {
+ 	RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET =         0x00040009,
+ 	RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN =               0x0004000a,
+ 	RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE =                0x0004000b,
++	RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF =               0x0004000f,
+ 	RPI_FIRMWARE_FRAMEBUFFER_RELEASE =                    0x00048001,
+ 	RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ 	RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT =  0x00044004,
+@@ -98,6 +102,7 @@ enum rpi_firmware_property_tag {
+ 	RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET =        0x00044009,
+ 	RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN =              0x0004400a,
+ 	RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE =               0x0004400b,
++	RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC =                 0x0004400e,
+ 	RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT =  0x00048003,
+ 	RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT =   0x00048004,
+ 	RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH =                  0x00048005,
+@@ -106,6 +111,9 @@ enum rpi_firmware_property_tag {
+ 	RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET =         0x00048009,
+ 	RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN =               0x0004800a,
+ 	RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE =                0x0004800b,
++	RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC =                  0x0004800e,
++
++	RPI_FIRMWARE_VCHIQ_INIT =                             0x00048010,
+ 
+ 	RPI_FIRMWARE_GET_COMMAND_LINE =                       0x00050001,
+ 	RPI_FIRMWARE_GET_DMA_CHANNELS =                       0x00060001,
diff --git a/target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch b/target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch
new file mode 100644
index 0000000..56120c6
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0027-Main-bcm2708-bcm2709-linux-port.patch
@@ -0,0 +1,2418 @@
+From 75ae3f717d7598a6eb1582097923ee0838a02a8b Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix at gmail.com>
+Date: Sun, 12 May 2013 12:24:19 +0100
+Subject: [PATCH 027/127] Main bcm2708/bcm2709 linux port
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix at gmail.com>
+Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
+---
+ arch/arm/Kconfig                                 |  49 +++
+ arch/arm/Kconfig.debug                           |   8 +
+ arch/arm/Makefile                                |   2 +
+ arch/arm/kernel/head.S                           |   8 +
+ arch/arm/kernel/process.c                        |  10 +
+ arch/arm/mach-bcm2708/Kconfig                    |  23 ++
+ arch/arm/mach-bcm2708/Makefile                   |   5 +
+ arch/arm/mach-bcm2708/Makefile.boot              |   3 +
+ arch/arm/mach-bcm2708/bcm2708.c                  | 231 ++++++++++++
+ arch/arm/mach-bcm2708/include/mach/debug-macro.S |  22 ++
+ arch/arm/mach-bcm2708/include/mach/io.h          |  27 ++
+ arch/arm/mach-bcm2708/include/mach/memory.h      |  57 +++
+ arch/arm/mach-bcm2708/include/mach/platform.h    | 112 ++++++
+ arch/arm/mach-bcm2708/include/mach/system.h      |  37 ++
+ arch/arm/mach-bcm2708/include/mach/uncompress.h  |  84 +++++
+ arch/arm/mach-bcm2708/include/mach/vmalloc.h     |  20 ++
+ arch/arm/mach-bcm2709/Kconfig                    |  16 +
+ arch/arm/mach-bcm2709/Makefile                   |   5 +
+ arch/arm/mach-bcm2709/Makefile.boot              |   3 +
+ arch/arm/mach-bcm2709/bcm2709.c                  | 380 ++++++++++++++++++++
+ arch/arm/mach-bcm2709/include/mach/debug-macro.S |  22 ++
+ arch/arm/mach-bcm2709/include/mach/entry-macro.S | 123 +++++++
+ arch/arm/mach-bcm2709/include/mach/io.h          |  27 ++
+ arch/arm/mach-bcm2709/include/mach/memory.h      |  57 +++
+ arch/arm/mach-bcm2709/include/mach/platform.h    | 188 ++++++++++
+ arch/arm/mach-bcm2709/include/mach/system.h      |  37 ++
+ arch/arm/mach-bcm2709/include/mach/uncompress.h  |  84 +++++
+ arch/arm/mach-bcm2709/include/mach/vc_mem.h      |  35 ++
+ arch/arm/mach-bcm2709/include/mach/vmalloc.h     |  20 ++
+ arch/arm/mach-bcm2709/vc_mem.c                   | 431 +++++++++++++++++++++++
+ arch/arm/mm/Kconfig                              |   2 +-
+ arch/arm/mm/proc-v6.S                            |  15 +-
+ arch/arm/mm/proc-v7.S                            |   1 +
+ arch/arm/tools/mach-types                        |   2 +
+ drivers/clocksource/Makefile                     |   2 +-
+ drivers/irqchip/Makefile                         |   3 +
+ include/linux/mmc/host.h                         |   1 +
+ 37 files changed, 2147 insertions(+), 5 deletions(-)
+ create mode 100644 arch/arm/mach-bcm2708/Kconfig
+ create mode 100644 arch/arm/mach-bcm2708/Makefile
+ create mode 100644 arch/arm/mach-bcm2708/Makefile.boot
+ create mode 100644 arch/arm/mach-bcm2708/bcm2708.c
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/debug-macro.S
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/io.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/memory.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/platform.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/system.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/uncompress.h
+ create mode 100644 arch/arm/mach-bcm2708/include/mach/vmalloc.h
+ create mode 100644 arch/arm/mach-bcm2709/Kconfig
+ create mode 100644 arch/arm/mach-bcm2709/Makefile
+ create mode 100644 arch/arm/mach-bcm2709/Makefile.boot
+ create mode 100644 arch/arm/mach-bcm2709/bcm2709.c
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/debug-macro.S
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/entry-macro.S
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/io.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/memory.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/platform.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/system.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/uncompress.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/vc_mem.h
+ create mode 100644 arch/arm/mach-bcm2709/include/mach/vmalloc.h
+ create mode 100644 arch/arm/mach-bcm2709/vc_mem.c
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -317,6 +317,52 @@ choice
+ 	default ARCH_VERSATILE if !MMU
+ 	default ARCH_MULTIPLATFORM if MMU
+ 
++config ARCH_BCM2708
++	bool "Broadcom BCM2708 family"
++	select CPU_V6
++	select ARM_AMBA
++	select CLKSRC_MMIO
++	select CLKSRC_OF if OF
++	select HAVE_SCHED_CLOCK
++	select NEED_MACH_GPIO_H
++	select NEED_MACH_MEMORY_H
++	select COMMON_CLK
++	select ARCH_HAS_CPUFREQ
++	select GENERIC_CLOCKEVENTS
++	select ARM_ERRATA_411920
++	select MACH_BCM2708
++	select MULTI_IRQ_HANDLER
++	select SPARSE_IRQ
++	select VC4
++	select FIQ
++	help
++	  This enables support for Broadcom BCM2708 boards.
++
++config ARCH_BCM2709
++	bool "Broadcom BCM2709 family"
++	select CPU_V7
++	select HAVE_SMP
++	select ARM_AMBA
++	select MIGHT_HAVE_CACHE_L2X0
++	select HAVE_SCHED_CLOCK
++	select NEED_MACH_MEMORY_H
++	select NEED_MACH_IO_H
++	select COMMON_CLK
++	select ARCH_HAS_CPUFREQ
++	select GENERIC_CLOCKEVENTS
++	select MACH_BCM2709
++	select MULTI_IRQ_HANDLER
++	select SPARSE_IRQ
++	select MFD_SYSCON
++	select VC4
++	select FIQ
++	select USE_OF
++	select ARCH_REQUIRE_GPIOLIB
++	select PINCTRL
++	select PINCTRL_BCM2835
++	help
++	  This enables support for Broadcom BCM2709 boards.
++
+ config ARCH_MULTIPLATFORM
+ 	bool "Allow multiple platforms to be selected"
+ 	depends on MMU
+@@ -808,6 +854,9 @@ config ARCH_VIRT
+ # Kconfigs may be included either alphabetically (according to the
+ # plat- suffix) or along side the corresponding mach-* source.
+ #
++source "arch/arm/mach-bcm2708/Kconfig"
++source "arch/arm/mach-bcm2709/Kconfig"
++
+ source "arch/arm/mach-mvebu/Kconfig"
+ 
+ source "arch/arm/mach-alpine/Kconfig"
+--- a/arch/arm/Kconfig.debug
++++ b/arch/arm/Kconfig.debug
+@@ -1241,6 +1241,14 @@ choice
+ 		  options; the platform specific options are deprecated
+ 		  and will be soon removed.
+ 
++	config DEBUG_BCM2708_UART0
++		bool "Broadcom BCM270X UART0 (PL011)"
++		depends on ARCH_BCM2708 || ARCH_BCM2709
++		help
++		  Say Y here if you want the debug print routines to direct
++		  their output to UART 0. The port must have been initialised
++		  by the boot-loader before use.
++
+ endchoice
+ 
+ config DEBUG_EXYNOS_UART
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -159,6 +159,8 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x003080
+ 
+ # Machine directory name.  This list is sorted alphanumerically
+ # by CONFIG_* macro name.
++machine-$(CONFIG_ARCH_BCM2708)		+= bcm2708
++machine-$(CONFIG_ARCH_BCM2709)		+= bcm2709
+ machine-$(CONFIG_ARCH_ALPINE)		+= alpine
+ machine-$(CONFIG_ARCH_AT91)		+= at91
+ machine-$(CONFIG_ARCH_AXXIA)		+= axxia
+--- a/arch/arm/kernel/head.S
++++ b/arch/arm/kernel/head.S
+@@ -700,6 +700,14 @@ ARM_BE8(rev16	ip, ip)
+ 	ldrcc	r7, [r4], #4	@ use branch for delay slot
+ 	bcc	1b
+ 	ret	lr
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
++	nop
+ #endif
+ ENDPROC(__fixup_a_pv_table)
+ 
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -91,6 +91,16 @@ void arch_cpu_idle_exit(void)
+ 	ledtrig_cpu(CPU_LED_IDLE_END);
+ }
+ 
++char bcm2708_reboot_mode = 'h';
++
++int __init reboot_setup(char *str)
++{
++	bcm2708_reboot_mode = str[0];
++	return 1;
++}
++
++__setup("reboot=", reboot_setup);
++
+ void __show_regs(struct pt_regs *regs)
+ {
+ 	unsigned long flags;
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/Kconfig
+@@ -0,0 +1,23 @@
++menu "Broadcom BCM2708 Implementations"
++	depends on ARCH_BCM2708
++
++config MACH_BCM2708
++	bool "Broadcom BCM2708 Development Platform"
++	select NEED_MACH_MEMORY_H
++	select NEED_MACH_IO_H
++	select CPU_V6
++	select USE_OF
++	select ARCH_REQUIRE_GPIOLIB
++	select PINCTRL
++	select PINCTRL_BCM2835
++	help
++	  Include support for the Broadcom(R) BCM2708 platform.
++
++config BCM2708_NOL2CACHE
++	bool "Videocore L2 cache disable"
++	depends on MACH_BCM2708
++        default n
++        help
++          Do not allow ARM to use GPU's L2 cache. Requires disable_l2cache in config.txt.
++
++endmenu
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-$(CONFIG_MACH_BCM2708) 	+= bcm2708.o
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/Makefile.boot
+@@ -0,0 +1,3 @@
++   zreladdr-y	:= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00800000
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/bcm2708.c
+@@ -0,0 +1,231 @@
++/*
++ *  linux/arch/arm/mach-bcm2708/bcm2708.c
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <asm/system_info.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <mach/system.h>
++
++#include <linux/broadcom/vc_cma.h>
++
++/* Effectively we have an IOMMU (ARM<->VideoCore map) that is set up to
++ * give us IO access only to 64Mbytes of physical memory (26 bits).  We could
++ * represent this window by setting our dmamasks to 26 bits but, in fact
++ * we're not going to use addresses outside this range (they're not in real
++ * memory) so we don't bother.
++ *
++ * In the future we might include code to use this IOMMU to remap other
++ * physical addresses onto VideoCore memory then the use of 32-bits would be
++ * more legitimate.
++ */
++
++/* command line parameters */
++static unsigned boardrev, serial;
++static unsigned reboot_part = 0;
++
++static struct map_desc bcm2708_io_desc[] __initdata = {
++	{
++	 .virtual = IO_ADDRESS(ARMCTRL_BASE),
++	 .pfn = __phys_to_pfn(ARMCTRL_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(UART0_BASE),
++	 .pfn = __phys_to_pfn(UART0_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(UART1_BASE),
++	 .pfn = __phys_to_pfn(UART1_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(DMA_BASE),
++	 .pfn = __phys_to_pfn(DMA_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(MCORE_BASE),
++	 .pfn = __phys_to_pfn(MCORE_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(ST_BASE),
++	 .pfn = __phys_to_pfn(ST_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(USB_BASE),
++	 .pfn = __phys_to_pfn(USB_BASE),
++	 .length = SZ_128K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(PM_BASE),
++	 .pfn = __phys_to_pfn(PM_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(GPIO_BASE),
++	 .pfn = __phys_to_pfn(GPIO_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE}
++};
++
++void __init bcm2708_map_io(void)
++{
++	iotable_init(bcm2708_io_desc, ARRAY_SIZE(bcm2708_io_desc));
++}
++
++int calc_rsts(int partition)
++{
++	return PM_PASSWORD |
++		((partition & (1 << 0))  << 0) |
++		((partition & (1 << 1))  << 1) |
++		((partition & (1 << 2))  << 2) |
++		((partition & (1 << 3))  << 3) |
++		((partition & (1 << 4))  << 4) |
++		((partition & (1 << 5))  << 5);
++}
++
++static void bcm2708_restart(enum reboot_mode mode, const char *cmd)
++{
++	extern char bcm2708_reboot_mode;
++	uint32_t pm_rstc, pm_wdog;
++	uint32_t timeout = 10;
++	uint32_t pm_rsts = 0;
++
++	if(bcm2708_reboot_mode == 'q')
++	{
++		// NOOBS < 1.3 booting with reboot=q
++		pm_rsts = readl(__io_address(PM_RSTS));
++		pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRQ_SET;
++	}
++	else if(bcm2708_reboot_mode == 'p')
++	{
++		// NOOBS < 1.3 halting
++		pm_rsts = readl(__io_address(PM_RSTS));
++		pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRH_SET;
++	}
++	else
++	{
++		pm_rsts = calc_rsts(reboot_part);
++	}
++
++	writel(pm_rsts, __io_address(PM_RSTS));
++
++	/* Setup watchdog for reset */
++	pm_rstc = readl(__io_address(PM_RSTC));
++
++	pm_wdog = PM_PASSWORD | (timeout & PM_WDOG_TIME_SET); // watchdog timer = timer clock / 16; need password (31:16) + value (11:0)
++	pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET;
++
++	writel(pm_wdog, __io_address(PM_WDOG));
++	writel(pm_rstc, __io_address(PM_RSTC));
++}
++
++/* We can't really power off, but if we do the normal reset scheme, and indicate to bootcode.bin not to reboot, then most of the chip will be powered off */
++static void bcm2708_power_off(void)
++{
++	extern char bcm2708_reboot_mode;
++	if(bcm2708_reboot_mode == 'q')
++	{
++		// NOOBS < v1.3
++		bcm2708_restart('p', "");
++	}
++	else
++	{
++		/* partition 63 is special code for HALT the bootloader knows not to boot*/
++		reboot_part = 63;
++		/* continue with normal reset mechanism */
++		bcm2708_restart(0, "");
++	}
++}
++
++static void __init bcm2708_init_uart1(void)
++{
++	struct device_node *np;
++
++	np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
++	if (of_device_is_available(np)) {
++		pr_info("bcm2708: Mini UART enabled\n");
++		writel(1, __io_address(UART1_BASE + 0x4));
++	}
++}
++
++void __init bcm2708_init(void)
++{
++	int ret;
++
++	vc_cma_early_init();
++
++	pm_power_off = bcm2708_power_off;
++
++	ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
++				   NULL);
++	if (ret) {
++		pr_err("of_platform_populate failed: %d\n", ret);
++		BUG();
++	}
++
++	bcm2708_init_uart1();
++
++	system_rev = boardrev;
++	system_serial_low = serial;
++}
++
++void __init bcm2708_init_early(void)
++{
++	/*
++	 * Some devices allocate their coherent buffers from atomic
++	 * context. Increase size of atomic coherent pool to make sure such
++	 * the allocations won't fail.
++	 */
++	init_dma_coherent_pool_size(SZ_4M);
++}
++
++static void __init board_reserve(void)
++{
++	vc_cma_reserve();
++}
++
++static const char * const bcm2708_compat[] = {
++	"brcm,bcm2708",
++	NULL
++};
++
++MACHINE_START(BCM2708, "BCM2708")
++    /* Maintainer: Broadcom Europe Ltd. */
++	.map_io = bcm2708_map_io,
++	.init_machine = bcm2708_init,
++	.init_early = bcm2708_init_early,
++	.reserve = board_reserve,
++	.restart	= bcm2708_restart,
++	.dt_compat = bcm2708_compat,
++MACHINE_END
++
++module_param(boardrev, uint, 0644);
++module_param(serial, uint, 0644);
++module_param(reboot_part, uint, 0644);
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/debug-macro.S
+@@ -0,0 +1,22 @@
++/* arch/arm/mach-bcm2708/include/mach/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 1994-1999 Russell King
++ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++*/
++
++#include <mach/platform.h>
++
++		.macro	addruart, rp, rv, tmp
++		ldr	\rp, =UART0_BASE
++		ldr	\rv, =IO_ADDRESS(UART0_BASE)
++		.endm
++
++#include <debug/pl01x.S>
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/io.h
+@@ -0,0 +1,27 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/io.h
++ *
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++#define __io(a)		__typesafe_io(a)
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/memory.h
+@@ -0,0 +1,57 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/memory.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++/* Memory overview:
++
++   [ARMcore] <--virtual addr-->
++   [ARMmmu] <--physical addr-->
++   [GERTmap] <--bus add-->
++   [VCperiph]
++
++*/
++
++/*
++ * Physical DRAM offset.
++ */
++#define BCM_PLAT_PHYS_OFFSET	UL(0x00000000)
++#define VC_ARMMEM_OFFSET	UL(0x00000000)   /* offset in VC of ARM memory */
++
++#ifdef CONFIG_BCM2708_NOL2CACHE
++ #define _REAL_BUS_OFFSET UL(0xC0000000)   /* don't use L1 or L2 caches */
++#else
++ #define _REAL_BUS_OFFSET UL(0x40000000)   /* use L2 cache */
++#endif
++
++/* We're using the memory at 64M in the VideoCore for Linux - this adjustment
++ * will provide the offset into this area as well as setting the bits that
++ * stop the L1 and L2 cache from being used
++ *
++ * WARNING: this only works because the ARM is given memory at a fixed location
++ *          (ARMMEM_OFFSET)
++ */
++#define BUS_OFFSET          (VC_ARMMEM_OFFSET + _REAL_BUS_OFFSET)
++#define __virt_to_bus(x)    ((x) + (BUS_OFFSET - PAGE_OFFSET))
++#define __bus_to_virt(x)    ((x) - (BUS_OFFSET - PAGE_OFFSET))
++#define __pfn_to_bus(x)     (__pfn_to_phys(x) + (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++#define __bus_to_pfn(x)     __phys_to_pfn((x) - (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/platform.h
+@@ -0,0 +1,112 @@
++/*
++ * arch/arm/mach-bcm2708/include/mach/platform.h
++ *
++ * Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _BCM2708_PLATFORM_H
++#define _BCM2708_PLATFORM_H
++
++
++/* macros to get at IO space when running virtually */
++#define IO_ADDRESS(x)	(((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
++
++#define __io_address(n)     IOMEM(IO_ADDRESS(n))
++
++
++/*
++ *  SDRAM
++ */
++#define BCM2708_SDRAM_BASE           0x00000000
++
++/*
++ *  Logic expansion modules
++ *
++ */
++
++
++/* ------------------------------------------------------------------------
++ *  BCM2708 ARMCTRL Registers
++ * ------------------------------------------------------------------------
++ */
++
++#define HW_REGISTER_RW(addr) (addr)
++#define HW_REGISTER_RO(addr) (addr)
++
++/*
++ * Definitions and addresses for the ARM CONTROL logic
++ * This file is manually generated.
++ */
++
++#define BCM2708_PERI_BASE        0x20000000
++#define IC0_BASE                 (BCM2708_PERI_BASE + 0x2000)
++#define ST_BASE                  (BCM2708_PERI_BASE + 0x3000)   /* System Timer */
++#define MPHI_BASE		 (BCM2708_PERI_BASE + 0x6000)	/* Message -based Parallel Host Interface */
++#define DMA_BASE		 (BCM2708_PERI_BASE + 0x7000)	/* DMA controller */
++#define ARM_BASE                 (BCM2708_PERI_BASE + 0xB000)	 /* BCM2708 ARM control block */
++#define PM_BASE			 (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
++#define PCM_CLOCK_BASE           (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */
++#define RNG_BASE                 (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
++#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO */
++#define UART0_BASE               (BCM2708_PERI_BASE + 0x201000)	/* Uart 0 */
++#define MMCI0_BASE               (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
++#define I2S_BASE                 (BCM2708_PERI_BASE + 0x203000) /* I2S */
++#define SPI0_BASE		 (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
++#define BSC0_BASE		 (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
++#define UART1_BASE               (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
++#define EMMC_BASE                (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
++#define SMI_BASE		 (BCM2708_PERI_BASE + 0x600000) /* SMI */
++#define BSC1_BASE		 (BCM2708_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */
++#define USB_BASE                 (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
++#define MCORE_BASE               (BCM2708_PERI_BASE + 0x0000)   /* Fake frame buffer device (actually the multicore sync block*/
++
++#define ARMCTRL_BASE             (ARM_BASE + 0x000)
++#define ARMCTRL_IC_BASE          (ARM_BASE + 0x200)           /* ARM interrupt controller */
++#define ARMCTRL_TIMER0_1_BASE    (ARM_BASE + 0x400)           /* Timer 0 and 1 */
++#define ARMCTRL_0_SBM_BASE       (ARM_BASE + 0x800)           /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
++
++/*
++ * Watchdog
++ */
++#define PM_RSTC			       (PM_BASE+0x1c)
++#define PM_RSTS			       (PM_BASE+0x20)
++#define PM_WDOG			       (PM_BASE+0x24)
++
++#define PM_WDOG_RESET                                         0000000000
++#define PM_PASSWORD		       0x5a000000
++#define PM_WDOG_TIME_SET	       0x000fffff
++#define PM_RSTC_WRCFG_CLR              0xffffffcf
++#define PM_RSTC_WRCFG_SET              0x00000030
++#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
++#define PM_RSTC_RESET                  0x00000102
++
++#define PM_RSTS_HADPOR_SET                                 0x00001000
++#define PM_RSTS_HADSRH_SET                                 0x00000400
++#define PM_RSTS_HADSRF_SET                                 0x00000200
++#define PM_RSTS_HADSRQ_SET                                 0x00000100
++#define PM_RSTS_HADWRH_SET                                 0x00000040
++#define PM_RSTS_HADWRF_SET                                 0x00000020
++#define PM_RSTS_HADWRQ_SET                                 0x00000010
++#define PM_RSTS_HADDRH_SET                                 0x00000004
++#define PM_RSTS_HADDRF_SET                                 0x00000002
++#define PM_RSTS_HADDRQ_SET                                 0x00000001
++
++#define UART0_CLOCK      3000000
++
++#endif
++
++/* END */
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/system.h
+@@ -0,0 +1,37 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/system.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <linux/io.h>
++#include <mach/platform.h>
++
++static inline void arch_idle(void)
++{
++	/*
++	 * This should do all the clock switching
++	 * and wait for interrupt tricks
++	 */
++	cpu_do_idle();
++}
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/uncompress.h
+@@ -0,0 +1,84 @@
++/*
++ *  arch/arm/mach-bcn2708/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/io.h>
++#include <linux/amba/serial.h>
++#include <mach/platform.h>
++
++#define UART_BAUD 115200
++
++#define BCM2708_UART_DR   __io(UART0_BASE + UART01x_DR)
++#define BCM2708_UART_FR   __io(UART0_BASE + UART01x_FR)
++#define BCM2708_UART_IBRD __io(UART0_BASE + UART011_IBRD)
++#define BCM2708_UART_FBRD __io(UART0_BASE + UART011_FBRD)
++#define BCM2708_UART_LCRH __io(UART0_BASE + UART011_LCRH)
++#define BCM2708_UART_CR   __io(UART0_BASE + UART011_CR)
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++	while (__raw_readl(BCM2708_UART_FR) & UART01x_FR_TXFF)
++		barrier();
++
++	__raw_writel(c, BCM2708_UART_DR);
++}
++
++static inline void flush(void)
++{
++	int fr;
++
++	do {
++		fr = __raw_readl(BCM2708_UART_FR);
++		barrier();
++	} while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
++}
++
++static inline void arch_decomp_setup(void)
++{
++	int temp, div, rem, frac;
++
++	temp = 16 * UART_BAUD;
++	div = UART0_CLOCK / temp;
++	rem = UART0_CLOCK % temp;
++	temp = (8 * rem) / UART_BAUD;
++	frac = (temp >> 1) + (temp & 1);
++
++	/* Make sure the UART is disabled before we start */
++	__raw_writel(0, BCM2708_UART_CR);
++
++	/* Set the baud rate */
++	__raw_writel(div, BCM2708_UART_IBRD);
++	__raw_writel(frac, BCM2708_UART_FBRD);
++
++	/* Set the UART to 8n1, FIFO enabled */
++	__raw_writel(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, BCM2708_UART_LCRH);
++
++	/* Enable the UART */
++	__raw_writel(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,
++			BCM2708_UART_CR);
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_wdog()
+--- /dev/null
++++ b/arch/arm/mach-bcm2708/include/mach/vmalloc.h
+@@ -0,0 +1,20 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/vmalloc.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#define VMALLOC_END		(0xe8000000)
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/Kconfig
+@@ -0,0 +1,16 @@
++menu "Broadcom BCM2709 Implementations"
++	depends on ARCH_BCM2709
++
++config MACH_BCM2709
++	bool "Broadcom BCM2709 Development Platform"
++	help
++	  Include support for the Broadcom(R) BCM2709 platform.
++
++config BCM2708_NOL2CACHE
++	bool "Videocore L2 cache disable"
++	depends on MACH_BCM2709
++        default y
++        help
++          Do not allow ARM to use GPU's L2 cache. Requires disable_l2cache in config.txt.
++
++endmenu
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/Makefile
+@@ -0,0 +1,5 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-$(CONFIG_MACH_BCM2709) 	+= bcm2709.o
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/Makefile.boot
+@@ -0,0 +1,3 @@
++   zreladdr-y	:= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00800000
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/bcm2709.c
+@@ -0,0 +1,380 @@
++/*
++ *  linux/arch/arm/mach-bcm2709/bcm2709.c
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/init.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk-provider.h>
++#include <linux/clocksource.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++
++#include <asm/system_info.h>
++#include <asm/mach-types.h>
++#include <asm/cputype.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <mach/system.h>
++
++#include <linux/broadcom/vc_cma.h>
++
++/* Effectively we have an IOMMU (ARM<->VideoCore map) that is set up to
++ * give us IO access only to 64Mbytes of physical memory (26 bits).  We could
++ * represent this window by setting our dmamasks to 26 bits but, in fact
++ * we're not going to use addresses outside this range (they're not in real
++ * memory) so we don't bother.
++ *
++ * In the future we might include code to use this IOMMU to remap other
++ * physical addresses onto VideoCore memory then the use of 32-bits would be
++ * more legitimate.
++ */
++
++/* command line parameters */
++static unsigned boardrev, serial;
++static unsigned reboot_part = 0;
++
++static struct map_desc bcm2709_io_desc[] __initdata = {
++	{
++	 .virtual = IO_ADDRESS(ARMCTRL_BASE),
++	 .pfn = __phys_to_pfn(ARMCTRL_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(UART0_BASE),
++	 .pfn = __phys_to_pfn(UART0_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(UART1_BASE),
++	 .pfn = __phys_to_pfn(UART1_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(DMA_BASE),
++	 .pfn = __phys_to_pfn(DMA_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(MCORE_BASE),
++	 .pfn = __phys_to_pfn(MCORE_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(ST_BASE),
++	 .pfn = __phys_to_pfn(ST_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(USB_BASE),
++	 .pfn = __phys_to_pfn(USB_BASE),
++	 .length = SZ_128K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(PM_BASE),
++	 .pfn = __phys_to_pfn(PM_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(GPIO_BASE),
++	 .pfn = __phys_to_pfn(GPIO_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++	{
++	 .virtual = IO_ADDRESS(ARM_LOCAL_BASE),
++	 .pfn = __phys_to_pfn(ARM_LOCAL_BASE),
++	 .length = SZ_4K,
++	 .type = MT_DEVICE},
++};
++
++void __init bcm2709_map_io(void)
++{
++	iotable_init(bcm2709_io_desc, ARRAY_SIZE(bcm2709_io_desc));
++}
++
++int calc_rsts(int partition)
++{
++	return PM_PASSWORD |
++		((partition & (1 << 0))  << 0) |
++		((partition & (1 << 1))  << 1) |
++		((partition & (1 << 2))  << 2) |
++		((partition & (1 << 3))  << 3) |
++		((partition & (1 << 4))  << 4) |
++		((partition & (1 << 5))  << 5);
++}
++
++static void bcm2709_restart(enum reboot_mode mode, const char *cmd)
++{
++	extern char bcm2708_reboot_mode;
++	uint32_t pm_rstc, pm_wdog;
++	uint32_t timeout = 10;
++	uint32_t pm_rsts = 0;
++
++	if(bcm2708_reboot_mode == 'q')
++	{
++		// NOOBS < 1.3 booting with reboot=q
++		pm_rsts = readl(__io_address(PM_RSTS));
++		pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRQ_SET;
++	}
++	else if(bcm2708_reboot_mode == 'p')
++	{
++		// NOOBS < 1.3 halting
++		pm_rsts = readl(__io_address(PM_RSTS));
++		pm_rsts = PM_PASSWORD | pm_rsts | PM_RSTS_HADWRH_SET;
++	}
++	else
++	{
++		pm_rsts = calc_rsts(reboot_part);
++	}
++
++	writel(pm_rsts, __io_address(PM_RSTS));
++
++	/* Setup watchdog for reset */
++	pm_rstc = readl(__io_address(PM_RSTC));
++
++	pm_wdog = PM_PASSWORD | (timeout & PM_WDOG_TIME_SET); // watchdog timer = timer clock / 16; need password (31:16) + value (11:0)
++	pm_rstc = PM_PASSWORD | (pm_rstc & PM_RSTC_WRCFG_CLR) | PM_RSTC_WRCFG_FULL_RESET;
++
++	writel(pm_wdog, __io_address(PM_WDOG));
++	writel(pm_rstc, __io_address(PM_RSTC));
++}
++
++/* We can't really power off, but if we do the normal reset scheme, and indicate to bootcode.bin not to reboot, then most of the chip will be powered off */
++static void bcm2709_power_off(void)
++{
++	extern char bcm2708_reboot_mode;
++	if(bcm2708_reboot_mode == 'q')
++	{
++		// NOOBS < v1.3
++		bcm2709_restart('p', "");
++	}
++	else
++	{
++		/* partition 63 is special code for HALT the bootloader knows not to boot*/
++		reboot_part = 63;
++		/* continue with normal reset mechanism */
++		bcm2709_restart(0, "");
++	}
++}
++
++static void __init bcm2709_init_uart1(void)
++{
++	struct device_node *np;
++
++	np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
++	if (of_device_is_available(np)) {
++		pr_info("bcm2709: Mini UART enabled\n");
++		writel(1, __io_address(UART1_BASE + 0x4));
++	}
++}
++
++void __init bcm2709_init(void)
++{
++	int ret;
++
++	vc_cma_early_init();
++
++	pm_power_off = bcm2709_power_off;
++
++	ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
++				   NULL);
++	if (ret) {
++		pr_err("of_platform_populate failed: %d\n", ret);
++		BUG();
++	}
++
++	bcm2709_init_uart1();
++
++	system_rev = boardrev;
++	system_serial_low = serial;
++}
++
++static void __init bcm2709_timer_init(void)
++{
++	// timer control
++	writel(0, __io_address(ARM_LOCAL_CONTROL));
++	// timer pre_scaler
++	writel(0x80000000, __io_address(ARM_LOCAL_PRESCALER)); // 19.2MHz
++	//writel(0x06AAAAAB, __io_address(ARM_LOCAL_PRESCALER)); // 1MHz
++
++	of_clk_init(NULL);
++	clocksource_probe();
++}
++
++
++void __init bcm2709_init_early(void)
++{
++	/*
++	 * Some devices allocate their coherent buffers from atomic
++	 * context. Increase size of atomic coherent pool to make sure such
++	 * the allocations won't fail.
++	 */
++	init_dma_coherent_pool_size(SZ_4M);
++}
++
++static void __init board_reserve(void)
++{
++	vc_cma_reserve();
++}
++
++
++#ifdef CONFIG_SMP
++#include <linux/smp.h>
++
++#include <asm/cacheflush.h>
++#include <asm/smp_plat.h>
++int dc4=0;
++//void dc4_log(unsigned x) { if (dc4) writel((x), __io_address(ST_BASE+10 + raw_smp_processor_id()*4)); }
++void dc4_log_dead(unsigned x) { if (dc4) writel((readl(__io_address(ST_BASE+0x10 + raw_smp_processor_id()*4)) & 0xffff) | ((x)<<16), __io_address(ST_BASE+0x10 + raw_smp_processor_id()*4)); }
++
++static void bcm2835_send_doorbell(const struct cpumask *mask, unsigned int irq)
++{
++        int cpu;
++        /*
++         * Ensure that stores to Normal memory are visible to the
++         * other CPUs before issuing the IPI.
++         */
++        dsb();
++
++        /* Convert our logical CPU mask into a physical one. */
++        for_each_cpu(cpu, mask)
++	{
++		/* submit softirq */
++		writel(1<<irq, __io_address(ARM_LOCAL_MAILBOX0_SET0 + 0x10 * MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0)));
++	}
++}
++
++void __init bcm2709_smp_init_cpus(void)
++{
++	void secondary_startup(void);
++	unsigned int i, ncores;
++
++	ncores = 4; // xxx scu_get_core_count(NULL);
++	printk("[%s] enter (%x->%x)\n", __FUNCTION__, (unsigned)virt_to_phys((void *)secondary_startup), (unsigned)__io_address(ST_BASE + 0x10));
++	printk("[%s] ncores=%d\n", __FUNCTION__, ncores);
++
++	for (i = 0; i < ncores; i++) {
++		set_cpu_possible(i, true);
++		/* enable IRQ (not FIQ) */
++		writel(0x1, __io_address(ARM_LOCAL_MAILBOX_INT_CONTROL0 + 0x4 * i));
++		//writel(0xf, __io_address(ARM_LOCAL_TIMER_INT_CONTROL0   + 0x4 * i));
++	}
++	set_smp_cross_call(bcm2835_send_doorbell);
++}
++
++/*
++ * for arch/arm/kernel/smp.c:smp_prepare_cpus(unsigned int max_cpus)
++ */
++void __init bcm2709_smp_prepare_cpus(unsigned int max_cpus)
++{
++    //void __iomem *scu_base;
++
++    printk("[%s] enter\n", __FUNCTION__);
++    //scu_base = scu_base_addr();
++    //scu_enable(scu_base);
++}
++
++/*
++ * for linux/arch/arm/kernel/smp.c:secondary_start_kernel(void)
++ */
++void __init bcm2709_secondary_init(unsigned int cpu)
++{
++    printk("[%s] enter cpu:%d\n", __FUNCTION__, cpu);
++    //gic_secondary_init(0);
++}
++
++/*
++ * for linux/arch/arm/kernel/smp.c:__cpu_up(..)
++ */
++int __init bcm2709_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++    void secondary_startup(void);
++    void *mbox_set = __io_address(ARM_LOCAL_MAILBOX3_SET0 + 0x10 * MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0));
++    void *mbox_clr = __io_address(ARM_LOCAL_MAILBOX3_CLR0 + 0x10 * MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0));
++    unsigned secondary_boot = (unsigned)virt_to_phys((void *)secondary_startup);
++    int timeout=20;
++    unsigned t = -1;
++    //printk("[%s] enter cpu:%d (%x->%p) %x\n", __FUNCTION__, cpu, secondary_boot, wake, readl(wake));
++
++    dsb();
++    BUG_ON(readl(mbox_clr) != 0);
++    writel(secondary_boot, mbox_set);
++
++    while (--timeout > 0) {
++	t = readl(mbox_clr);
++	if (t == 0) break;
++	cpu_relax();
++    }
++    if (timeout==0)
++        printk("[%s] cpu:%d failed to start (%x)\n", __FUNCTION__, cpu, t);
++    else
++        printk("[%s] cpu:%d started (%x) %d\n", __FUNCTION__, cpu, t, timeout);
++
++    return 0;
++}
++
++
++struct smp_operations  bcm2709_smp_ops __initdata = {
++	.smp_init_cpus		= bcm2709_smp_init_cpus,
++	.smp_prepare_cpus	= bcm2709_smp_prepare_cpus,
++	.smp_secondary_init	= bcm2709_secondary_init,
++	.smp_boot_secondary	= bcm2709_boot_secondary,
++};
++#endif
++
++static const char * const bcm2709_compat[] = {
++	"brcm,bcm2709",
++	"brcm,bcm2708", /* Could use bcm2708 in a pinch */
++	NULL
++};
++
++MACHINE_START(BCM2709, "BCM2709")
++    /* Maintainer: Broadcom Europe Ltd. */
++#ifdef CONFIG_SMP
++	.smp		= smp_ops(bcm2709_smp_ops),
++#endif
++	.map_io = bcm2709_map_io,
++	.init_time = bcm2709_timer_init,
++	.init_machine = bcm2709_init,
++	.init_early = bcm2709_init_early,
++	.reserve = board_reserve,
++	.restart	= bcm2709_restart,
++	.dt_compat = bcm2709_compat,
++MACHINE_END
++
++MACHINE_START(BCM2708, "BCM2709")
++    /* Maintainer: Broadcom Europe Ltd. */
++#ifdef CONFIG_SMP
++	.smp		= smp_ops(bcm2709_smp_ops),
++#endif
++	.map_io = bcm2709_map_io,
++	.init_time = bcm2709_timer_init,
++	.init_machine = bcm2709_init,
++	.init_early = bcm2709_init_early,
++	.reserve = board_reserve,
++	.restart	= bcm2709_restart,
++	.dt_compat = bcm2709_compat,
++MACHINE_END
++
++module_param(boardrev, uint, 0644);
++module_param(serial, uint, 0644);
++module_param(reboot_part, uint, 0644);
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/debug-macro.S
+@@ -0,0 +1,22 @@
++/* arch/arm/mach-bcm2708/include/mach/debug-macro.S
++ *
++ * Debugging macro include header
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 1994-1999 Russell King
++ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++*/
++
++#include <mach/platform.h>
++
++		.macro	addruart, rp, rv, tmp
++		ldr	\rp, =UART0_BASE
++		ldr	\rv, =IO_ADDRESS(UART0_BASE)
++		.endm
++
++#include <debug/pl01x.S>
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/entry-macro.S
+@@ -0,0 +1,123 @@
++/*
++ * arch/arm/mach-bcm2708/include/mach/entry-macro.S
++ *
++ * Low-level IRQ helper macros for BCM2708 platforms
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <mach/hardware.h>
++#include <mach/irqs.h>
++
++		.macro	disable_fiq
++		.endm
++
++		.macro  get_irqnr_preamble, base, tmp
++		ldr	\base, =IO_ADDRESS(ARMCTRL_IC_BASE)
++		.endm
++
++		.macro  arch_ret_to_user, tmp1, tmp2
++		.endm
++
++		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++		/* get core number */
++		mrc     p15, 0, \tmp, c0, c0, 5
++		ubfx    \tmp, \tmp, #0, #2
++
++		/* get core's local interrupt controller */
++		ldr	\irqstat, = __io_address(ARM_LOCAL_IRQ_PENDING0)	@ local interrupt source
++		add	\irqstat, \irqstat, \tmp, lsl #2
++		ldr	\tmp, [\irqstat]
++		/* ignore gpu interrupt */
++		bic     \tmp, #0x100
++		/* ignore mailbox interrupts */
++		bics    \tmp, #0xf0
++		beq	1005f
++
++		@ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
++		@ N.B. CLZ is an ARM5 instruction.
++		mov	\irqnr, #(ARM_IRQ_LOCAL_BASE + 31)
++		sub	\irqstat, \tmp, #1
++		eor	\irqstat, \irqstat, \tmp
++		clz	\tmp, \irqstat
++		sub	\irqnr, \tmp
++		b	1020f
++1005:
++		/* get core number */
++		mrc     p15, 0, \tmp, c0, c0, 5
++		ubfx    \tmp, \tmp, #0, #2
++
++                cmp	\tmp, #1
++		beq	1020f
++                cmp	\tmp, #2
++		beq	1020f
++                cmp	\tmp, #3
++		beq	1020f
++
++		/* get masked status */
++		ldr	\irqstat, [\base, #(ARM_IRQ_PEND0 - ARMCTRL_IC_BASE)]
++		mov	\irqnr, #(ARM_IRQ0_BASE + 31)
++		and	\tmp, \irqstat, #0x300		 @ save bits 8 and 9
++		/* clear bits 8 and 9, and test */
++		bics	\irqstat, \irqstat, #0x300
++		bne	1010f
++
++		tst	\tmp, #0x100
++		ldrne	\irqstat, [\base, #(ARM_IRQ_PEND1 - ARMCTRL_IC_BASE)]
++		movne \irqnr, #(ARM_IRQ1_BASE + 31)
++		@ Mask out the interrupts also present in PEND0 - see SW-5809
++		bicne \irqstat, #((1<<7) | (1<<9) | (1<<10))
++		bicne \irqstat, #((1<<18) | (1<<19))
++		bne	1010f
++
++		tst	\tmp, #0x200
++		ldrne \irqstat, [\base, #(ARM_IRQ_PEND2 - ARMCTRL_IC_BASE)]
++		movne \irqnr, #(ARM_IRQ2_BASE + 31)
++		@ Mask out the interrupts also present in PEND0 - see SW-5809
++		bicne \irqstat, #((1<<21) | (1<<22) | (1<<23) | (1<<24) | (1<<25))
++		bicne \irqstat, #((1<<30))
++		beq 1020f
++
++1010:
++		@ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
++		@ N.B. CLZ is an ARM5 instruction.
++		sub	\tmp, \irqstat, #1
++		eor	\irqstat, \irqstat, \tmp
++		clz	\tmp, \irqstat
++		sub	\irqnr, \tmp
++
++1020:	@ EQ will be set if no irqs pending
++
++		.endm
++
++		.macro  test_for_ipi, irqnr, irqstat, base, tmp
++		/* get core number */
++		mrc     p15, 0, \tmp, c0, c0, 5
++		ubfx    \tmp, \tmp, #0, #2
++		/* get core's mailbox interrupt control */
++		ldr	\irqstat, = __io_address(ARM_LOCAL_MAILBOX0_CLR0)	@ mbox_clr
++		add	\irqstat, \irqstat, \tmp, lsl #4
++		ldr	\tmp, [\irqstat]
++		cmp     \tmp, #0
++		beq	1030f
++		clz	\tmp, \tmp
++		rsb	\irqnr, \tmp, #31
++		mov	\tmp, #1
++		lsl	\tmp, \irqnr
++		str	\tmp, [\irqstat]  @ clear interrupt source
++		dsb
++1030:	@ EQ will be set if no irqs pending
++		.endm
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/io.h
+@@ -0,0 +1,27 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/io.h
++ *
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++#define __io(a)		__typesafe_io(a)
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/memory.h
+@@ -0,0 +1,57 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/memory.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++/* Memory overview:
++
++   [ARMcore] <--virtual addr-->
++   [ARMmmu] <--physical addr-->
++   [GERTmap] <--bus add-->
++   [VCperiph]
++
++*/
++
++/*
++ * Physical DRAM offset.
++ */
++#define BCM_PLAT_PHYS_OFFSET	UL(0x00000000)
++#define VC_ARMMEM_OFFSET	UL(0x00000000)   /* offset in VC of ARM memory */
++
++#ifdef CONFIG_BCM2708_NOL2CACHE
++ #define _REAL_BUS_OFFSET UL(0xC0000000)   /* don't use L1 or L2 caches */
++#else
++ #define _REAL_BUS_OFFSET UL(0x40000000)   /* use L2 cache */
++#endif
++
++/* We're using the memory at 64M in the VideoCore for Linux - this adjustment
++ * will provide the offset into this area as well as setting the bits that
++ * stop the L1 and L2 cache from being used
++ *
++ * WARNING: this only works because the ARM is given memory at a fixed location
++ *          (ARMMEM_OFFSET)
++ */
++#define BUS_OFFSET          (VC_ARMMEM_OFFSET + _REAL_BUS_OFFSET)
++#define __virt_to_bus(x)    ((x) + (BUS_OFFSET - PAGE_OFFSET))
++#define __bus_to_virt(x)    ((x) - (BUS_OFFSET - PAGE_OFFSET))
++#define __pfn_to_bus(x)     (__pfn_to_phys(x) + (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++#define __bus_to_pfn(x)     __phys_to_pfn((x) - (BUS_OFFSET - BCM_PLAT_PHYS_OFFSET))
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/platform.h
+@@ -0,0 +1,188 @@
++/*
++ * arch/arm/mach-bcm2708/include/mach/platform.h
++ *
++ * Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _BCM2708_PLATFORM_H
++#define _BCM2708_PLATFORM_H
++
++
++/* macros to get at IO space when running virtually */
++#define IO_ADDRESS(x)	(((x) & 0x00ffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
++
++#define __io_address(n)     IOMEM(IO_ADDRESS(n))
++
++
++/*
++ *  SDRAM
++ */
++#define BCM2708_SDRAM_BASE           0x00000000
++
++/*
++ *  Logic expansion modules
++ *
++ */
++
++
++/* ------------------------------------------------------------------------
++ *  BCM2708 ARMCTRL Registers
++ * ------------------------------------------------------------------------
++ */
++
++#define HW_REGISTER_RW(addr) (addr)
++#define HW_REGISTER_RO(addr) (addr)
++
++/*
++ * Definitions and addresses for the ARM CONTROL logic
++ * This file is manually generated.
++ */
++
++#define BCM2708_PERI_BASE        0x3F000000
++#define IC0_BASE                 (BCM2708_PERI_BASE + 0x2000)
++#define ST_BASE                  (BCM2708_PERI_BASE + 0x3000)   /* System Timer */
++#define MPHI_BASE		 (BCM2708_PERI_BASE + 0x6000)	/* Message -based Parallel Host Interface */
++#define DMA_BASE		 (BCM2708_PERI_BASE + 0x7000)	/* DMA controller */
++#define ARM_BASE                 (BCM2708_PERI_BASE + 0xB000)	 /* BCM2708 ARM control block */
++#define PM_BASE			 (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
++#define PCM_CLOCK_BASE           (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */
++#define RNG_BASE                 (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
++#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO */
++#define UART0_BASE               (BCM2708_PERI_BASE + 0x201000)	/* Uart 0 */
++#define MMCI0_BASE               (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
++#define I2S_BASE                 (BCM2708_PERI_BASE + 0x203000) /* I2S */
++#define SPI0_BASE		 (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
++#define BSC0_BASE		 (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
++#define UART1_BASE               (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
++#define EMMC_BASE                (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
++#define SMI_BASE		 (BCM2708_PERI_BASE + 0x600000) /* SMI */
++#define BSC1_BASE		 (BCM2708_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */
++#define USB_BASE                 (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
++#define MCORE_BASE               (BCM2708_PERI_BASE + 0x0000)   /* Fake frame buffer device (actually the multicore sync block*/
++
++#define ARMCTRL_BASE             (ARM_BASE + 0x000)
++#define ARMCTRL_IC_BASE          (ARM_BASE + 0x200)           /* ARM interrupt controller */
++#define ARMCTRL_TIMER0_1_BASE    (ARM_BASE + 0x400)           /* Timer 0 and 1 */
++#define ARMCTRL_0_SBM_BASE       (ARM_BASE + 0x800)           /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
++
++/*
++ * Watchdog
++ */
++#define PM_RSTC			       (PM_BASE+0x1c)
++#define PM_RSTS			       (PM_BASE+0x20)
++#define PM_WDOG			       (PM_BASE+0x24)
++
++#define PM_WDOG_RESET                                         0000000000
++#define PM_PASSWORD		       0x5a000000
++#define PM_WDOG_TIME_SET	       0x000fffff
++#define PM_RSTC_WRCFG_CLR              0xffffffcf
++#define PM_RSTC_WRCFG_SET              0x00000030
++#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
++#define PM_RSTC_RESET                  0x00000102
++
++#define PM_RSTS_HADPOR_SET                                 0x00001000
++#define PM_RSTS_HADSRH_SET                                 0x00000400
++#define PM_RSTS_HADSRF_SET                                 0x00000200
++#define PM_RSTS_HADSRQ_SET                                 0x00000100
++#define PM_RSTS_HADWRH_SET                                 0x00000040
++#define PM_RSTS_HADWRF_SET                                 0x00000020
++#define PM_RSTS_HADWRQ_SET                                 0x00000010
++#define PM_RSTS_HADDRH_SET                                 0x00000004
++#define PM_RSTS_HADDRF_SET                                 0x00000002
++#define PM_RSTS_HADDRQ_SET                                 0x00000001
++
++#define UART0_CLOCK      3000000
++
++#define ARM_LOCAL_BASE 0x40000000
++#define ARM_LOCAL_CONTROL		HW_REGISTER_RW(ARM_LOCAL_BASE+0x000)
++
++#define ARM_LOCAL_CONTROL		HW_REGISTER_RW(ARM_LOCAL_BASE+0x000)
++#define ARM_LOCAL_PRESCALER		HW_REGISTER_RW(ARM_LOCAL_BASE+0x008)
++#define ARM_LOCAL_GPU_INT_ROUTING	HW_REGISTER_RW(ARM_LOCAL_BASE+0x00C)
++#define ARM_LOCAL_PM_ROUTING_SET	HW_REGISTER_RW(ARM_LOCAL_BASE+0x010)
++#define ARM_LOCAL_PM_ROUTING_CLR	HW_REGISTER_RW(ARM_LOCAL_BASE+0x014)
++#define ARM_LOCAL_TIMER_LS		HW_REGISTER_RW(ARM_LOCAL_BASE+0x01C)
++#define ARM_LOCAL_TIMER_MS		HW_REGISTER_RW(ARM_LOCAL_BASE+0x020)
++#define ARM_LOCAL_INT_ROUTING		HW_REGISTER_RW(ARM_LOCAL_BASE+0x024)
++#define ARM_LOCAL_AXI_COUNT		HW_REGISTER_RW(ARM_LOCAL_BASE+0x02C)
++#define ARM_LOCAL_AXI_IRQ		HW_REGISTER_RW(ARM_LOCAL_BASE+0x030)
++#define ARM_LOCAL_TIMER_CONTROL		HW_REGISTER_RW(ARM_LOCAL_BASE+0x034)
++#define ARM_LOCAL_TIMER_WRITE		HW_REGISTER_RW(ARM_LOCAL_BASE+0x038)
++
++#define ARM_LOCAL_TIMER_INT_CONTROL0	HW_REGISTER_RW(ARM_LOCAL_BASE+0x040)
++#define ARM_LOCAL_TIMER_INT_CONTROL1	HW_REGISTER_RW(ARM_LOCAL_BASE+0x044)
++#define ARM_LOCAL_TIMER_INT_CONTROL2	HW_REGISTER_RW(ARM_LOCAL_BASE+0x048)
++#define ARM_LOCAL_TIMER_INT_CONTROL3	HW_REGISTER_RW(ARM_LOCAL_BASE+0x04C)
++
++#define ARM_LOCAL_MAILBOX_INT_CONTROL0	HW_REGISTER_RW(ARM_LOCAL_BASE+0x050)
++#define ARM_LOCAL_MAILBOX_INT_CONTROL1	HW_REGISTER_RW(ARM_LOCAL_BASE+0x054)
++#define ARM_LOCAL_MAILBOX_INT_CONTROL2	HW_REGISTER_RW(ARM_LOCAL_BASE+0x058)
++#define ARM_LOCAL_MAILBOX_INT_CONTROL3	HW_REGISTER_RW(ARM_LOCAL_BASE+0x05C)
++
++#define ARM_LOCAL_IRQ_PENDING0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x060)
++#define ARM_LOCAL_IRQ_PENDING1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x064)
++#define ARM_LOCAL_IRQ_PENDING2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x068)
++#define ARM_LOCAL_IRQ_PENDING3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x06C)
++
++#define ARM_LOCAL_FIQ_PENDING0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x070)
++#define ARM_LOCAL_FIQ_PENDING1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x074)
++#define ARM_LOCAL_FIQ_PENDING2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x078)
++#define ARM_LOCAL_FIQ_PENDING3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x07C)
++
++#define ARM_LOCAL_MAILBOX0_SET0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x080)
++#define ARM_LOCAL_MAILBOX1_SET0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x084)
++#define ARM_LOCAL_MAILBOX2_SET0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x088)
++#define ARM_LOCAL_MAILBOX3_SET0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x08C)
++
++#define ARM_LOCAL_MAILBOX0_SET1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x090)
++#define ARM_LOCAL_MAILBOX1_SET1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x094)
++#define ARM_LOCAL_MAILBOX2_SET1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x098)
++#define ARM_LOCAL_MAILBOX3_SET1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x09C)
++
++#define ARM_LOCAL_MAILBOX0_SET2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0A0)
++#define ARM_LOCAL_MAILBOX1_SET2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0A4)
++#define ARM_LOCAL_MAILBOX2_SET2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0A8)
++#define ARM_LOCAL_MAILBOX3_SET2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0AC)
++
++#define ARM_LOCAL_MAILBOX0_SET3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0B0)
++#define ARM_LOCAL_MAILBOX1_SET3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0B4)
++#define ARM_LOCAL_MAILBOX2_SET3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0B8)
++#define ARM_LOCAL_MAILBOX3_SET3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0BC)
++
++#define ARM_LOCAL_MAILBOX0_CLR0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0C0)
++#define ARM_LOCAL_MAILBOX1_CLR0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0C4)
++#define ARM_LOCAL_MAILBOX2_CLR0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0C8)
++#define ARM_LOCAL_MAILBOX3_CLR0		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0CC)
++
++#define ARM_LOCAL_MAILBOX0_CLR1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0D0)
++#define ARM_LOCAL_MAILBOX1_CLR1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0D4)
++#define ARM_LOCAL_MAILBOX2_CLR1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0D8)
++#define ARM_LOCAL_MAILBOX3_CLR1		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0DC)
++
++#define ARM_LOCAL_MAILBOX0_CLR2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0E0)
++#define ARM_LOCAL_MAILBOX1_CLR2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0E4)
++#define ARM_LOCAL_MAILBOX2_CLR2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0E8)
++#define ARM_LOCAL_MAILBOX3_CLR2		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0EC)
++
++#define ARM_LOCAL_MAILBOX0_CLR3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0F0)
++#define ARM_LOCAL_MAILBOX1_CLR3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0F4)
++#define ARM_LOCAL_MAILBOX2_CLR3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0F8)
++#define ARM_LOCAL_MAILBOX3_CLR3		HW_REGISTER_RW(ARM_LOCAL_BASE+0x0FC)
++
++#endif
++
++/* END */
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/system.h
+@@ -0,0 +1,37 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/system.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <linux/io.h>
++#include <mach/platform.h>
++
++static inline void arch_idle(void)
++{
++	/*
++	 * This should do all the clock switching
++	 * and wait for interrupt tricks
++	 */
++	cpu_do_idle();
++}
++
++#endif
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/uncompress.h
+@@ -0,0 +1,84 @@
++/*
++ *  arch/arm/mach-bcn2708/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *  Copyright (C) 2003 ARM Limited
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/io.h>
++#include <linux/amba/serial.h>
++#include <mach/platform.h>
++
++#define UART_BAUD 115200
++
++#define BCM2708_UART_DR   __io(UART0_BASE + UART01x_DR)
++#define BCM2708_UART_FR   __io(UART0_BASE + UART01x_FR)
++#define BCM2708_UART_IBRD __io(UART0_BASE + UART011_IBRD)
++#define BCM2708_UART_FBRD __io(UART0_BASE + UART011_FBRD)
++#define BCM2708_UART_LCRH __io(UART0_BASE + UART011_LCRH)
++#define BCM2708_UART_CR   __io(UART0_BASE + UART011_CR)
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++	while (__raw_readl(BCM2708_UART_FR) & UART01x_FR_TXFF)
++		barrier();
++
++	__raw_writel(c, BCM2708_UART_DR);
++}
++
++static inline void flush(void)
++{
++	int fr;
++
++	do {
++		fr = __raw_readl(BCM2708_UART_FR);
++		barrier();
++	} while ((fr & (UART011_FR_TXFE | UART01x_FR_BUSY)) != UART011_FR_TXFE);
++}
++
++static inline void arch_decomp_setup(void)
++{
++	int temp, div, rem, frac;
++
++	temp = 16 * UART_BAUD;
++	div = UART0_CLOCK / temp;
++	rem = UART0_CLOCK % temp;
++	temp = (8 * rem) / UART_BAUD;
++	frac = (temp >> 1) + (temp & 1);
++
++	/* Make sure the UART is disabled before we start */
++	__raw_writel(0, BCM2708_UART_CR);
++
++	/* Set the baud rate */
++	__raw_writel(div, BCM2708_UART_IBRD);
++	__raw_writel(frac, BCM2708_UART_FBRD);
++
++	/* Set the UART to 8n1, FIFO enabled */
++	__raw_writel(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, BCM2708_UART_LCRH);
++
++	/* Enable the UART */
++	__raw_writel(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,
++			BCM2708_UART_CR);
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_wdog()
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/vc_mem.h
+@@ -0,0 +1,35 @@
++/*****************************************************************************
++* Copyright 2010 - 2011 Broadcom Corporation.  All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#if !defined( VC_MEM_H )
++#define VC_MEM_H
++
++#include <linux/ioctl.h>
++
++#define VC_MEM_IOC_MAGIC  'v'
++
++#define VC_MEM_IOC_MEM_PHYS_ADDR    _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
++#define VC_MEM_IOC_MEM_SIZE         _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
++#define VC_MEM_IOC_MEM_BASE         _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
++#define VC_MEM_IOC_MEM_LOAD         _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
++
++#if defined( __KERNEL__ )
++#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
++
++extern unsigned long mm_vc_mem_phys_addr;
++extern unsigned int  mm_vc_mem_size;
++extern int vc_mem_get_current_size( void );
++#endif
++
++#endif  /* VC_MEM_H */
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/include/mach/vmalloc.h
+@@ -0,0 +1,20 @@
++/*
++ *  arch/arm/mach-bcm2708/include/mach/vmalloc.h
++ *
++ *  Copyright (C) 2010 Broadcom
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#define VMALLOC_END		(0xff000000)
+--- /dev/null
++++ b/arch/arm/mach-bcm2709/vc_mem.c
+@@ -0,0 +1,431 @@
++/*****************************************************************************
++* Copyright 2010 - 2011 Broadcom Corporation.  All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/debugfs.h>
++#include <asm/uaccess.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_data/mailbox-bcm2708.h>
++
++#ifdef CONFIG_ARCH_KONA
++#include <chal/chal_ipc.h>
++#elif defined(CONFIG_ARCH_BCM2708) || defined(CONFIG_ARCH_BCM2709)
++#else
++#include <csp/chal_ipc.h>
++#endif
++
++#include "mach/vc_mem.h"
++
++#define DRIVER_NAME  "vc-mem"
++
++// Device (/dev) related variables
++static dev_t vc_mem_devnum = 0;
++static struct class *vc_mem_class = NULL;
++static struct cdev vc_mem_cdev;
++static int vc_mem_inited = 0;
++
++#ifdef CONFIG_DEBUG_FS
++static struct dentry *vc_mem_debugfs_entry;
++#endif
++
++/*
++ * Videocore memory addresses and size
++ *
++ * Drivers that wish to know the videocore memory addresses and sizes should
++ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
++ * headers. This allows the other drivers to not be tied down to a a certain
++ * address/size at compile time.
++ *
++ * In the future, the goal is to have the videocore memory virtual address and
++ * size be calculated at boot time rather than at compile time. The decision of
++ * where the videocore memory resides and its size would be in the hands of the
++ * bootloader (and/or kernel). When that happens, the values of these variables
++ * would be calculated and assigned in the init function.
++ */
++// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
++unsigned long mm_vc_mem_phys_addr = 0x00000000;
++unsigned int mm_vc_mem_size = 0;
++unsigned int mm_vc_mem_base = 0;
++
++EXPORT_SYMBOL(mm_vc_mem_phys_addr);
++EXPORT_SYMBOL(mm_vc_mem_size);
++EXPORT_SYMBOL(mm_vc_mem_base);
++
++static uint phys_addr = 0;
++static uint mem_size = 0;
++static uint mem_base = 0;
++
++
++/****************************************************************************
++*
++*   vc_mem_open
++*
++***************************************************************************/
++
++static int
++vc_mem_open(struct inode *inode, struct file *file)
++{
++	(void) inode;
++	(void) file;
++
++	pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++	return 0;
++}
++
++/****************************************************************************
++*
++*   vc_mem_release
++*
++***************************************************************************/
++
++static int
++vc_mem_release(struct inode *inode, struct file *file)
++{
++	(void) inode;
++	(void) file;
++
++	pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++	return 0;
++}
++
++/****************************************************************************
++*
++*   vc_mem_get_size
++*
++***************************************************************************/
++
++static void
++vc_mem_get_size(void)
++{
++}
++
++/****************************************************************************
++*
++*   vc_mem_get_base
++*
++***************************************************************************/
++
++static void
++vc_mem_get_base(void)
++{
++}
++
++/****************************************************************************
++*
++*   vc_mem_get_current_size
++*
++***************************************************************************/
++
++int
++vc_mem_get_current_size(void)
++{
++	return mm_vc_mem_size;
++}
++
++EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
++
++/****************************************************************************
++*
++*   vc_mem_ioctl
++*
++***************************************************************************/
++
++static long
++vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++	int rc = 0;
++
++	(void) cmd;
++	(void) arg;
++
++	pr_debug("%s: called file = 0x%p\n", __func__, file);
++
++	switch (cmd) {
++	case VC_MEM_IOC_MEM_PHYS_ADDR:
++		{
++			pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
++				__func__, (void *) mm_vc_mem_phys_addr);
++
++			if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
++					 sizeof (mm_vc_mem_phys_addr)) != 0) {
++				rc = -EFAULT;
++			}
++			break;
++		}
++	case VC_MEM_IOC_MEM_SIZE:
++		{
++			// Get the videocore memory size first
++			vc_mem_get_size();
++
++			pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
++				mm_vc_mem_size);
++
++			if (copy_to_user((void *) arg, &mm_vc_mem_size,
++					 sizeof (mm_vc_mem_size)) != 0) {
++				rc = -EFAULT;
++			}
++			break;
++		}
++	case VC_MEM_IOC_MEM_BASE:
++		{
++			// Get the videocore memory base
++			vc_mem_get_base();
++
++			pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
++				mm_vc_mem_base);
++
++			if (copy_to_user((void *) arg, &mm_vc_mem_base,
++					 sizeof (mm_vc_mem_base)) != 0) {
++				rc = -EFAULT;
++			}
++			break;
++		}
++	case VC_MEM_IOC_MEM_LOAD:
++		{
++			// Get the videocore memory base
++			vc_mem_get_base();
++
++			pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
++				mm_vc_mem_base);
++
++			if (copy_to_user((void *) arg, &mm_vc_mem_base,
++					 sizeof (mm_vc_mem_base)) != 0) {
++				rc = -EFAULT;
++			}
++			break;
++		}
++	default:
++		{
++			return -ENOTTY;
++		}
++	}
++	pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
++
++	return rc;
++}
++
++/****************************************************************************
++*
++*   vc_mem_mmap
++*
++***************************************************************************/
++
++static int
++vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++	int rc = 0;
++	unsigned long length = vma->vm_end - vma->vm_start;
++	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++
++	pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
++		__func__, (long) vma->vm_start, (long) vma->vm_end,
++		(long) vma->vm_pgoff);
++
++	if (offset + length > mm_vc_mem_size) {
++		pr_err("%s: length %ld is too big\n", __func__, length);
++		return -EINVAL;
++	}
++	// Do not cache the memory map
++	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++	rc = remap_pfn_range(vma, vma->vm_start,
++			     (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
++			     vma->vm_pgoff, length, vma->vm_page_prot);
++	if (rc != 0) {
++		pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
++	}
++
++	return rc;
++}
++
++/****************************************************************************
++*
++*   File Operations for the driver.
++*
++***************************************************************************/
++
++static const struct file_operations vc_mem_fops = {
++	.owner = THIS_MODULE,
++	.open = vc_mem_open,
++	.release = vc_mem_release,
++	.unlocked_ioctl = vc_mem_ioctl,
++	.mmap = vc_mem_mmap,
++};
++
++#ifdef CONFIG_DEBUG_FS
++static void vc_mem_debugfs_deinit(void)
++{
++	debugfs_remove_recursive(vc_mem_debugfs_entry);
++	vc_mem_debugfs_entry = NULL;
++}
++
++
++static int vc_mem_debugfs_init(
++	struct device *dev)
++{
++	vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
++	if (!vc_mem_debugfs_entry) {
++		dev_warn(dev, "could not create debugfs entry\n");
++		return -EFAULT;
++	}
++
++	if (!debugfs_create_x32("vc_mem_phys_addr",
++				0444,
++				vc_mem_debugfs_entry,
++				(u32 *)&mm_vc_mem_phys_addr)) {
++		dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
++			__func__);
++		goto fail;
++	}
++
++	if (!debugfs_create_x32("vc_mem_size",
++				0444,
++				vc_mem_debugfs_entry,
++				(u32 *)&mm_vc_mem_size)) {
++		dev_warn(dev, "%s:could not create vc_mem_size entry\n",
++			__func__);
++		goto fail;
++	}
++
++	if (!debugfs_create_x32("vc_mem_base",
++				0444,
++				vc_mem_debugfs_entry,
++				(u32 *)&mm_vc_mem_base)) {
++		dev_warn(dev, "%s:could not create vc_mem_base entry\n",
++			 __func__);
++		goto fail;
++	}
++
++	return 0;
++
++fail:
++	vc_mem_debugfs_deinit();
++	return -EFAULT;
++}
++
++#endif /* CONFIG_DEBUG_FS */
++
++
++/****************************************************************************
++*
++*   vc_mem_init
++*
++***************************************************************************/
++
++static int __init
++vc_mem_init(void)
++{
++	int rc = -EFAULT;
++	struct device *dev;
++
++	pr_debug("%s: called\n", __func__);
++
++	mm_vc_mem_phys_addr = phys_addr;
++	mm_vc_mem_size = mem_size;
++	mm_vc_mem_base = mem_base;
++
++	vc_mem_get_size();
++
++	pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
++		mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
++
++	if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
++		pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
++		       __func__, rc);
++		goto out_err;
++	}
++
++	cdev_init(&vc_mem_cdev, &vc_mem_fops);
++	if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
++		pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
++		goto out_unregister;
++	}
++
++	vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
++	if (IS_ERR(vc_mem_class)) {
++		rc = PTR_ERR(vc_mem_class);
++		pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
++		goto out_cdev_del;
++	}
++
++	dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
++			    DRIVER_NAME);
++	if (IS_ERR(dev)) {
++		rc = PTR_ERR(dev);
++		pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
++		goto out_class_destroy;
++	}
++
++#ifdef CONFIG_DEBUG_FS
++	/* don't fail if the debug entries cannot be created */
++	vc_mem_debugfs_init(dev);
++#endif
++
++	vc_mem_inited = 1;
++	return 0;
++
++	device_destroy(vc_mem_class, vc_mem_devnum);
++
++      out_class_destroy:
++	class_destroy(vc_mem_class);
++	vc_mem_class = NULL;
++
++      out_cdev_del:
++	cdev_del(&vc_mem_cdev);
++
++      out_unregister:
++	unregister_chrdev_region(vc_mem_devnum, 1);
++
++      out_err:
++	return -1;
++}
++
++/****************************************************************************
++*
++*   vc_mem_exit
++*
++***************************************************************************/
++
++static void __exit
++vc_mem_exit(void)
++{
++	pr_debug("%s: called\n", __func__);
++
++	if (vc_mem_inited) {
++#if CONFIG_DEBUG_FS
++		vc_mem_debugfs_deinit();
++#endif
++		device_destroy(vc_mem_class, vc_mem_devnum);
++		class_destroy(vc_mem_class);
++		cdev_del(&vc_mem_cdev);
++		unregister_chrdev_region(vc_mem_devnum, 1);
++	}
++}
++
++module_init(vc_mem_init);
++module_exit(vc_mem_exit);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Broadcom Corporation");
++
++module_param(phys_addr, uint, 0644);
++module_param(mem_size, uint, 0644);
++module_param(mem_base, uint, 0644);
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -358,7 +358,7 @@ config CPU_PJ4B
+ 
+ # ARMv6
+ config CPU_V6
+-	bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
++	bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX || MACH_BCM2708)
+ 	select CPU_32v6
+ 	select CPU_ABRT_EV6
+ 	select CPU_CACHE_V6
+--- a/arch/arm/mm/proc-v6.S
++++ b/arch/arm/mm/proc-v6.S
+@@ -73,10 +73,19 @@ ENDPROC(cpu_v6_reset)
+  *
+  *	IRQs are already disabled.
+  */
++
++/* See jira SW-5991 for details of this workaround */
+ ENTRY(cpu_v6_do_idle)
+-	mov	r1, #0
+-	mcr	p15, 0, r1, c7, c10, 4		@ DWB - WFI may enter a low-power mode
+-	mcr	p15, 0, r1, c7, c0, 4		@ wait for interrupt
++	.align 5
++	mov     r1, #2
++1:	subs	r1, #1
++	nop
++	mcreq	p15, 0, r1, c7, c10, 4		@ DWB - WFI may enter a low-power mode
++	mcreq	p15, 0, r1, c7, c0, 4		@ wait for interrupt
++	nop
++	nop
++	nop
++	bne 1b
+ 	ret	lr
+ 
+ ENTRY(cpu_v6_dcache_clean_area)
+--- a/arch/arm/mm/proc-v7.S
++++ b/arch/arm/mm/proc-v7.S
+@@ -480,6 +480,7 @@ __errata_finish:
+ 	orr	r0, r0, r6			@ set them
+  THUMB(	orr	r0, r0, #1 << 30	)	@ Thumb exceptions
+ 	ret	lr				@ return to head.S:__ret
++        .space 256
+ ENDPROC(__v7_setup)
+ 
+ 	.align	2
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -522,6 +522,8 @@ torbreck		MACH_TORBRECK		TORBRECK		3090
+ prima2_evb		MACH_PRIMA2_EVB		PRIMA2_EVB		3103
+ paz00			MACH_PAZ00		PAZ00			3128
+ acmenetusfoxg20		MACH_ACMENETUSFOXG20	ACMENETUSFOXG20		3129
++bcm2708			MACH_BCM2708		BCM2708			3138
++bcm2709			MACH_BCM2709		BCM2709			3139
+ ag5evm			MACH_AG5EVM		AG5EVM			3189
+ ics_if_voip		MACH_ICS_IF_VOIP	ICS_IF_VOIP		3206
+ wlf_cragg_6410		MACH_WLF_CRAGG_6410	WLF_CRAGG_6410		3207
+--- a/drivers/clocksource/Makefile
++++ b/drivers/clocksource/Makefile
+@@ -19,7 +19,7 @@ obj-$(CONFIG_CLKSRC_NOMADIK_MTU)	+= noma
+ obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o
+ obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
+ obj-$(CONFIG_ORION_TIMER)	+= time-orion.o
+-obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
++obj-$(CONFIG_ARCH_BCM2835)$(CONFIG_ARCH_BCM2708)	+= bcm2835_timer.o
+ obj-$(CONFIG_ARCH_CLPS711X)	+= clps711x-timer.o
+ obj-$(CONFIG_ARCH_ATLAS7)	+= timer-atlas7.o
+ obj-$(CONFIG_ARCH_MOXART)	+= moxart_timer.o
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -2,6 +2,9 @@ obj-$(CONFIG_IRQCHIP)			+= irqchip.o
+ 
+ obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2835.o
+ obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2836.o
++obj-$(CONFIG_ARCH_BCM2708)		+= irq-bcm2835.o
++obj-$(CONFIG_ARCH_BCM2709)		+= irq-bcm2835.o
++obj-$(CONFIG_ARCH_BCM2709)		+= irq-bcm2836.o
+ obj-$(CONFIG_ARCH_EXYNOS)		+= exynos-combiner.o
+ obj-$(CONFIG_ARCH_HIP04)		+= irq-hip04.o
+ obj-$(CONFIG_ARCH_MMP)			+= irq-mmp.o
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -289,6 +289,7 @@ struct mmc_host {
+ #define MMC_CAP2_HSX00_1_2V	(MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
+ #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
+ #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
++#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 31)	/* Always use multiblock transfers */
+ 
+ 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
+ 
diff --git a/target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch b/target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch
new file mode 100644
index 0000000..53fc545
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0028-squash-include-ARCH_BCM2708-ARCH_BCM2709.patch
@@ -0,0 +1,138 @@
+From ceefa4e6b0d4b529eed6666120674cccde24d59a Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix at gmail.com>
+Date: Wed, 11 Nov 2015 21:01:15 +0000
+Subject: [PATCH 028/127] squash: include ARCH_BCM2708 / ARCH_BCM2709
+
+---
+ drivers/char/hw_random/Kconfig    |  2 +-
+ drivers/mailbox/Kconfig           |  2 +-
+ drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++--
+ drivers/pinctrl/Makefile          |  1 +
+ drivers/pwm/Kconfig               |  2 +-
+ drivers/spi/Kconfig               |  2 +-
+ drivers/watchdog/Kconfig          |  2 +-
+ sound/soc/bcm/Kconfig             |  2 +-
+ 8 files changed, 23 insertions(+), 8 deletions(-)
+
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -90,7 +90,7 @@ config HW_RANDOM_BCM63XX
+ 
+ config HW_RANDOM_BCM2835
+ 	tristate "Broadcom BCM2835 Random Number Generator support"
+-	depends on ARCH_BCM2835
++	depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ 	default HW_RANDOM
+ 	---help---
+ 	  This driver provides kernel-side support for the Random Number
+--- a/drivers/mailbox/Kconfig
++++ b/drivers/mailbox/Kconfig
+@@ -65,7 +65,7 @@ config ALTERA_MBOX
+ 
+ config BCM2835_MBOX
+ 	tristate "BCM2835 Mailbox"
+-	depends on ARCH_BCM2835
++	depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ 	help
+ 	  An implementation of the BCM2385 Mailbox.  It is used to invoke
+ 	  the services of the Videocore. Say Y here if you want to use the
+--- a/drivers/mailbox/bcm2835-mailbox.c
++++ b/drivers/mailbox/bcm2835-mailbox.c
+@@ -51,12 +51,15 @@
+ #define MAIL1_WRT	(ARM_0_MAIL1 + 0x00)
+ #define MAIL1_STA	(ARM_0_MAIL1 + 0x18)
+ 
++/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
++#ifndef ARM_MS_FULL
+ /* Status register: FIFO state. */
+ #define ARM_MS_FULL		BIT(31)
+ #define ARM_MS_EMPTY		BIT(30)
+ 
+ /* Configuration register: Enable interrupts. */
+ #define ARM_MC_IHAVEDATAIRQEN	BIT(0)
++#endif
+ 
+ struct bcm2835_mbox {
+ 	void __iomem *regs;
+@@ -151,7 +154,7 @@ static int bcm2835_mbox_probe(struct pla
+ 		return -ENOMEM;
+ 	spin_lock_init(&mbox->lock);
+ 
+-	ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
++	ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+ 			       bcm2835_mbox_irq, 0, dev_name(dev), mbox);
+ 	if (ret) {
+ 		dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
+@@ -209,7 +212,18 @@ static struct platform_driver bcm2835_mb
+ 	.probe		= bcm2835_mbox_probe,
+ 	.remove		= bcm2835_mbox_remove,
+ };
+-module_platform_driver(bcm2835_mbox_driver);
++
++static int __init bcm2835_mbox_init(void)
++{
++	return platform_driver_register(&bcm2835_mbox_driver);
++}
++arch_initcall(bcm2835_mbox_init);
++
++static void __init bcm2835_mbox_exit(void)
++{
++	platform_driver_unregister(&bcm2835_mbox_driver);
++}
++module_exit(bcm2835_mbox_exit);
+ 
+ MODULE_AUTHOR("Lubomir Rintel <lkundrak at v3.sk>");
+ MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -40,6 +40,7 @@ obj-$(CONFIG_PINCTRL_TB10X)	+= pinctrl-t
+ obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
+ obj-$(CONFIG_PINCTRL_ZYNQ)	+= pinctrl-zynq.o
+ 
++obj-$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += bcm/
+ obj-$(CONFIG_ARCH_BCM)		+= bcm/
+ obj-$(CONFIG_ARCH_BERLIN)	+= berlin/
+ obj-y				+= freescale/
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -85,7 +85,7 @@ config PWM_BCM_KONA
+ 
+ config PWM_BCM2835
+ 	tristate "BCM2835 PWM support"
+-	depends on ARCH_BCM2835
++	depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ 	help
+ 	  PWM framework driver for BCM2835 controller (Raspberry Pi)
+ 
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -78,7 +78,7 @@ config SPI_ATMEL
+ config SPI_BCM2835
+ 	tristate "BCM2835 SPI controller"
+ 	depends on GPIOLIB
+-	depends on ARCH_BCM2835 || COMPILE_TEST
++	depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST
+ 	depends on GPIOLIB
+ 	help
+ 	  This selects a driver for the Broadcom BCM2835 SPI master.
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -1291,7 +1291,7 @@ config BCM63XX_WDT
+ 
+ config BCM2835_WDT
+ 	tristate "Broadcom BCM2835 hardware watchdog"
+-	depends on ARCH_BCM2835
++	depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ 	select WATCHDOG_CORE
+ 	help
+ 	  Watchdog driver for the built in watchdog hardware in Broadcom
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -1,6 +1,6 @@
+ config SND_BCM2835_SOC_I2S
+ 	tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
+-	depends on ARCH_BCM2835 || COMPILE_TEST
++	depends on ARCH_BCM2835 || MACH_BCM2708 || MACH_BCM2709 || COMPILE_TEST
+ 	select SND_SOC_GENERIC_DMAENGINE_PCM
+ 	select REGMAP_MMIO
+ 	help
diff --git a/target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch b/target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch
new file mode 100644
index 0000000..ee8c4fa
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0029-Add-dwc_otg-driver.patch
@@ -0,0 +1,60780 @@
+From 3fa74ccc327ddeb8f718cf4c42d61b43cc0a9626 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix at gmail.com>
+Date: Wed, 1 May 2013 19:46:17 +0100
+Subject: [PATCH 029/127] Add dwc_otg driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix at gmail.com>
+
+usb: dwc: fix lockdep false positive
+
+Signed-off-by: Kari Suvanto <karis79 at gmail.com>
+
+usb: dwc: fix inconsistent lock state
+
+Signed-off-by: Kari Suvanto <karis79 at 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 at 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 at 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 at tronnes.org>
+
+dwc_otg: Remove duplicate gadget probe/unregister function
+---
+ 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                           |   13 +
+ drivers/usb/host/Makefile                          |    2 +
+ drivers/usb/host/dwc_common_port/Makefile          |   58 +
+ drivers/usb/host/dwc_common_port/Makefile.fbsd     |   17 +
+ drivers/usb/host/dwc_common_port/Makefile.linux    |   49 +
+ drivers/usb/host/dwc_common_port/changes.txt       |  174 +
+ drivers/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 +
+ drivers/usb/host/dwc_common_port/dwc_common_fbsd.c | 1308 ++++
+ .../usb/host/dwc_common_port/dwc_common_linux.c    | 1433 ++++
+ drivers/usb/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 +
+ drivers/usb/host/dwc_common_port/dwc_notifier.c    |  319 +
+ drivers/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             | 1575 +++++
+ 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            | 1210 ++++
+ 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             | 7141 ++++++++++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil.h             | 1464 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c        | 1594 +++++
+ 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          | 1757 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_driver.h          |   86 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c         | 1355 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h         |  370 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S        |   80 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c             | 4257 ++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.h             |  862 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c        | 1132 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h          |  417 ++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c        | 2714 ++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c       | 1005 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c       |  957 +++
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h          |  188 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.c             | 2712 ++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.h             |  266 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h          |  360 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c        | 5147 ++++++++++++++
+ 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 +
+ drivers/usb/host/dwc_otg/test/test_mod_param.pl    |  133 +
+ drivers/usb/host/dwc_otg/test/test_sysfs.pl        |  193 +
+ 70 files changed, 59867 insertions(+), 16 deletions(-)
+ create mode 100644 drivers/usb/gadget/file_storage.c
+ create mode 100644 drivers/usb/host/dwc_common_port/Makefile
+ create mode 100644 drivers/usb/host/dwc_common_port/Makefile.fbsd
+ create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux
+ create mode 100644 drivers/usb/host/dwc_common_port/changes.txt
+ create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h
+ create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h
+ create mode 100644 drivers/usb/host/dwc_common_port/usb.h
+ create mode 100644 drivers/usb/host/dwc_otg/Makefile
+ create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg
+ create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_adp.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c
+ create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h
+ create mode 100644 drivers/usb/host/dwc_otg/test/Makefile
+ create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm
+ create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl
+ create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl
+
+--- a/arch/arm/include/asm/irqflags.h
++++ b/arch/arm/include/asm/irqflags.h
+@@ -162,13 +162,23 @@ static inline unsigned long arch_local_s
+ }
+ 
+ /*
+- * 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");
+--- 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)
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -7,6 +7,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/
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -152,6 +152,7 @@ int usb_choose_configuration(struct usb_
+ 		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;
+ }
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -4946,7 +4946,7 @@ static void port_event(struct usb_hub *h
+ 	if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ 		u16 status = 0, unused;
+ 
+-		dev_dbg(&port_dev->dev, "over-current change\n");
++		dev_notice(&port_dev->dev, "over-current change\n");
+ 		usb_clear_port_feature(hdev, port1,
+ 				USB_PORT_FEAT_C_OVER_CURRENT);
+ 		msleep(100);	/* Cool down */
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -1909,6 +1909,85 @@ free_interfaces:
+ 	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);
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -19,33 +19,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	defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
+ /* 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;
+@@ -95,16 +144,57 @@ static int is_targeted(struct usb_device
+ 			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
+ 
+-	/* add other match criteria here ... */
++			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;
++		}
++	}
+ 
+-	/* 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));
++	/* add other match criteria here ... */
+ 
++	report_errors(dev);
+ 	return 0;
+ }
+ 
+--- /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);
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -735,6 +735,19 @@ config USB_HWA_HCD
+ 	  To compile this driver a module, choose M here: the module
+ 	  will be called "hwa-hc".
+ 
++config USB_DWCOTG
++	tristate "Synopsis DWC host support"
++	depends on USB
++	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.
++
++	  To compile this driver as a module, choose M here: the
++	  modules built will be called dwc_otg and dwc_common_port.
++
+ config USB_IMX21_HCD
+        tristate "i.MX21 HCD support"
+        depends on ARM && ARCH_MXC
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -69,6 +69,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_MPH_DR_OF)	+= fsl-mph-dr-of.o
+ obj-$(CONFIG_USB_EHCI_FSL)	+= ehci-fsl.o
+--- /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/
+--- /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>
+--- /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/
+--- /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.
+--- /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
+--- /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 */
+--- /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_ */
+--- /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;
++}
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
+@@ -0,0 +1,1433 @@
++#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)
++{
++#ifdef xxCOSIM /* Only works for 32-bit cosim */
++	void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL);
++#else
++	void *buf = dma_alloc_coherent(dma_ctx, (size_t)size, dma_addr, GFP_KERNEL | GFP_DMA32);
++#endif
++	if (!buf) {
++		return NULL;
++	}
++
++	memset(buf, 0, (size_t)size);
++	return buf;
++}
++
++void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++	void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC);
++	if (!buf) {
++		return NULL;
++	}
++	memset(buf, 0, (size_t)size);
++	return buf;
++}
++
++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(unsigned long data)
++{
++	dwc_timer_t *timer = (dwc_timer_t *)data;
++	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->t = DWC_ALLOC(sizeof(*t->t));
++	if (!t->t) {
++		DWC_ERROR("Cannot allocate memory for timer->t");
++		goto no_timer;
++	}
++
++	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;
++	setup_timer(t->t, timer_callback, (unsigned long)t);
++
++	t->cb = cb;
++	t->data = data;
++
++	return t;
++
++ no_lock:
++	DWC_FREE(t->name);
++ no_name:
++	DWC_FREE(t->t);
++ no_timer:
++	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->t);
++	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 */
+--- /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;
++}
+--- /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 */
+--- /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_ */
+--- /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 */
+--- /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_ */
+--- /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_ */
+--- /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 */
+--- /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 */
+--- /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 */
+--- /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 */
+--- /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__ */
+--- /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(_size_,_dma_) __DWC_DMA_ALLOC(NULL, _size_, _dma_)
++#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(NULL, _size_,_dma_)
++#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(NULL, _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(_size_,_dma_) dwc_dma_alloc_debug(NULL, _size_, \
++						_dma_, __func__, __LINE__)
++#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(NULL, _size_, \
++						_dma_, __func__, __LINE__)
++#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(NULL, _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_ */
+--- /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 at 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_ */
+--- /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
+--- /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
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dummy_audio.c
+@@ -0,0 +1,1575 @@
++/*
++ * 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 = kmalloc (sizeof *dev, SLAB_KERNEL);
++	if (!dev)
++		return -ENOMEM;
++	memset (dev, 0, sizeof *dev);
++	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);
+--- /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
+--- /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;
++}
+--- /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__
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
+@@ -0,0 +1,1210 @@
++/* ==========================================================================
++ * $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 at 0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
++				"Reg at 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)
++{
++        dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
++
++	//dwc_otg_dump_spram(otg_dev->core_if);
++
++	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
++}
+--- /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;
++extern struct device_attribute dev_attr_guid;
++extern struct device_attribute dev_attr_gsnpsid;
++extern struct device_attribute dev_attr_devspeed;
++extern struct device_attribute dev_attr_enumspeed;
++extern struct device_attribute dev_attr_hptxfsiz;
++extern struct device_attribute dev_attr_hprt0;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++extern struct device_attribute dev_attr_lpm_response;
++extern struct device_attribute devi_attr_sleep_status;
++#endif
++
++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
++    );
++
++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
++    );
++#endif
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c
+@@ -0,0 +1,1876 @@
++/* ==========================================================================
++ * 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
++ *
++ * This file contains the most of the CFI(Core Feature Interface)
++ * implementation for the OTG.
++ */
++
++#ifdef DWC_UTE_CFI
++
++#include "dwc_otg_pcd.h"
++#include "dwc_otg_cfi.h"
++
++/** This definition should actually migrate to the Portability Library */
++#define DWC_CONSTANT_CPU_TO_LE16(x) (x)
++
++extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
++
++static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
++static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
++				 struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *ctrl_req);
++static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
++static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req);
++static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *req);
++static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				struct cfi_usb_ctrlrequest *req);
++static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req);
++static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
++
++static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
++static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
++static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
++
++static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
++
++/** This is the header of the all features descriptor */
++static cfi_all_features_header_t all_props_desc_header = {
++	.wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
++	.wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
++	.wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
++};
++
++/** This is an array of statically allocated feature descriptors */
++static cfi_feature_desc_header_t prop_descs[] = {
++
++	/* FT_ID_DMA_MODE */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
++	 },
++
++	/* FT_ID_DMA_BUFFER_SETUP */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_DMA_BUFF_ALIGN */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 },
++
++	/* FT_ID_DMA_CONCAT_SETUP */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 //.wDataLength  = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_DMA_CIRCULAR */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_THRESHOLD_SETUP */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
++	 },
++
++	/* FT_ID_DFIFO_DEPTH */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
++	 .bmAttributes = CFI_FEATURE_ATTR_RO,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 },
++
++	/* FT_ID_TX_FIFO_DEPTH */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 },
++
++	/* FT_ID_RX_FIFO_DEPTH */
++	{
++	 .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
++	 .bmAttributes = CFI_FEATURE_ATTR_RW,
++	 .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
++	 }
++};
++
++/** The table of feature names */
++cfi_string_t prop_name_table[] = {
++	{FT_ID_DMA_MODE, "dma_mode"},
++	{FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
++	{FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
++	{FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
++	{FT_ID_DMA_CIRCULAR, "buffer_circular"},
++	{FT_ID_THRESHOLD_SETUP, "threshold_setup"},
++	{FT_ID_DFIFO_DEPTH, "dfifo_depth"},
++	{FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
++	{FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
++	{}
++};
++
++/************************************************************************/
++
++/**
++ * Returns the name of the feature by its ID
++ * or NULL if no featute ID matches.
++ *
++ */
++const uint8_t *get_prop_name(uint16_t prop_id, int *len)
++{
++	cfi_string_t *pstr;
++	*len = 0;
++
++	for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
++		if (pstr->id == prop_id) {
++			*len = DWC_STRLEN(pstr->s);
++			return pstr->s;
++		}
++	}
++	return NULL;
++}
++
++/**
++ * This function handles all CFI specific control requests.
++ *
++ * Return a negative value to stall the DCE.
++ */
++int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
++{
++	int retval = 0;
++	dwc_otg_pcd_ep_t *ep = NULL;
++	cfiobject_t *cfi = pcd->cfi;
++	struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
++	uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
++	uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
++	uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
++	uint32_t regaddr = 0;
++	uint32_t regval = 0;
++
++	/* Save this Control Request in the CFI object.
++	 * The data field will be assigned in the data stage completion CB function.
++	 */
++	cfi->ctrl_req = *ctrl;
++	cfi->ctrl_req.data = NULL;
++
++	cfi->need_gadget_att = 0;
++	cfi->need_status_in_complete = 0;
++
++	switch (ctrl->bRequest) {
++	case VEN_CORE_GET_FEATURES:
++		retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
++		if (retval >= 0) {
++			//dump_msg(cfi->buf_in.buf, retval);
++			ep = &pcd->ep0;
++
++			retval = min((uint16_t) retval, wLen);
++			/* Transfer this buffer to the host through the EP0-IN EP */
++			ep->dwc_ep.dma_addr = cfi->buf_in.addr;
++			ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_len = retval;
++			ep->dwc_ep.xfer_count = 0;
++			ep->dwc_ep.sent_zlp = 0;
++			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++			pcd->ep0_pending = 1;
++			dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		}
++		retval = 0;
++		break;
++
++	case VEN_CORE_GET_FEATURE:
++		CFI_INFO("VEN_CORE_GET_FEATURE\n");
++		retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
++					       pcd, ctrl);
++		if (retval >= 0) {
++			ep = &pcd->ep0;
++
++			retval = min((uint16_t) retval, wLen);
++			/* Transfer this buffer to the host through the EP0-IN EP */
++			ep->dwc_ep.dma_addr = cfi->buf_in.addr;
++			ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
++			ep->dwc_ep.xfer_len = retval;
++			ep->dwc_ep.xfer_count = 0;
++			ep->dwc_ep.sent_zlp = 0;
++			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++			pcd->ep0_pending = 1;
++			dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		}
++		CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
++		dump_msg(cfi->buf_in.buf, retval);
++		break;
++
++	case VEN_CORE_SET_FEATURE:
++		CFI_INFO("VEN_CORE_SET_FEATURE\n");
++		/* Set up an XFER to get the data stage of the control request,
++		 * which is the new value of the feature to be modified.
++		 */
++		ep = &pcd->ep0;
++		ep->dwc_ep.is_in = 0;
++		ep->dwc_ep.dma_addr = cfi->buf_out.addr;
++		ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_len = wLen;
++		ep->dwc_ep.xfer_count = 0;
++		ep->dwc_ep.sent_zlp = 0;
++		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++		pcd->ep0_pending = 1;
++		/* Read the control write's data stage */
++		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		retval = 0;
++		break;
++
++	case VEN_CORE_RESET_FEATURES:
++		CFI_INFO("VEN_CORE_RESET_FEATURES\n");
++		cfi->need_gadget_att = 1;
++		cfi->need_status_in_complete = 1;
++		retval = cfi_preproc_reset(pcd, ctrl);
++		CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
++		break;
++
++	case VEN_CORE_ACTIVATE_FEATURES:
++		CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
++		break;
++
++	case VEN_CORE_READ_REGISTER:
++		CFI_INFO("VEN_CORE_READ_REGISTER\n");
++		/* wValue optionally contains the HI WORD of the register offset and
++		 * wIndex contains the LOW WORD of the register offset
++		 */
++		if (wValue == 0) {
++			/* @TODO - MAS - fix the access to the base field */
++			regaddr = 0;
++			//regaddr = (uint32_t) pcd->otg_dev->os_dep.base;
++			//GET_CORE_IF(pcd)->co
++			regaddr |= wIndex;
++		} else {
++			regaddr = (wValue << 16) | wIndex;
++		}
++
++		/* Read a 32-bit value of the memory at the regaddr */
++		regval = DWC_READ_REG32((uint32_t *) regaddr);
++
++		ep = &pcd->ep0;
++		dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
++		ep->dwc_ep.is_in = 1;
++		ep->dwc_ep.dma_addr = cfi->buf_in.addr;
++		ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
++		ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
++		ep->dwc_ep.xfer_len = wLen;
++		ep->dwc_ep.xfer_count = 0;
++		ep->dwc_ep.sent_zlp = 0;
++		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++		pcd->ep0_pending = 1;
++		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		cfi->need_gadget_att = 0;
++		retval = 0;
++		break;
++
++	case VEN_CORE_WRITE_REGISTER:
++		CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
++		/* Set up an XFER to get the data stage of the control request,
++		 * which is the new value of the register to be modified.
++		 */
++		ep = &pcd->ep0;
++		ep->dwc_ep.is_in = 0;
++		ep->dwc_ep.dma_addr = cfi->buf_out.addr;
++		ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
++		ep->dwc_ep.xfer_len = wLen;
++		ep->dwc_ep.xfer_count = 0;
++		ep->dwc_ep.sent_zlp = 0;
++		ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
++
++		pcd->ep0_pending = 1;
++		/* Read the control write's data stage */
++		dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
++		retval = 0;
++		break;
++
++	default:
++		retval = -DWC_E_NOT_SUPPORTED;
++		break;
++	}
++
++	return retval;
++}
++
++/**
++ * This function prepares the core features descriptors and copies its
++ * raw representation into the buffer <buf>.
++ *
++ * The buffer structure is as follows:
++ *	all_features_header (8 bytes)
++ *	features_#1 (8 bytes + feature name string length)
++ *	features_#2 (8 bytes + feature name string length)
++ *	.....
++ *	features_#n - where n=the total count of feature descriptors
++ */
++static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
++{
++	cfi_feature_desc_header_t *prop_hdr = prop_descs;
++	cfi_feature_desc_header_t *prop;
++	cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
++	cfi_all_features_header_t *tmp;
++	uint8_t *tmpbuf = buf;
++	const uint8_t *pname = NULL;
++	int i, j, namelen = 0, totlen;
++
++	/* Prepare and copy the core features into the buffer */
++	CFI_INFO("%s:\n", __func__);
++
++	tmp = (cfi_all_features_header_t *) tmpbuf;
++	*tmp = *all_props_hdr;
++	tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
++
++	j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
++	for (i = 0; i < j; i++, prop_hdr++) {
++		pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
++		prop = (cfi_feature_desc_header_t *) tmpbuf;
++		*prop = *prop_hdr;
++
++		prop->bNameLen = namelen;
++		prop->wLength =
++		    DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
++					     namelen);
++
++		tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
++		dwc_memcpy(tmpbuf, pname, namelen);
++		tmpbuf += namelen;
++	}
++
++	totlen = tmpbuf - buf;
++
++	if (totlen > 0) {
++		tmp = (cfi_all_features_header_t *) buf;
++		tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
++	}
++
++	return totlen;
++}
++
++/**
++ * This function releases all the dynamic memory in the CFI object.
++ */
++static void cfi_release(cfiobject_t * cfiobj)
++{
++	cfi_ep_t *cfiep;
++	dwc_list_link_t *tmp;
++
++	CFI_INFO("%s\n", __func__);
++
++	if (cfiobj->buf_in.buf) {
++		DWC_DMA_FREE(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
++			     cfiobj->buf_in.addr);
++		cfiobj->buf_in.buf = NULL;
++	}
++
++	if (cfiobj->buf_out.buf) {
++		DWC_DMA_FREE(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
++			     cfiobj->buf_out.addr);
++		cfiobj->buf_out.buf = NULL;
++	}
++
++	/* Free the Buffer Setup values for each EP */
++	//list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
++	DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
++		cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++		cfi_free_ep_bs_dyn_data(cfiep);
++	}
++}
++
++/**
++ * This function frees the dynamically allocated EP buffer setup data.
++ */
++static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
++{
++	if (cfiep->bm_sg) {
++		DWC_FREE(cfiep->bm_sg);
++		cfiep->bm_sg = NULL;
++	}
++
++	if (cfiep->bm_align) {
++		DWC_FREE(cfiep->bm_align);
++		cfiep->bm_align = NULL;
++	}
++
++	if (cfiep->bm_concat) {
++		if (NULL != cfiep->bm_concat->wTxBytes) {
++			DWC_FREE(cfiep->bm_concat->wTxBytes);
++			cfiep->bm_concat->wTxBytes = NULL;
++		}
++		DWC_FREE(cfiep->bm_concat);
++		cfiep->bm_concat = NULL;
++	}
++}
++
++/**
++ * This function initializes the default values of the features
++ * for a specific endpoint and should be called only once when
++ * the EP is enabled first time.
++ */
++static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
++{
++	int retval = 0;
++
++	cfiep->bm_sg = DWC_ALLOC(sizeof(ddma_sg_buffer_setup_t));
++	if (NULL == cfiep->bm_sg) {
++		CFI_INFO("Failed to allocate memory for SG feature value\n");
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
++
++	/* For the Concatenation feature's default value we do not allocate
++	 * memory for the wTxBytes field - it will be done in the set_feature_value
++	 * request handler.
++	 */
++	cfiep->bm_concat = DWC_ALLOC(sizeof(ddma_concat_buffer_setup_t));
++	if (NULL == cfiep->bm_concat) {
++		CFI_INFO
++		    ("Failed to allocate memory for CONCATENATION feature value\n");
++		DWC_FREE(cfiep->bm_sg);
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
++
++	cfiep->bm_align = DWC_ALLOC(sizeof(ddma_align_buffer_setup_t));
++	if (NULL == cfiep->bm_align) {
++		CFI_INFO
++		    ("Failed to allocate memory for Alignment feature value\n");
++		DWC_FREE(cfiep->bm_sg);
++		DWC_FREE(cfiep->bm_concat);
++		return -DWC_E_NO_MEMORY;
++	}
++	dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
++
++	return retval;
++}
++
++/**
++ * The callback function that notifies the CFI on the activation of
++ * an endpoint in the PCD. The following steps are done in this function:
++ *
++ *	Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's
++ *		active endpoint)
++ *	Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP
++ *	Set the Buffer Mode to standard
++ *	Initialize the default values for all EP modes (SG, Circular, Concat, Align)
++ *	Add the cfi_ep_t object to the list of active endpoints in the CFI object
++ */
++static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
++			 struct dwc_otg_pcd_ep *ep)
++{
++	cfi_ep_t *cfiep;
++	int retval = -DWC_E_NOT_SUPPORTED;
++
++	CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
++		 "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
++	/* MAS - Check whether this endpoint already is in the list */
++	cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
++
++	if (NULL == cfiep) {
++		/* Allocate a cfi_ep_t object */
++		cfiep = DWC_ALLOC(sizeof(cfi_ep_t));
++		if (NULL == cfiep) {
++			CFI_INFO
++			    ("Unable to allocate memory for <cfiep> in function %s\n",
++			     __func__);
++			return -DWC_E_NO_MEMORY;
++		}
++		dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
++
++		/* Save the dwc_otg_pcd_ep pointer in the cfiep object */
++		cfiep->ep = ep;
++
++		/* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
++		ep->dwc_ep.descs =
++		    DWC_DMA_ALLOC(MAX_DMA_DESCS_PER_EP *
++				  sizeof(dwc_otg_dma_desc_t),
++				  &ep->dwc_ep.descs_dma_addr);
++
++		if (NULL == ep->dwc_ep.descs) {
++			DWC_FREE(cfiep);
++			return -DWC_E_NO_MEMORY;
++		}
++
++		DWC_LIST_INIT(&cfiep->lh);
++
++		/* Set the buffer mode to BM_STANDARD. It will be modified
++		 * when building descriptors for a specific buffer mode */
++		ep->dwc_ep.buff_mode = BM_STANDARD;
++
++		/* Create and initialize the default values for this EP's Buffer modes */
++		if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
++			return retval;
++
++		/* Add the cfi_ep_t object to the CFI object's list of active endpoints */
++		DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
++		retval = 0;
++	} else {		/* The sought EP already is in the list */
++		CFI_INFO("%s: The sought EP already is in the list\n",
++			 __func__);
++	}
++
++	return retval;
++}
++
++/**
++ * This function is called when the data stage of a 3-stage Control Write request
++ * is complete.
++ *
++ */
++static int cfi_ctrl_write_complete(struct cfiobject *cfi,
++				   struct dwc_otg_pcd *pcd)
++{
++	uint32_t addr, reg_value;
++	uint16_t wIndex, wValue;
++	uint8_t bRequest;
++	uint8_t *buf = cfi->buf_out.buf;
++	//struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
++	struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
++	int retval = -DWC_E_NOT_SUPPORTED;
++
++	CFI_INFO("%s\n", __func__);
++
++	bRequest = ctrl_req->bRequest;
++	wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
++	wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
++
++	/*
++	 * Save the pointer to the data stage in the ctrl_req's <data> field.
++	 * The request should be already saved in the command stage by now.
++	 */
++	ctrl_req->data = cfi->buf_out.buf;
++	cfi->need_status_in_complete = 0;
++	cfi->need_gadget_att = 0;
++
++	switch (bRequest) {
++	case VEN_CORE_WRITE_REGISTER:
++		/* The buffer contains raw data of the new value for the register */
++		reg_value = *((uint32_t *) buf);
++		if (wValue == 0) {
++			addr = 0;
++			//addr = (uint32_t) pcd->otg_dev->os_dep.base;
++			addr += wIndex;
++		} else {
++			addr = (wValue << 16) | wIndex;
++		}
++
++		//writel(reg_value, addr);
++
++		retval = 0;
++		cfi->need_status_in_complete = 1;
++		break;
++
++	case VEN_CORE_SET_FEATURE:
++		/* The buffer contains raw data of the new value of the feature */
++		retval = cfi_set_feature_value(pcd);
++		if (retval < 0)
++			return retval;
++
++		cfi->need_status_in_complete = 1;
++		break;
++
++	default:
++		break;
++	}
++
++	return retval;
++}
++
++/**
++ * This function builds the DMA descriptors for the SG buffer mode.
++ */
++static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++			       dwc_otg_pcd_request_t * req)
++{
++	struct dwc_otg_pcd_ep *ep = cfiep->ep;
++	ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
++	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
++	struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
++	dma_addr_t buff_addr = req->dma;
++	int i;
++	uint32_t txsize, off;
++
++	txsize = sgval->wSize;
++	off = sgval->bOffset;
++
++//      CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n",
++//              __func__, cfiep->ep->ep.name, txsize, off);
++
++	for (i = 0; i < sgval->bCount; i++) {
++		desc->status.b.bs = BS_HOST_BUSY;
++		desc->buf = buff_addr;
++		desc->status.b.l = 0;
++		desc->status.b.ioc = 0;
++		desc->status.b.sp = 0;
++		desc->status.b.bytes = txsize;
++		desc->status.b.bs = BS_HOST_READY;
++
++		/* Set the next address of the buffer */
++		buff_addr += txsize + off;
++		desc_last = desc;
++		desc++;
++	}
++
++	/* Set the last, ioc and sp bits on the Last DMA Descriptor */
++	desc_last->status.b.l = 1;
++	desc_last->status.b.ioc = 1;
++	desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
++	/* Save the last DMA descriptor pointer */
++	cfiep->dma_desc_last = desc_last;
++	cfiep->desc_count = sgval->bCount;
++}
++
++/**
++ * This function builds the DMA descriptors for the Concatenation buffer mode.
++ */
++static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++				   dwc_otg_pcd_request_t * req)
++{
++	struct dwc_otg_pcd_ep *ep = cfiep->ep;
++	ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
++	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
++	struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
++	dma_addr_t buff_addr = req->dma;
++	int i;
++	uint16_t *txsize;
++
++	txsize = concatval->wTxBytes;
++
++	for (i = 0; i < concatval->hdr.bDescCount; i++) {
++		desc->buf = buff_addr;
++		desc->status.b.bs = BS_HOST_BUSY;
++		desc->status.b.l = 0;
++		desc->status.b.ioc = 0;
++		desc->status.b.sp = 0;
++		desc->status.b.bytes = *txsize;
++		desc->status.b.bs = BS_HOST_READY;
++
++		txsize++;
++		/* Set the next address of the buffer */
++		buff_addr += UGETW(ep->desc->wMaxPacketSize);
++		desc_last = desc;
++		desc++;
++	}
++
++	/* Set the last, ioc and sp bits on the Last DMA Descriptor */
++	desc_last->status.b.l = 1;
++	desc_last->status.b.ioc = 1;
++	desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
++	cfiep->dma_desc_last = desc_last;
++	cfiep->desc_count = concatval->hdr.bDescCount;
++}
++
++/**
++ * This function builds the DMA descriptors for the Circular buffer mode
++ */
++static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++				 dwc_otg_pcd_request_t * req)
++{
++	/* @todo: MAS - add implementation when this feature needs to be tested */
++}
++
++/**
++ * This function builds the DMA descriptors for the Alignment buffer mode
++ */
++static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
++				  dwc_otg_pcd_request_t * req)
++{
++	struct dwc_otg_pcd_ep *ep = cfiep->ep;
++	ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
++	struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
++	dma_addr_t buff_addr = req->dma;
++
++	desc->status.b.bs = BS_HOST_BUSY;
++	desc->status.b.l = 1;
++	desc->status.b.ioc = 1;
++	desc->status.b.sp = ep->dwc_ep.sent_zlp;
++	desc->status.b.bytes = req->length;
++	/* Adjust the buffer alignment */
++	desc->buf = (buff_addr + alignval->bAlign);
++	desc->status.b.bs = BS_HOST_READY;
++	cfiep->dma_desc_last = desc;
++	cfiep->desc_count = 1;
++}
++
++/**
++ * This function builds the DMA descriptors chain for different modes of the
++ * buffer setup of an endpoint.
++ */
++static void cfi_build_descriptors(struct cfiobject *cfi,
++				  struct dwc_otg_pcd *pcd,
++				  struct dwc_otg_pcd_ep *ep,
++				  dwc_otg_pcd_request_t * req)
++{
++	cfi_ep_t *cfiep;
++
++	/* Get the cfiep by the dwc_otg_pcd_ep */
++	cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
++	if (NULL == cfiep) {
++		CFI_INFO("%s: Unable to find a matching active endpoint\n",
++			 __func__);
++		return;
++	}
++
++	cfiep->xfer_len = req->length;
++
++	/* Iterate through all the DMA descriptors */
++	switch (cfiep->ep->dwc_ep.buff_mode) {
++	case BM_SG:
++		cfi_build_sg_descs(cfi, cfiep, req);
++		break;
++
++	case BM_CONCAT:
++		cfi_build_concat_descs(cfi, cfiep, req);
++		break;
++
++	case BM_CIRCULAR:
++		cfi_build_circ_descs(cfi, cfiep, req);
++		break;
++
++	case BM_ALIGN:
++		cfi_build_align_descs(cfi, cfiep, req);
++		break;
++
++	default:
++		break;
++	}
++}
++
++/**
++ * Allocate DMA buffer for different Buffer modes.
++ */
++static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
++			      struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
++			      unsigned size, gfp_t flags)
++{
++	return DWC_DMA_ALLOC(size, dma);
++}
++
++/**
++ * This function initializes the CFI object.
++ */
++int init_cfi(cfiobject_t * cfiobj)
++{
++	CFI_INFO("%s\n", __func__);
++
++	/* Allocate a buffer for IN XFERs */
++	cfiobj->buf_in.buf =
++	    DWC_DMA_ALLOC(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
++	if (NULL == cfiobj->buf_in.buf) {
++		CFI_INFO("Unable to allocate buffer for INs\n");
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Allocate a buffer for OUT XFERs */
++	cfiobj->buf_out.buf =
++	    DWC_DMA_ALLOC(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
++	if (NULL == cfiobj->buf_out.buf) {
++		CFI_INFO("Unable to allocate buffer for OUT\n");
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Initialize the callback function pointers */
++	cfiobj->ops.release = cfi_release;
++	cfiobj->ops.ep_enable = cfi_ep_enable;
++	cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
++	cfiobj->ops.build_descriptors = cfi_build_descriptors;
++	cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
++
++	/* Initialize the list of active endpoints in the CFI object */
++	DWC_LIST_INIT(&cfiobj->active_eps);
++
++	return 0;
++}
++
++/**
++ * This function reads the required feature's current value into the buffer
++ *
++ * @retval: Returns negative as error, or the data length of the feature
++ */
++static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
++				 struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *ctrl_req)
++{
++	int retval = -DWC_E_NOT_SUPPORTED;
++	struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
++	uint16_t dfifo, rxfifo, txfifo;
++
++	switch (ctrl_req->wIndex) {
++		/* Whether the DDMA is enabled or not */
++	case FT_ID_DMA_MODE:
++		*buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
++		retval = 1;
++		break;
++
++	case FT_ID_DMA_BUFFER_SETUP:
++		retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
++		break;
++
++	case FT_ID_DMA_BUFF_ALIGN:
++		retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
++		break;
++
++	case FT_ID_DMA_CONCAT_SETUP:
++		retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
++		break;
++
++	case FT_ID_DMA_CIRCULAR:
++		CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
++		break;
++
++	case FT_ID_THRESHOLD_SETUP:
++		CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
++		break;
++
++	case FT_ID_DFIFO_DEPTH:
++		dfifo = get_dfifo_size(coreif);
++		*((uint16_t *) buf) = dfifo;
++		retval = sizeof(uint16_t);
++		break;
++
++	case FT_ID_TX_FIFO_DEPTH:
++		retval = get_txfifo_size(pcd, ctrl_req->wValue);
++		if (retval >= 0) {
++			txfifo = retval;
++			*((uint16_t *) buf) = txfifo;
++			retval = sizeof(uint16_t);
++		}
++		break;
++
++	case FT_ID_RX_FIFO_DEPTH:
++		retval = get_rxfifo_size(coreif, ctrl_req->wValue);
++		if (retval >= 0) {
++			rxfifo = retval;
++			*((uint16_t *) buf) = rxfifo;
++			retval = sizeof(uint16_t);
++		}
++		break;
++	}
++
++	return retval;
++}
++
++/**
++ * This function resets the SG for the specified EP to its default value
++ */
++static int cfi_reset_sg_val(cfi_ep_t * cfiep)
++{
++	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
++	return 0;
++}
++
++/**
++ * This function resets the Alignment for the specified EP to its default value
++ */
++static int cfi_reset_align_val(cfi_ep_t * cfiep)
++{
++	dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
++	return 0;
++}
++
++/**
++ * This function resets the Concatenation for the specified EP to its default value
++ * This function will also set the value of the wTxBytes field to NULL after
++ * freeing the memory previously allocated for this field.
++ */
++static int cfi_reset_concat_val(cfi_ep_t * cfiep)
++{
++	/* First we need to free the wTxBytes field */
++	if (cfiep->bm_concat->wTxBytes) {
++		DWC_FREE(cfiep->bm_concat->wTxBytes);
++		cfiep->bm_concat->wTxBytes = NULL;
++	}
++
++	dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
++	return 0;
++}
++
++/**
++ * This function resets all the buffer setups of the specified endpoint
++ */
++static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
++{
++	cfi_reset_sg_val(cfiep);
++	cfi_reset_align_val(cfiep);
++	cfi_reset_concat_val(cfiep);
++	return 0;
++}
++
++static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
++				     uint8_t rx_rst, uint8_t tx_rst)
++{
++	int retval = -DWC_E_INVALID;
++	uint16_t tx_siz[15];
++	uint16_t rx_siz = 0;
++	dwc_otg_pcd_ep_t *ep = NULL;
++	dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
++	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
++
++	if (rx_rst) {
++		rx_siz = params->dev_rx_fifo_size;
++		params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
++	}
++
++	if (tx_rst) {
++		if (ep_addr == 0) {
++			int i;
++
++			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++				tx_siz[i] =
++				    core_if->core_params->dev_tx_fifo_size[i];
++				core_if->core_params->dev_tx_fifo_size[i] =
++				    core_if->init_txfsiz[i];
++			}
++		} else {
++
++			ep = get_ep_by_addr(pcd, ep_addr);
++
++			if (NULL == ep) {
++				CFI_INFO
++				    ("%s: Unable to get the endpoint addr=0x%02x\n",
++				     __func__, ep_addr);
++				return -DWC_E_INVALID;
++			}
++
++			tx_siz[0] =
++			    params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
++						     1];
++			params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
++			    GET_CORE_IF(pcd)->init_txfsiz[ep->
++							  dwc_ep.tx_fifo_num -
++							  1];
++		}
++	}
++
++	if (resize_fifos(GET_CORE_IF(pcd))) {
++		retval = 0;
++	} else {
++		CFI_INFO
++		    ("%s: Error resetting the feature Reset All(FIFO size)\n",
++		     __func__);
++		if (rx_rst) {
++			params->dev_rx_fifo_size = rx_siz;
++		}
++
++		if (tx_rst) {
++			if (ep_addr == 0) {
++				int i;
++				for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
++				     i++) {
++					core_if->
++					    core_params->dev_tx_fifo_size[i] =
++					    tx_siz[i];
++				}
++			} else {
++				params->dev_tx_fifo_size[ep->
++							 dwc_ep.tx_fifo_num -
++							 1] = tx_siz[0];
++			}
++		}
++		retval = -DWC_E_INVALID;
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
++	if (retval < 0) {
++		return retval;
++	}
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_ep_reset_all_setup_vals(cfiep);
++		cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_ep_reset_all_setup_vals(cfiep);
++			cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Reset All\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
++					   uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_reset_sg_val(cfiep);
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_reset_sg_val(cfiep);
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Buffer Setup\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_reset_concat_val(cfiep);
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_reset_concat_val(cfiep);
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Concatenation Value\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++}
++
++static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
++{
++	int retval = 0;
++	cfi_ep_t *cfiep;
++	cfiobject_t *cfi = pcd->cfi;
++	dwc_list_link_t *tmp;
++
++	/* If the EP address is known then reset the features for only that EP */
++	if (addr) {
++		cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
++		if (NULL == cfiep) {
++			CFI_INFO("%s: Error getting the EP address 0x%02x\n",
++				 __func__, addr);
++			return -DWC_E_INVALID;
++		}
++		retval = cfi_reset_align_val(cfiep);
++	}
++	/* Otherwise (wValue == 0), reset all features of all EP's */
++	else {
++		/* Traverse all the active EP's and reset the feature(s) value(s) */
++		//list_for_each_entry(cfiep, &cfi->active_eps, lh) {
++		DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++			cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++			retval = cfi_reset_align_val(cfiep);
++			if (retval < 0) {
++				CFI_INFO
++				    ("%s: Error resetting the feature Aliignment Value\n",
++				     __func__);
++				return retval;
++			}
++		}
++	}
++	return retval;
++
++}
++
++static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req)
++{
++	int retval = 0;
++
++	switch (req->wIndex) {
++	case 0:
++		/* Reset all features */
++		retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_DMA_BUFFER_SETUP:
++		/* Reset the SG buffer setup */
++		retval =
++		    cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_DMA_CONCAT_SETUP:
++		/* Reset the Concatenation buffer setup */
++		retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_DMA_BUFF_ALIGN:
++		/* Reset the Alignment buffer setup */
++		retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
++		break;
++
++	case FT_ID_TX_FIFO_DEPTH:
++		retval =
++		    cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
++		pcd->cfi->need_gadget_att = 0;
++		break;
++
++	case FT_ID_RX_FIFO_DEPTH:
++		retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
++		pcd->cfi->need_gadget_att = 0;
++		break;
++	default:
++		break;
++	}
++	return retval;
++}
++
++/**
++ * This function sets a new value for the SG buffer setup.
++ */
++static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
++{
++	uint8_t inaddr, outaddr;
++	cfi_ep_t *epin, *epout;
++	ddma_sg_buffer_setup_t *psgval;
++	uint32_t desccount, size;
++
++	CFI_INFO("%s\n", __func__);
++
++	psgval = (ddma_sg_buffer_setup_t *) buf;
++	desccount = (uint32_t) psgval->bCount;
++	size = (uint32_t) psgval->wSize;
++
++	/* Check the DMA descriptor count */
++	if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
++		CFI_INFO
++		    ("%s: The count of DMA Descriptors should be between 1 and %d\n",
++		     __func__, MAX_DMA_DESCS_PER_EP);
++		return -DWC_E_INVALID;
++	}
++
++	/* Check the DMA descriptor count */
++
++	if (size == 0) {
++
++		CFI_INFO("%s: The transfer size should be at least 1 byte\n",
++			 __func__);
++
++		return -DWC_E_INVALID;
++
++	}
++
++	inaddr = psgval->bInEndpointAddress;
++	outaddr = psgval->bOutEndpointAddress;
++
++	epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
++	epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
++
++	if (NULL == epin || NULL == epout) {
++		CFI_INFO
++		    ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
++		     __func__, inaddr, outaddr);
++		return -DWC_E_INVALID;
++	}
++
++	epin->ep->dwc_ep.buff_mode = BM_SG;
++	dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
++
++	epout->ep->dwc_ep.buff_mode = BM_SG;
++	dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
++
++	return 0;
++}
++
++/**
++ * This function sets a new value for the buffer Alignment setup.
++ */
++static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
++{
++	cfi_ep_t *ep;
++	uint8_t addr;
++	ddma_align_buffer_setup_t *palignval;
++
++	palignval = (ddma_align_buffer_setup_t *) buf;
++	addr = palignval->bEndpointAddress;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, addr);
++		return -DWC_E_INVALID;
++	}
++
++	ep->ep->dwc_ep.buff_mode = BM_ALIGN;
++	dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
++
++	return 0;
++}
++
++/**
++ * This function sets a new value for the Concatenation buffer setup.
++ */
++static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
++{
++	uint8_t addr;
++	cfi_ep_t *ep;
++	struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
++	uint16_t *pVals;
++	uint32_t desccount;
++	int i;
++	uint16_t mps;
++
++	pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
++	desccount = (uint32_t) pConcatValHdr->bDescCount;
++	pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
++
++	/* Check the DMA descriptor count */
++	if (desccount > MAX_DMA_DESCS_PER_EP) {
++		CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
++			 __func__, MAX_DMA_DESCS_PER_EP);
++		return -DWC_E_INVALID;
++	}
++
++	addr = pConcatValHdr->bEndpointAddress;
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, addr);
++		return -DWC_E_INVALID;
++	}
++
++	mps = UGETW(ep->ep->desc->wMaxPacketSize);
++
++#if 0
++	for (i = 0; i < desccount; i++) {
++		CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
++	}
++	CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
++#endif
++
++	/* Check the wTxSizes to be less than or equal to the mps */
++	for (i = 0; i < desccount; i++) {
++		if (pVals[i] > mps) {
++			CFI_INFO
++			    ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
++			     __func__, i, pVals[i]);
++			return -DWC_E_INVALID;
++		}
++	}
++
++	ep->ep->dwc_ep.buff_mode = BM_CONCAT;
++	dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
++
++	/* Free the previously allocated storage for the wTxBytes */
++	if (ep->bm_concat->wTxBytes) {
++		DWC_FREE(ep->bm_concat->wTxBytes);
++	}
++
++	/* Allocate a new storage for the wTxBytes field */
++	ep->bm_concat->wTxBytes =
++	    DWC_ALLOC(sizeof(uint16_t) * pConcatValHdr->bDescCount);
++	if (NULL == ep->bm_concat->wTxBytes) {
++		CFI_INFO("%s: Unable to allocate memory\n", __func__);
++		return -DWC_E_NO_MEMORY;
++	}
++
++	/* Copy the new values into the wTxBytes filed */
++	dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
++		   sizeof(uint16_t) * pConcatValHdr->bDescCount);
++
++	return 0;
++}
++
++/**
++ * This function calculates the total of all FIFO sizes
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return The total of data FIFO sizes.
++ *
++ */
++static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_params_t *params = core_if->core_params;
++	uint16_t dfifo_total = 0;
++	int i;
++
++	/* The shared RxFIFO size */
++	dfifo_total =
++	    params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
++
++	/* Add up each TxFIFO size to the total */
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++		dfifo_total += params->dev_tx_fifo_size[i];
++	}
++
++	return dfifo_total;
++}
++
++/**
++ * This function returns Rx FIFO size
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return The total of data FIFO sizes.
++ *
++ */
++static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
++{
++	switch (wValue >> 8) {
++	case 0:
++		return (core_if->pwron_rxfsiz <
++			32768) ? core_if->pwron_rxfsiz : 32768;
++		break;
++	case 1:
++		return core_if->core_params->dev_rx_fifo_size;
++		break;
++	default:
++		return -DWC_E_INVALID;
++		break;
++	}
++}
++
++/**
++ * This function returns Tx FIFO size for IN EP
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return The total of data FIFO sizes.
++ *
++ */
++static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
++{
++	dwc_otg_pcd_ep_t *ep;
++
++	ep = get_ep_by_addr(pcd, wValue & 0xff);
++
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, wValue & 0xff);
++		return -DWC_E_INVALID;
++	}
++
++	if (!ep->dwc_ep.is_in) {
++		CFI_INFO
++		    ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
++		     __func__, wValue & 0xff);
++		return -DWC_E_INVALID;
++	}
++
++	switch (wValue >> 8) {
++	case 0:
++		return (GET_CORE_IF(pcd)->pwron_txfsiz
++			[ep->dwc_ep.tx_fifo_num - 1] <
++			768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->
++							      dwc_ep.tx_fifo_num
++							      - 1] : 32768;
++		break;
++	case 1:
++		return GET_CORE_IF(pcd)->core_params->
++		    dev_tx_fifo_size[ep->dwc_ep.num - 1];
++		break;
++	default:
++		return -DWC_E_INVALID;
++		break;
++	}
++}
++
++/**
++ * This function checks if the submitted combination of
++ * device mode FIFO sizes is possible or not.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return 1 if possible, 0 otherwise.
++ *
++ */
++static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
++{
++	uint16_t dfifo_actual = 0;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	uint16_t start_addr = 0;
++	int i;
++
++	dfifo_actual =
++	    params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++		dfifo_actual += params->dev_tx_fifo_size[i];
++	}
++
++	if (dfifo_actual > core_if->total_fifo_size) {
++		return 0;
++	}
++
++	if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
++		return 0;
++
++	if (params->dev_nperio_tx_fifo_size > 32768
++	    || params->dev_nperio_tx_fifo_size < 16)
++		return 0;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++
++		if (params->dev_tx_fifo_size[i] > 768
++		    || params->dev_tx_fifo_size[i] < 4)
++			return 0;
++	}
++
++	if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
++		return 0;
++	start_addr = params->dev_rx_fifo_size;
++
++	if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
++		return 0;
++	start_addr += params->dev_nperio_tx_fifo_size;
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++
++		if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
++			return 0;
++		start_addr += params->dev_tx_fifo_size[i];
++	}
++
++	return 1;
++}
++
++/**
++ * This function resizes Device mode FIFOs
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ * @return 1 if successful, 0 otherwise
++ *
++ */
++static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
++{
++	int i = 0;
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	uint32_t rx_fifo_size;
++	fifosize_data_t nptxfifosize;
++	fifosize_data_t txfifosize[15];
++
++	uint32_t rx_fsz_bak;
++	uint32_t nptxfsz_bak;
++	uint32_t txfsz_bak[15];
++
++	uint16_t start_address;
++	uint8_t retval = 1;
++
++	if (!check_fifo_sizes(core_if)) {
++		return 0;
++	}
++
++	/* Configure data FIFO sizes */
++	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
++		rx_fsz_bak = DWC_READ_REG32(&global_regs->grxfsiz);
++		rx_fifo_size = params->dev_rx_fifo_size;
++		DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
++
++		/*
++		 * Tx FIFOs These FIFOs are numbered from 1 to 15.
++		 * Indexes of the FIFO size module parameters in the
++		 * dev_tx_fifo_size array and the FIFO size registers in
++		 * the dtxfsiz array run from 0 to 14.
++		 */
++
++		/* Non-periodic Tx FIFO */
++		nptxfsz_bak = DWC_READ_REG32(&global_regs->gnptxfsiz);
++		nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++		start_address = params->dev_rx_fifo_size;
++		nptxfifosize.b.startaddr = start_address;
++
++		DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
++
++		start_address += nptxfifosize.b.depth;
++
++		for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++			txfsz_bak[i] = DWC_READ_REG32(&global_regs->dtxfsiz[i]);
++
++			txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
++			txfifosize[i].b.startaddr = start_address;
++			DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++					txfifosize[i].d32);
++
++			start_address += txfifosize[i].b.depth;
++		}
++
++		/** Check if register values are set correctly */
++		if (rx_fifo_size != DWC_READ_REG32(&global_regs->grxfsiz)) {
++			retval = 0;
++		}
++
++		if (nptxfifosize.d32 != DWC_READ_REG32(&global_regs->gnptxfsiz)) {
++			retval = 0;
++		}
++
++		for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++			if (txfifosize[i].d32 !=
++			    DWC_READ_REG32(&global_regs->dtxfsiz[i])) {
++				retval = 0;
++			}
++		}
++
++		/** If register values are not set correctly, reset old values */
++		if (retval == 0) {
++			DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fsz_bak);
++
++			/* Non-periodic Tx FIFO */
++			DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfsz_bak);
++
++			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++						txfsz_bak[i]);
++			}
++		}
++	} else {
++		return 0;
++	}
++
++	/* Flush the FIFOs */
++	dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
++	dwc_otg_flush_rx_fifo(core_if);
++
++	return retval;
++}
++
++/**
++ * This function sets a new value for the buffer Alignment setup.
++ */
++static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
++{
++	int retval;
++	uint32_t fsiz;
++	uint16_t size;
++	uint16_t ep_addr;
++	dwc_otg_pcd_ep_t *ep;
++	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
++	tx_fifo_size_setup_t *ptxfifoval;
++
++	ptxfifoval = (tx_fifo_size_setup_t *) buf;
++	ep_addr = ptxfifoval->bEndpointAddress;
++	size = ptxfifoval->wDepth;
++
++	ep = get_ep_by_addr(pcd, ep_addr);
++
++	CFI_INFO
++	    ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
++	     __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
++
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
++			 __func__, ep_addr);
++		return -DWC_E_INVALID;
++	}
++
++	fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
++	params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
++
++	if (resize_fifos(GET_CORE_IF(pcd))) {
++		retval = 0;
++	} else {
++		CFI_INFO
++		    ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
++		     __func__, ep_addr);
++		params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
++		retval = -DWC_E_INVALID;
++	}
++
++	return retval;
++}
++
++/**
++ * This function sets a new value for the buffer Alignment setup.
++ */
++static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
++{
++	int retval;
++	uint32_t fsiz;
++	uint16_t size;
++	dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
++	rx_fifo_size_setup_t *prxfifoval;
++
++	prxfifoval = (rx_fifo_size_setup_t *) buf;
++	size = prxfifoval->wDepth;
++
++	fsiz = params->dev_rx_fifo_size;
++	params->dev_rx_fifo_size = size;
++
++	if (resize_fifos(GET_CORE_IF(pcd))) {
++		retval = 0;
++	} else {
++		CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
++			 __func__);
++		params->dev_rx_fifo_size = fsiz;
++		retval = -DWC_E_INVALID;
++	}
++
++	return retval;
++}
++
++/**
++ * This function reads the SG of an EP's buffer setup into the buffer buf
++ */
++static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++			     struct cfi_usb_ctrlrequest *req)
++{
++	int retval = -DWC_E_INVALID;
++	uint8_t addr;
++	cfi_ep_t *ep;
++
++	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
++	addr = req->wValue & 0xFF;
++	if (addr == 0)		/* The address should be non-zero */
++		return retval;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
++			 __func__, addr);
++		return retval;
++	}
++
++	dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
++	retval = BS_SG_VAL_DESC_LEN;
++	return retval;
++}
++
++/**
++ * This function reads the Concatenation value of an EP's buffer mode into
++ * the buffer buf
++ */
++static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				 struct cfi_usb_ctrlrequest *req)
++{
++	int retval = -DWC_E_INVALID;
++	uint8_t addr;
++	cfi_ep_t *ep;
++	uint8_t desc_count;
++
++	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
++	addr = req->wValue & 0xFF;
++	if (addr == 0)		/* The address should be non-zero */
++		return retval;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
++			 __func__, addr);
++		return retval;
++	}
++
++	/* Copy the header to the buffer */
++	dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
++	/* Advance the buffer pointer by the header size */
++	buf += BS_CONCAT_VAL_HDR_LEN;
++
++	desc_count = ep->bm_concat->hdr.bDescCount;
++	/* Copy alll the wTxBytes to the buffer */
++	dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
++
++	retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
++	return retval;
++}
++
++/**
++ * This function reads the buffer Alignment value of an EP's buffer mode into
++ * the buffer buf
++ *
++ * @return The total number of bytes copied to the buffer or negative error code.
++ */
++static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
++				struct cfi_usb_ctrlrequest *req)
++{
++	int retval = -DWC_E_INVALID;
++	uint8_t addr;
++	cfi_ep_t *ep;
++
++	/* The Low Byte of the wValue contains a non-zero address of the endpoint */
++	addr = req->wValue & 0xFF;
++	if (addr == 0)		/* The address should be non-zero */
++		return retval;
++
++	ep = get_cfi_ep_by_addr(pcd->cfi, addr);
++	if (NULL == ep) {
++		CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
++			 __func__, addr);
++		return retval;
++	}
++
++	dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
++	retval = BS_ALIGN_VAL_HDR_LEN;
++
++	return retval;
++}
++
++/**
++ * This function sets a new value for the specified feature
++ *
++ * @param	pcd	A pointer to the PCD object
++ *
++ * @return 0 if successful, negative error code otherwise to stall the DCE.
++ */
++static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
++{
++	int retval = -DWC_E_NOT_SUPPORTED;
++	uint16_t wIndex, wValue;
++	uint8_t bRequest;
++	struct dwc_otg_core_if *coreif;
++	cfiobject_t *cfi = pcd->cfi;
++	struct cfi_usb_ctrlrequest *ctrl_req;
++	uint8_t *buf;
++	ctrl_req = &cfi->ctrl_req;
++
++	buf = pcd->cfi->ctrl_req.data;
++
++	coreif = GET_CORE_IF(pcd);
++	bRequest = ctrl_req->bRequest;
++	wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
++	wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
++
++	/* See which feature is to be modified */
++	switch (wIndex) {
++	case FT_ID_DMA_BUFFER_SETUP:
++		/* Modify the feature */
++		if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
++			return retval;
++
++		/* And send this request to the gadget */
++		cfi->need_gadget_att = 1;
++		break;
++
++	case FT_ID_DMA_BUFF_ALIGN:
++		if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 1;
++		break;
++
++	case FT_ID_DMA_CONCAT_SETUP:
++		/* Modify the feature */
++		if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 1;
++		break;
++
++	case FT_ID_DMA_CIRCULAR:
++		CFI_INFO("FT_ID_DMA_CIRCULAR\n");
++		break;
++
++	case FT_ID_THRESHOLD_SETUP:
++		CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
++		break;
++
++	case FT_ID_DFIFO_DEPTH:
++		CFI_INFO("FT_ID_DFIFO_DEPTH\n");
++		break;
++
++	case FT_ID_TX_FIFO_DEPTH:
++		CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
++		if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 0;
++		break;
++
++	case FT_ID_RX_FIFO_DEPTH:
++		CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
++		if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
++			return retval;
++		cfi->need_gadget_att = 0;
++		break;
++	}
++
++	return retval;
++}
++
++#endif //DWC_UTE_CFI
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
+@@ -0,0 +1,320 @@
++/* ==========================================================================
++ * 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_CFI_H__)
++#define __DWC_OTG_CFI_H__
++
++#include "dwc_otg_pcd.h"
++#include "dwc_cfi_common.h"
++
++/**
++ * @file
++ * This file contains the CFI related OTG PCD specific common constants,
++ * interfaces(functions and macros) and data structures.The CFI Protocol is an
++ * optional interface for internal testing purposes that a DUT may implement to
++ * support testing of configurable features.
++ *
++ */
++
++struct dwc_otg_pcd;
++struct dwc_otg_pcd_ep;
++
++/** OTG CFI Features (properties) ID constants */
++/** This is a request for all Core Features */
++#define FT_ID_DMA_MODE					0x0001
++#define FT_ID_DMA_BUFFER_SETUP			0x0002
++#define FT_ID_DMA_BUFF_ALIGN			0x0003
++#define FT_ID_DMA_CONCAT_SETUP			0x0004
++#define FT_ID_DMA_CIRCULAR				0x0005
++#define FT_ID_THRESHOLD_SETUP			0x0006
++#define FT_ID_DFIFO_DEPTH				0x0007
++#define FT_ID_TX_FIFO_DEPTH				0x0008
++#define FT_ID_RX_FIFO_DEPTH				0x0009
++
++/**********************************************************/
++#define CFI_INFO_DEF
++
++#ifdef CFI_INFO_DEF
++#define CFI_INFO(fmt...)	DWC_PRINTF("CFI: " fmt);
++#else
++#define CFI_INFO(fmt...)
++#endif
++
++#define min(x,y) ({ \
++	x < y ? x : y; })
++
++#define max(x,y) ({ \
++	x > y ? x : y; })
++
++/**
++ * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is
++ * also used for setting up a buffer for Circular DDMA.
++ */
++struct _ddma_sg_buffer_setup {
++#define BS_SG_VAL_DESC_LEN	6
++	/* The OUT EP address */
++	uint8_t bOutEndpointAddress;
++	/* The IN EP address */
++	uint8_t bInEndpointAddress;
++	/* Number of bytes to put between transfer segments (must be DWORD boundaries) */
++	uint8_t bOffset;
++	/* The number of transfer segments (a DMA descriptors per each segment) */
++	uint8_t bCount;
++	/* Size (in byte) of each transfer segment */
++	uint16_t wSize;
++} __attribute__ ((packed));
++typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
++
++/** Descriptor DMA Concatenation Buffer setup structure */
++struct _ddma_concat_buffer_setup_hdr {
++#define BS_CONCAT_VAL_HDR_LEN	4
++	/* The endpoint for which the buffer is to be set up */
++	uint8_t bEndpointAddress;
++	/* The count of descriptors to be used */
++	uint8_t bDescCount;
++	/* The total size of the transfer */
++	uint16_t wSize;
++} __attribute__ ((packed));
++typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
++
++/** Descriptor DMA Concatenation Buffer setup structure */
++struct _ddma_concat_buffer_setup {
++	/* The SG header */
++	ddma_concat_buffer_setup_hdr_t hdr;
++
++	/* The XFER sizes pointer (allocated dynamically) */
++	uint16_t *wTxBytes;
++} __attribute__ ((packed));
++typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
++
++/** Descriptor DMA Alignment Buffer setup structure */
++struct _ddma_align_buffer_setup {
++#define BS_ALIGN_VAL_HDR_LEN	2
++	uint8_t bEndpointAddress;
++	uint8_t bAlign;
++} __attribute__ ((packed));
++typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
++
++/** Transmit FIFO Size setup structure */
++struct _tx_fifo_size_setup {
++	uint8_t bEndpointAddress;
++	uint16_t wDepth;
++} __attribute__ ((packed));
++typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
++
++/** Transmit FIFO Size setup structure */
++struct _rx_fifo_size_setup {
++	uint16_t wDepth;
++} __attribute__ ((packed));
++typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
++
++/**
++ * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest
++ * This structure encapsulates the standard usb_ctrlrequest and adds a pointer
++ * to the data returned in the data stage of a 3-stage Control Write requests.
++ */
++struct cfi_usb_ctrlrequest {
++	uint8_t bRequestType;
++	uint8_t bRequest;
++	uint16_t wValue;
++	uint16_t wIndex;
++	uint16_t wLength;
++	uint8_t *data;
++} UPACKED;
++
++/*---------------------------------------------------------------------------*/
++
++/**
++ * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures.
++ * This structure is used to store the buffer setup data for any
++ * enabled endpoint in the PCD.
++ */
++struct cfi_ep {
++	/* Entry for the list container */
++	dwc_list_link_t lh;
++	/* Pointer to the active PCD endpoint structure */
++	struct dwc_otg_pcd_ep *ep;
++	/* The last descriptor in the chain of DMA descriptors of the endpoint */
++	struct dwc_otg_dma_desc *dma_desc_last;
++	/* The SG feature value */
++	ddma_sg_buffer_setup_t *bm_sg;
++	/* The Circular feature value */
++	ddma_sg_buffer_setup_t *bm_circ;
++	/* The Concatenation feature value */
++	ddma_concat_buffer_setup_t *bm_concat;
++	/* The Alignment feature value */
++	ddma_align_buffer_setup_t *bm_align;
++	/* XFER length */
++	uint32_t xfer_len;
++	/*
++	 * Count of DMA descriptors currently used.
++	 * The total should not exceed the MAX_DMA_DESCS_PER_EP value
++	 * defined in the dwc_otg_cil.h
++	 */
++	uint32_t desc_count;
++};
++typedef struct cfi_ep cfi_ep_t;
++
++typedef struct cfi_dma_buff {
++#define CFI_IN_BUF_LEN	1024
++#define CFI_OUT_BUF_LEN	1024
++	dma_addr_t addr;
++	uint8_t *buf;
++} cfi_dma_buff_t;
++
++struct cfiobject;
++
++/**
++ * This is the interface for the CFI operations.
++ *
++ * @param	ep_enable			Called when any endpoint is enabled and activated.
++ * @param	release				Called when the CFI object is released and it needs to correctly
++ *								deallocate the dynamic memory
++ * @param	ctrl_write_complete	Called when the data stage of the request is complete
++ */
++typedef struct cfi_ops {
++	int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
++			  struct dwc_otg_pcd_ep * ep);
++	void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
++			       struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
++			       unsigned size, gfp_t flags);
++	void (*release) (struct cfiobject * cfi);
++	int (*ctrl_write_complete) (struct cfiobject * cfi,
++				    struct dwc_otg_pcd * pcd);
++	void (*build_descriptors) (struct cfiobject * cfi,
++				   struct dwc_otg_pcd * pcd,
++				   struct dwc_otg_pcd_ep * ep,
++				   dwc_otg_pcd_request_t * req);
++} cfi_ops_t;
++
++struct cfiobject {
++	cfi_ops_t ops;
++	struct dwc_otg_pcd *pcd;
++	struct usb_gadget *gadget;
++
++	/* Buffers used to send/receive CFI-related request data */
++	cfi_dma_buff_t buf_in;
++	cfi_dma_buff_t buf_out;
++
++	/* CFI specific Control request wrapper */
++	struct cfi_usb_ctrlrequest ctrl_req;
++
++	/* The list of active EP's in the PCD of type cfi_ep_t */
++	dwc_list_link_t active_eps;
++
++	/* This flag shall control the propagation of a specific request
++	 * to the gadget's processing routines.
++	 * 0 - no gadget handling
++	 * 1 - the gadget needs to know about this request (w/o completing a status
++	 * phase - just return a 0 to the _setup callback)
++	 */
++	uint8_t need_gadget_att;
++
++	/* Flag indicating whether the status IN phase needs to be
++	 * completed by the PCD
++	 */
++	uint8_t need_status_in_complete;
++};
++typedef struct cfiobject cfiobject_t;
++
++#define DUMP_MSG
++
++#if defined(DUMP_MSG)
++static inline void dump_msg(const u8 * buf, unsigned int length)
++{
++	unsigned int start, num, i;
++	char line[52], *p;
++
++	if (length >= 512)
++		return;
++
++	start = 0;
++	while (length > 0) {
++		num = min(length, 16u);
++		p = line;
++		for (i = 0; i < num; ++i) {
++			if (i == 8)
++				*p++ = ' ';
++			DWC_SPRINTF(p, " %02x", buf[i]);
++			p += 3;
++		}
++		*p = 0;
++		DWC_DEBUG("%6x: %s\n", start, line);
++		buf += num;
++		start += num;
++		length -= num;
++	}
++}
++#else
++static inline void dump_msg(const u8 * buf, unsigned int length)
++{
++}
++#endif
++
++/**
++ * This function returns a pointer to cfi_ep_t object with the addr address.
++ */
++static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
++						uint8_t addr)
++{
++	struct cfi_ep *pcfiep;
++	dwc_list_link_t *tmp;
++
++	DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++		pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++
++		if (pcfiep->ep->desc->bEndpointAddress == addr) {
++			return pcfiep;
++		}
++	}
++
++	return NULL;
++}
++
++/**
++ * This function returns a pointer to cfi_ep_t object that matches
++ * the dwc_otg_pcd_ep object.
++ */
++static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
++						  struct dwc_otg_pcd_ep *ep)
++{
++	struct cfi_ep *pcfiep = NULL;
++	dwc_list_link_t *tmp;
++
++	DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
++		pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
++		if (pcfiep->ep == ep) {
++			return pcfiep;
++		}
++	}
++	return NULL;
++}
++
++int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
++
++#endif /* (__DWC_OTG_CFI_H__) */
+--- /dev/null
++++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
+@@ -0,0 +1,7141 @@
++/* ==========================================================================
++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
++ * $Revision: #191 $
++ * $Date: 2012/08/10 $
++ * $Change: 2047372 $
++ *
++ * 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 Core Interface Layer provides basic services for accessing and
++ * managing the DWC_otg hardware. These services are used by both the
++ * Host Controller Driver and the Peripheral Controller Driver.
++ *
++ * The CIL manages the memory map for the core so that the HCD and PCD
++ * don't have to do this separately. It also handles basic tasks like
++ * reading/writing the registers and data FIFOs in the controller.
++ * Some of the data access functions provide encapsulation of several
++ * operations required to perform a task, such as writing multiple
++ * registers to start a transfer. Finally, the CIL performs basic
++ * services that are not specific to either the host or device modes
++ * of operation. These services include management of the OTG Host
++ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
++ * Diagnostic API is also provided to allow testing of the controller
++ * hardware.
++ *
++ * The Core Interface Layer has the following requirements:
++ * - Provides basic controller operations.
++ * - Minimal use of OS services.
++ * - The OS services used will be abstracted by using inline functions
++ *	 or macros.
++ *
++ */
++
++#include "dwc_os.h"
++#include "dwc_otg_regs.h"
++#include "dwc_otg_cil.h"
++
++static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
++
++/**
++ * This function is called to initialize the DWC_otg CSR data
++ * structures. The register addresses in the device and host
++ * structures are initialized from the base address supplied by the
++ * caller. The calling function must make the OS calls to get the
++ * base address of the DWC_otg controller registers. The core_params
++ * argument holds the parameters that specify how the core should be
++ * configured.
++ *
++ * @param reg_base_addr Base address of DWC_otg core registers
++ *
++ */
++dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
++{
++	dwc_otg_core_if_t *core_if = 0;
++	dwc_otg_dev_if_t *dev_if = 0;
++	dwc_otg_host_if_t *host_if = 0;
++	uint8_t *reg_base = (uint8_t *) reg_base_addr;
++	int i = 0;
++
++	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
++
++	core_if = DWC_ALLOC(sizeof(dwc_otg_core_if_t));
++
++	if (core_if == NULL) {
++		DWC_DEBUGPL(DBG_CIL,
++			    "Allocation of dwc_otg_core_if_t failed\n");
++		return 0;
++	}
++	core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
++
++	/*
++	 * Allocate the Device Mode structures.
++	 */
++	dev_if = DWC_ALLOC(sizeof(dwc_otg_dev_if_t));
++
++	if (dev_if == NULL) {
++		DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	dev_if->dev_global_regs =
++	    (dwc_otg_device_global_regs_t *) (reg_base +
++					      DWC_DEV_GLOBAL_REG_OFFSET);
++
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
++		    (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
++		     (i * DWC_EP_REG_OFFSET));
++
++		dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
++		    (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
++		     (i * DWC_EP_REG_OFFSET));
++		DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
++			    i, &dev_if->in_ep_regs[i]->diepctl);
++		DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
++			    i, &dev_if->out_ep_regs[i]->doepctl);
++	}
++
++	dev_if->speed = 0;	// unknown
++
++	core_if->dev_if = dev_if;
++
++	/*
++	 * Allocate the Host Mode structures.
++	 */
++	host_if = DWC_ALLOC(sizeof(dwc_otg_host_if_t));
++
++	if (host_if == NULL) {
++		DWC_DEBUGPL(DBG_CIL,
++			    "Allocation of dwc_otg_host_if_t failed\n");
++		DWC_FREE(dev_if);
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
++	    (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
++
++	host_if->hprt0 =
++	    (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
++
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
++		    (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
++		     (i * DWC_OTG_CHAN_REGS_OFFSET));
++		DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
++			    i, &host_if->hc_regs[i]->hcchar);
++	}
++
++	host_if->num_host_channels = MAX_EPS_CHANNELS;
++	core_if->host_if = host_if;
++
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		core_if->data_fifo[i] =
++		    (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
++				  (i * DWC_OTG_DATA_FIFO_SIZE));
++		DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08lx\n",
++			    i, (unsigned long)core_if->data_fifo[i]);
++	}
++
++	core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
++
++	/* Initiate lx_state to L3 disconnected state */
++	core_if->lx_state = DWC_OTG_L3;
++	/*
++	 * Store the contents of the hardware configuration registers here for
++	 * easy access later.
++	 */
++	core_if->hwcfg1.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg1);
++	core_if->hwcfg2.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
++	core_if->hwcfg3.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg3);
++	core_if->hwcfg4.d32 =
++	    DWC_READ_REG32(&core_if->core_global_regs->ghwcfg4);
++
++	/* Force host mode to get HPTXFSIZ exact power on value */
++	{
++		gusbcfg_data_t gusbcfg = {.d32 = 0 };
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_host_mode = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(100);
++		core_if->hptxfsiz.d32 =
++		DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
++		gusbcfg.d32 =  DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++		gusbcfg.b.force_host_mode = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++		dwc_mdelay(100);
++	}
++
++	DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
++	DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
++	DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
++	DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
++
++	core_if->hcfg.d32 =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	core_if->dcfg.d32 =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++
++	DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
++	DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
++
++	DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
++	DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
++	DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
++	DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
++		    core_if->hwcfg2.b.num_host_chan);
++	DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
++		    core_if->hwcfg2.b.nonperio_tx_q_depth);
++	DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
++		    core_if->hwcfg2.b.host_perio_tx_q_depth);
++	DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
++		    core_if->hwcfg2.b.dev_token_q_depth);
++
++	DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
++		    core_if->hwcfg3.b.dfifo_depth);
++	DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
++		    core_if->hwcfg3.b.xfer_size_cntr_width);
++
++	/*
++	 * Set the SRP sucess bit for FS-I2c
++	 */
++	core_if->srp_success = 0;
++	core_if->srp_timer_started = 0;
++
++	/*
++	 * Create new workqueue and init works
++	 */
++	core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
++	if (core_if->wq_otg == 0) {
++		DWC_WARN("DWC_WORKQ_ALLOC failed\n");
++		DWC_FREE(host_if);
++		DWC_FREE(dev_if);
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	core_if->snpsid = DWC_READ_REG32(&core_if->core_global_regs->gsnpsid);
++
++	DWC_PRINTF("Core Release: %x.%x%x%x\n",
++		   (core_if->snpsid >> 12 & 0xF),
++		   (core_if->snpsid >> 8 & 0xF),
++		   (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
++
++	core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
++					     w_wakeup_detected, core_if);
++	if (core_if->wkp_timer == 0) {
++		DWC_WARN("DWC_TIMER_ALLOC failed\n");
++		DWC_FREE(host_if);
++		DWC_FREE(dev_if);
++		DWC_WORKQ_FREE(core_if->wq_otg);
++		DWC_FREE(core_if);
++		return 0;
++	}
++
++	if (dwc_otg_setup_params(core_if)) {
++		DWC_WARN("Error while setting core params\n");
++	}
++
++	core_if->hibernation_suspend = 0;
++
++	/** ADP initialization */
++	dwc_otg_adp_init(core_if);
++
++	return core_if;
++}
++
++/**
++ * This function frees the structures allocated by dwc_otg_cil_init().
++ *
++ * @param core_if The core interface pointer returned from
++ * 		  dwc_otg_cil_init().
++ *
++ */
++void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
++{
++	dctl_data_t dctl = {.d32 = 0 };
++	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
++
++	/* Disable all interrupts */
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 1, 0);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
++
++	dctl.b.sftdiscon = 1;
++	if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0,
++				 dctl.d32);
++	}
++
++	if (core_if->wq_otg) {
++		DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
++		DWC_WORKQ_FREE(core_if->wq_otg);
++	}
++	if (core_if->dev_if) {
++		DWC_FREE(core_if->dev_if);
++	}
++	if (core_if->host_if) {
++		DWC_FREE(core_if->host_if);
++	}
++
++	/** Remove ADP Stuff  */
++	dwc_otg_adp_remove(core_if);
++	if (core_if->core_params) {
++		DWC_FREE(core_if->core_params);
++	}
++	if (core_if->wkp_timer) {
++		DWC_TIMER_FREE(core_if->wkp_timer);
++	}
++	if (core_if->srp_timer) {
++		DWC_TIMER_FREE(core_if->srp_timer);
++	}
++	DWC_FREE(core_if);
++}
++
++/**
++ * This function enables the controller's Global Interrupt in the AHB Config
++ * register.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
++{
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++	ahbcfg.b.glblintrmsk = 1;	/* Enable interrupts */
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
++}
++
++/**
++ * This function disables the controller's Global Interrupt in the AHB Config
++ * register.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
++{
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++	ahbcfg.b.glblintrmsk = 1;	/* Disable interrupts */
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
++}
++
++/**
++ * This function initializes the commmon interrupts, used in both
++ * device and host modes.
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ *
++ */
++static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	/* Clear any pending OTG Interrupts */
++	DWC_WRITE_REG32(&global_regs->gotgint, 0xFFFFFFFF);
++
++	/* Clear any pending interrupts */
++	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
++
++	/*
++	 * Enable the interrupts in the GINTMSK.
++	 */
++	intr_mask.b.modemismatch = 1;
++	intr_mask.b.otgintr = 1;
++
++	if (!core_if->dma_enable) {
++		intr_mask.b.rxstsqlvl = 1;
++	}
++
++	intr_mask.b.conidstschng = 1;
++	intr_mask.b.wkupintr = 1;
++	intr_mask.b.disconnect = 0;
++	intr_mask.b.usbsuspend = 1;
++	intr_mask.b.sessreqintr = 1;
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	if (core_if->core_params->lpm_enable) {
++		intr_mask.b.lpmtranrcvd = 1;
++	}
++#endif
++	DWC_WRITE_REG32(&global_regs->gintmsk, intr_mask.d32);
++}
++
++/*
++ * The restore operation is modified to support Synopsys Emulated Powerdown and
++ * Hibernation. This function is for exiting from Device mode hibernation by
++ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
++ * @param core_if Programming view of DWC_otg controller.
++ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
++ * @param reset - indicates whether resume is initiated by Reset.
++ */
++int dwc_otg_device_hibernation_restore(dwc_otg_core_if_t * core_if,
++				       int rem_wakeup, int reset)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	dctl_data_t dctl = {.d32 = 0 };
++
++	int timeout = 2000;
++
++	if (!core_if->hibernation_suspend) {
++		DWC_PRINTF("Already exited from Hibernation\n");
++		return 1;
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "%s called\n", __FUNCTION__);
++	/* Switch-on voltage to the core */
++	gpwrdn.b.pwrdnswtch = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Assert Restore signal */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable power clamps */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnclmp = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	if (rem_wakeup) {
++		dwc_udelay(70);
++	}
++
++	/* Deassert Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable PMU interrupt */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuintsel = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Mask interrupts from gpwrdn */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.connect_det_msk = 1;
++	gpwrdn.b.srp_det_msk = 1;
++	gpwrdn.b.disconn_det_msk = 1;
++	gpwrdn.b.rst_det_msk = 1;
++	gpwrdn.b.lnstchng_msk = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Indicates that we are going out from hibernation */
++	core_if->hibernation_suspend = 0;
++
++	/*
++	 * Set Restore Essential Regs bit in PCGCCTL register, restore_mode = 1
++	 * indicates restore from remote_wakeup
++	 */
++	restore_essential_regs(core_if, rem_wakeup, 0);
++
++	/*
++	 * Wait a little for seeing new value of variable hibernation_suspend if
++	 * Restore done interrupt received before polling
++	 */
++	dwc_udelay(10);
++
++	if (core_if->hibernation_suspend == 0) {
++		/*
++		 * Wait For Restore_done Interrupt. This mechanism of polling the
++		 * interrupt is introduced to avoid any possible race conditions
++		 */
++		do {
++			gintsts_data_t gintsts;
++			gintsts.d32 =
++			    DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			if (gintsts.b.restoredone) {
++				gintsts.d32 = 0;
++				gintsts.b.restoredone = 1;
++				DWC_WRITE_REG32(&core_if->core_global_regs->
++						gintsts, gintsts.d32);
++				DWC_PRINTF("Restore Done Interrupt seen\n");
++				break;
++			}
++			dwc_udelay(10);
++		} while (--timeout);
++		if (!timeout) {
++			DWC_PRINTF("Restore Done interrupt wasn't generated here\n");
++		}
++	}
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* De-assert Restore */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	if (!rem_wakeup) {
++		pcgcctl.d32 = 0;
++		pcgcctl.b.rstpdwnmodule = 1;
++		DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
++	}
++
++	/* Restore GUSBCFG and DCFG */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
++			core_if->gr_backup->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
++			core_if->dr_backup->dcfg);
++
++	/* De-assert Wakeup Logic */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	if (!rem_wakeup) {
++		/* Set Device programming done bit */
++		dctl.b.pwronprgdone = 1;
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++	} else {
++		/* Start Remote Wakeup Signaling */
++		dctl.d32 = core_if->dr_backup->dctl;
++		dctl.b.rmtwkupsig = 1;
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
++	}
++
++	dwc_mdelay(2);
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Restore global registers */
++	dwc_otg_restore_global_regs(core_if);
++	/* Restore device global registers */
++	dwc_otg_restore_dev_regs(core_if, rem_wakeup);
++
++	if (rem_wakeup) {
++		dwc_mdelay(7);
++		dctl.d32 = 0;
++		dctl.b.rmtwkupsig = 1;
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
++	}
++
++	core_if->hibernation_suspend = 0;
++	/* The core will be in ON STATE */
++	core_if->lx_state = DWC_OTG_L0;
++	DWC_PRINTF("Hibernation recovery completes here\n");
++
++	return 1;
++}
++
++/*
++ * The restore operation is modified to support Synopsys Emulated Powerdown and
++ * Hibernation. This function is for exiting from Host mode hibernation by
++ * Host Initiated Resume/Reset and Device Initiated Remote-Wakeup.
++ * @param core_if Programming view of DWC_otg controller.
++ * @param rem_wakeup - indicates whether resume is initiated by Device or Host.
++ * @param reset - indicates whether resume is initiated by Reset.
++ */
++int dwc_otg_host_hibernation_restore(dwc_otg_core_if_t * core_if,
++				     int rem_wakeup, int reset)
++{
++	gpwrdn_data_t gpwrdn = {.d32 = 0 };
++	hprt0_data_t hprt0 = {.d32 = 0 };
++
++	int timeout = 2000;
++
++	DWC_DEBUGPL(DBG_HCD, "%s called\n", __FUNCTION__);
++	/* Switch-on voltage to the core */
++	gpwrdn.b.pwrdnswtch = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Assert Restore signal */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable power clamps */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnclmp = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	if (!rem_wakeup) {
++		dwc_udelay(50);
++	}
++
++	/* Deassert Reset core */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pwrdnrstn = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
++	dwc_udelay(10);
++
++	/* Disable PMU interrupt */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuintsel = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	gpwrdn.d32 = 0;
++	gpwrdn.b.connect_det_msk = 1;
++	gpwrdn.b.srp_det_msk = 1;
++	gpwrdn.b.disconn_det_msk = 1;
++	gpwrdn.b.rst_det_msk = 1;
++	gpwrdn.b.lnstchng_msk = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++
++	/* Indicates that we are going out from hibernation */
++	core_if->hibernation_suspend = 0;
++
++	/* Set Restore Essential Regs bit in PCGCCTL register */
++	restore_essential_regs(core_if, rem_wakeup, 1);
++
++	/* Wait a little for seeing new value of variable hibernation_suspend if
++	 * Restore done interrupt received before polling */
++	dwc_udelay(10);
++
++	if (core_if->hibernation_suspend == 0) {
++		/* Wait For Restore_done Interrupt. This mechanism of polling the
++		 * interrupt is introduced to avoid any possible race conditions
++		 */
++		do {
++			gintsts_data_t gintsts;
++			gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			if (gintsts.b.restoredone) {
++				gintsts.d32 = 0;
++				gintsts.b.restoredone = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++				DWC_DEBUGPL(DBG_HCD,"Restore Done Interrupt seen\n");
++				break;
++			}
++			dwc_udelay(10);
++		} while (--timeout);
++		if (!timeout) {
++			DWC_WARN("Restore Done interrupt wasn't generated\n");
++		}
++	}
++
++	/* Set the flag's value to 0 again after receiving restore done interrupt */
++	core_if->hibernation_suspend = 0;
++
++	/* This step is not described in functional spec but if not wait for this
++	 * delay, mismatch interrupts occurred because just after restore core is
++	 * in Device mode(gintsts.curmode == 0) */
++	dwc_mdelay(100);
++
++	/* Clear all pending interrupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* De-assert Restore */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.restore = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Restore GUSBCFG and HCFG */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
++			core_if->gr_backup->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
++			core_if->hr_backup->hcfg_local);
++
++	/* De-assert Wakeup Logic */
++	gpwrdn.d32 = 0;
++	gpwrdn.b.pmuactv = 1;
++	DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
++	dwc_udelay(10);
++
++	/* Start the Resume operation by programming HPRT0 */
++	hprt0.d32 = core_if->hr_backup->hprt0_local;
++	hprt0.b.prtpwr = 1;
++	hprt0.b.prtena = 0;
++	hprt0.b.prtsusp = 0;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++	DWC_PRINTF("Resume Starts Now\n");
++	if (!reset) {		// Indicates it is Resume Operation
++		hprt0.d32 = core_if->hr_backup->hprt0_local;
++		hprt0.b.prtres = 1;
++		hprt0.b.prtpwr = 1;
++		hprt0.b.prtena = 0;
++		hprt0.b.prtsusp = 0;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++		if (!rem_wakeup)
++			hprt0.b.prtres = 0;
++		/* Wait for Resume time and then program HPRT again */
++		dwc_mdelay(100);
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++	} else {		// Indicates it is Reset Operation
++		hprt0.d32 = core_if->hr_backup->hprt0_local;
++		hprt0.b.prtrst = 1;
++		hprt0.b.prtpwr = 1;
++		hprt0.b.prtena = 0;
++		hprt0.b.prtsusp = 0;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++		/* Wait for Reset time and then program HPRT again */
++		dwc_mdelay(60);
++		hprt0.b.prtrst = 0;
++		DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++	}
++	/* Clear all interrupt status */
++	hprt0.d32 = dwc_otg_read_hprt0(core_if);
++	hprt0.b.prtconndet = 1;
++	hprt0.b.prtenchng = 1;
++	DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
++
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Restore global registers */
++	dwc_otg_restore_global_regs(core_if);
++	/* Restore host global registers */
++	dwc_otg_restore_host_regs(core_if, reset);
++
++	/* The core will be in ON STATE */
++	core_if->lx_state = DWC_OTG_L0;
++	DWC_PRINTF("Hibernation recovery is complete here\n");
++	return 0;
++}
++
++/** Saves some register values into system memory. */
++int dwc_otg_save_global_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++	int i;
++
++	gr = core_if->gr_backup;
++	if (!gr) {
++		gr = DWC_ALLOC(sizeof(*gr));
++		if (!gr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->gr_backup = gr;
++	}
++
++	gr->gotgctl_local = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
++	gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++	gr->gahbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
++	gr->gusbcfg_local = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	gr->grxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->grxfsiz);
++	gr->gnptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->gnptxfsiz);
++	gr->hptxfsiz_local = DWC_READ_REG32(&core_if->core_global_regs->hptxfsiz);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	gr->glpmcfg_local = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
++#endif
++	gr->gi2cctl_local = DWC_READ_REG32(&core_if->core_global_regs->gi2cctl);
++	gr->pcgcctl_local = DWC_READ_REG32(core_if->pcgcctl);
++	gr->gdfifocfg_local =
++	    DWC_READ_REG32(&core_if->core_global_regs->gdfifocfg);
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		gr->dtxfsiz_local[i] =
++		    DWC_READ_REG32(&(core_if->core_global_regs->dtxfsiz[i]));
++	}
++
++	DWC_DEBUGPL(DBG_ANY, "===========Backing Global registers==========\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up gotgctl   = %08x\n", gr->gotgctl_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk   = %08x\n", gr->gintmsk_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gahbcfg   = %08x\n", gr->gahbcfg_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gusbcfg   = %08x\n", gr->gusbcfg_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up grxfsiz   = %08x\n", gr->grxfsiz_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up gnptxfsiz = %08x\n",
++		    gr->gnptxfsiz_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up hptxfsiz  = %08x\n",
++		    gr->hptxfsiz_local);
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	DWC_DEBUGPL(DBG_ANY, "Backed up glpmcfg   = %08x\n", gr->glpmcfg_local);
++#endif
++	DWC_DEBUGPL(DBG_ANY, "Backed up gi2cctl   = %08x\n", gr->gi2cctl_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up pcgcctl   = %08x\n", gr->pcgcctl_local);
++	DWC_DEBUGPL(DBG_ANY,"Backed up gdfifocfg   = %08x\n",gr->gdfifocfg_local);
++
++	return 0;
++}
++
++/** Saves GINTMSK register before setting the msk bits. */
++int dwc_otg_save_gintmsk_reg(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++
++	gr = core_if->gr_backup;
++	if (!gr) {
++		gr = DWC_ALLOC(sizeof(*gr));
++		if (!gr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->gr_backup = gr;
++	}
++
++	gr->gintmsk_local = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
++
++	DWC_DEBUGPL(DBG_ANY,"=============Backing GINTMSK registers============\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up gintmsk   = %08x\n", gr->gintmsk_local);
++
++	return 0;
++}
++
++int dwc_otg_save_dev_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_dev_regs_backup *dr;
++	int i;
++
++	dr = core_if->dr_backup;
++	if (!dr) {
++		dr = DWC_ALLOC(sizeof(*dr));
++		if (!dr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->dr_backup = dr;
++	}
++
++	dr->dcfg = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++	dr->dctl = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
++	dr->daintmsk =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->daintmsk);
++	dr->diepmsk =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->diepmsk);
++	dr->doepmsk =
++	    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->doepmsk);
++
++	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++		dr->diepctl[i] =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl);
++		dr->dieptsiz[i] =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz);
++		dr->diepdma[i] =
++		    DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma);
++	}
++
++	DWC_DEBUGPL(DBG_ANY,
++		    "=============Backing Host registers==============\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up dcfg            = %08x\n", dr->dcfg);
++	DWC_DEBUGPL(DBG_ANY, "Backed up dctl        = %08x\n", dr->dctl);
++	DWC_DEBUGPL(DBG_ANY, "Backed up daintmsk            = %08x\n",
++		    dr->daintmsk);
++	DWC_DEBUGPL(DBG_ANY, "Backed up diepmsk        = %08x\n", dr->diepmsk);
++	DWC_DEBUGPL(DBG_ANY, "Backed up doepmsk        = %08x\n", dr->doepmsk);
++	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++		DWC_DEBUGPL(DBG_ANY, "Backed up diepctl[%d]        = %08x\n", i,
++			    dr->diepctl[i]);
++		DWC_DEBUGPL(DBG_ANY, "Backed up dieptsiz[%d]        = %08x\n",
++			    i, dr->dieptsiz[i]);
++		DWC_DEBUGPL(DBG_ANY, "Backed up diepdma[%d]        = %08x\n", i,
++			    dr->diepdma[i]);
++	}
++
++	return 0;
++}
++
++int dwc_otg_save_host_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_host_regs_backup *hr;
++	int i;
++
++	hr = core_if->hr_backup;
++	if (!hr) {
++		hr = DWC_ALLOC(sizeof(*hr));
++		if (!hr) {
++			return -DWC_E_NO_MEMORY;
++		}
++		core_if->hr_backup = hr;
++	}
++
++	hr->hcfg_local =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	hr->haintmsk_local =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
++	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
++		hr->hcintmsk_local[i] =
++		    DWC_READ_REG32(&core_if->host_if->hc_regs[i]->hcintmsk);
++	}
++	hr->hprt0_local = DWC_READ_REG32(core_if->host_if->hprt0);
++	hr->hfir_local =
++	    DWC_READ_REG32(&core_if->host_if->host_global_regs->hfir);
++
++	DWC_DEBUGPL(DBG_ANY,
++		    "=============Backing Host registers===============\n");
++	DWC_DEBUGPL(DBG_ANY, "Backed up hcfg		= %08x\n",
++		    hr->hcfg_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up haintmsk = %08x\n", hr->haintmsk_local);
++	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
++		DWC_DEBUGPL(DBG_ANY, "Backed up hcintmsk[%02d]=%08x\n", i,
++			    hr->hcintmsk_local[i]);
++	}
++	DWC_DEBUGPL(DBG_ANY, "Backed up hprt0           = %08x\n",
++		    hr->hprt0_local);
++	DWC_DEBUGPL(DBG_ANY, "Backed up hfir           = %08x\n",
++		    hr->hfir_local);
++
++	return 0;
++}
++
++int dwc_otg_restore_global_regs(dwc_otg_core_if_t *core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++	int i;
++
++	gr = core_if->gr_backup;
++	if (!gr) {
++		return -DWC_E_INVALID;
++	}
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gotgctl, gr->gotgctl_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gr->gintmsk_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gr->gusbcfg_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gr->gahbcfg_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->grxfsiz, gr->grxfsiz_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gnptxfsiz,
++			gr->gnptxfsiz_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->hptxfsiz,
++			gr->hptxfsiz_local);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gdfifocfg,
++			gr->gdfifocfg_local);
++	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
++		DWC_WRITE_REG32(&core_if->core_global_regs->dtxfsiz[i],
++				gr->dtxfsiz_local[i]);
++	}
++
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++	DWC_WRITE_REG32(core_if->host_if->hprt0, 0x0000100A);
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg,
++			(gr->gahbcfg_local));
++	return 0;
++}
++
++int dwc_otg_restore_dev_regs(dwc_otg_core_if_t * core_if, int rem_wakeup)
++{
++	struct dwc_otg_dev_regs_backup *dr;
++	int i;
++
++	dr = core_if->dr_backup;
++
++	if (!dr) {
++		return -DWC_E_INVALID;
++	}
++
++	if (!rem_wakeup) {
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
++				dr->dctl);
++	}
++
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, dr->daintmsk);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, dr->diepmsk);
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, dr->doepmsk);
++
++	for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->dieptsiz, dr->dieptsiz[i]);
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepdma, dr->diepdma[i]);
++		DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl, dr->diepctl[i]);
++	}
++
++	return 0;
++}
++
++int dwc_otg_restore_host_regs(dwc_otg_core_if_t * core_if, int reset)
++{
++	struct dwc_otg_host_regs_backup *hr;
++	int i;
++	hr = core_if->hr_backup;
++
++	if (!hr) {
++		return -DWC_E_INVALID;
++	}
++
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hr->hcfg_local);
++	//if (!reset)
++	//{
++	//      DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hfir, hr->hfir_local);
++	//}
++
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk,
++			hr->haintmsk_local);
++	for (i = 0; i < dwc_otg_get_param_host_channels(core_if); ++i) {
++		DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk,
++				hr->hcintmsk_local[i]);
++	}
++
++	return 0;
++}
++
++int restore_lpm_i2c_regs(dwc_otg_core_if_t * core_if)
++{
++	struct dwc_otg_global_regs_backup *gr;
++
++	gr = core_if->gr_backup;
++
++	/* Restore values for LPM and I2C */
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, gr->glpmcfg_local);
++#endif
++	DWC_WRITE_REG32(&core_if->core_global_regs->gi2cctl, gr->gi2cctl_local);
++
++	return 0;
++}
++
++int restore_essential_regs(dwc_otg_core_if_t * core_if, int rmode, int is_host)
++{
++	struct dwc_otg_global_regs_backup *gr;
++	pcgcctl_data_t pcgcctl = {.d32 = 0 };
++	gahbcfg_data_t gahbcfg = {.d32 = 0 };
++	gusbcfg_data_t gusbcfg = {.d32 = 0 };
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++	/* Restore LPM and I2C registers */
++	restore_lpm_i2c_regs(core_if);
++
++	/* Set PCGCCTL to 0 */
++	DWC_WRITE_REG32(core_if->pcgcctl, 0x00000000);
++
++	gr = core_if->gr_backup;
++	/* Load restore values for [31:14] bits */
++	DWC_WRITE_REG32(core_if->pcgcctl,
++			((gr->pcgcctl_local & 0xffffc000) | 0x00020000));
++
++	/* Umnask global Interrupt in GAHBCFG and restore it */
++	gahbcfg.d32 = gr->gahbcfg_local;
++	gahbcfg.b.glblintrmsk = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
++
++	/* Clear all pending interupts */
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Unmask restore done interrupt */
++	gintmsk.b.restoredone = 1;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
++
++	/* Restore GUSBCFG and HCFG/DCFG */
++	gusbcfg.d32 = core_if->gr_backup->gusbcfg_local;
++	DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, gusbcfg.d32);
++
++	if (is_host) {
++		hcfg_data_t hcfg = {.d32 = 0 };
++		hcfg.d32 = core_if->hr_backup->hcfg_local;
++		DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg,
++				hcfg.d32);
++
++		/* Load restore values for [31:14] bits */
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
++
++		if (rmode)
++			pcgcctl.b.restoremode = 1;
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++		dwc_udelay(10);
++
++		/* Load restore values for [31:14] bits and set EssRegRestored bit */
++		pcgcctl.d32 = gr->pcgcctl_local | 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.b.ess_reg_restored = 1;
++		if (rmode)
++			pcgcctl.b.restoremode = 1;
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++	} else {
++		dcfg_data_t dcfg = {.d32 = 0 };
++		dcfg.d32 = core_if->dr_backup->dcfg;
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++		/* Load restore values for [31:14] bits */
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
++		if (!rmode) {
++			pcgcctl.d32 |= 0x208;
++		}
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++		dwc_udelay(10);
++
++		/* Load restore values for [31:14] bits */
++		pcgcctl.d32 = gr->pcgcctl_local & 0xffffc000;
++		pcgcctl.d32 = gr->pcgcctl_local | 0x00020000;
++		pcgcctl.b.ess_reg_restored = 1;
++		if (!rmode)
++			pcgcctl.d32 |= 0x208;
++		DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
++	}
++
++	return 0;
++}
++
++/**
++ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
++ * type.
++ */
++static void init_fslspclksel(dwc_otg_core_if_t * core_if)
++{
++	uint32_t val;
++	hcfg_data_t hcfg;
++
++	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	     (core_if->core_params->ulpi_fs_ls)) ||
++	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
++		/* Full speed PHY */
++		val = DWC_HCFG_48_MHZ;
++	} else {
++		/* High speed PHY running at full speed or high speed */
++		val = DWC_HCFG_30_60_MHZ;
++	}
++
++	DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
++	hcfg.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->hcfg);
++	hcfg.b.fslspclksel = val;
++	DWC_WRITE_REG32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
++}
++
++/**
++ * Initializes the DevSpd field of the DCFG register depending on the PHY type
++ * and the enumeration speed of the device.
++ */
++static void init_devspd(dwc_otg_core_if_t * core_if)
++{
++	uint32_t val;
++	dcfg_data_t dcfg;
++
++	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	     (core_if->core_params->ulpi_fs_ls)) ||
++	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
++		/* Full speed PHY */
++		val = 0x3;
++	} else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
++		/* High speed PHY running at full speed */
++		val = 0x1;
++	} else {
++		/* High speed PHY running at high speed */
++		val = 0x0;
++	}
++
++	DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
++
++	dcfg.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++	dcfg.b.devspd = val;
++	DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
++}
++
++/**
++ * This function calculates the number of IN EPS
++ * using GHWCFG1 and GHWCFG2 registers values
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ */
++static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
++{
++	uint32_t num_in_eps = 0;
++	uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
++	uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
++	uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
++	int i;
++
++	for (i = 0; i < num_eps; ++i) {
++		if (!(hwcfg1 & 0x1))
++			num_in_eps++;
++
++		hwcfg1 >>= 2;
++	}
++
++	if (core_if->hwcfg4.b.ded_fifo_en) {
++		num_in_eps =
++		    (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
++	}
++
++	return num_in_eps;
++}
++
++/**
++ * This function calculates the number of OUT EPS
++ * using GHWCFG1 and GHWCFG2 registers values
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ */
++static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
++{
++	uint32_t num_out_eps = 0;
++	uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
++	uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
++	int i;
++
++	for (i = 0; i < num_eps; ++i) {
++		if (!(hwcfg1 & 0x1))
++			num_out_eps++;
++
++		hwcfg1 >>= 2;
++	}
++	return num_out_eps;
++}
++
++/**
++ * This function initializes the DWC_otg controller registers and
++ * prepares the core for device mode or host mode operation.
++ *
++ * @param core_if Programming view of the DWC_otg controller
++ *
++ */
++void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
++{
++	int i = 0;
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	gahbcfg_data_t ahbcfg = {.d32 = 0 };
++	gusbcfg_data_t usbcfg = {.d32 = 0 };
++	gi2cctl_data_t i2cctl = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n",
++                    core_if, global_regs);
++
++	/* Common Initialization */
++	usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++
++	/* Program the ULPI External VBUS bit if needed */
++	usbcfg.b.ulpi_ext_vbus_drv =
++	    (core_if->core_params->phy_ulpi_ext_vbus ==
++	     DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
++
++	/* Set external TS Dline pulsing */
++	usbcfg.b.term_sel_dl_pulse =
++	    (core_if->core_params->ts_dline == 1) ? 1 : 0;
++	DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++	/* Reset the Controller */
++	dwc_otg_core_reset(core_if);
++
++	core_if->adp_enable = core_if->core_params->adp_supp_enable;
++	core_if->power_down = core_if->core_params->power_down;
++	core_if->otg_sts = 0;
++
++	/* Initialize parameters from Hardware configuration registers. */
++	dev_if->num_in_eps = calc_num_in_eps(core_if);
++	dev_if->num_out_eps = calc_num_out_eps(core_if);
++
++	DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
++		    core_if->hwcfg4.b.num_dev_perio_in_ep);
++
++	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
++		dev_if->perio_tx_fifo_size[i] =
++		    DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
++		DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
++			    i, dev_if->perio_tx_fifo_size[i]);
++	}
++
++	for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++		dev_if->tx_fifo_size[i] =
++		    DWC_READ_REG32(&global_regs->dtxfsiz[i]) >> 16;
++		DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
++			    i, dev_if->tx_fifo_size[i]);
++	}
++
++	core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
++	core_if->rx_fifo_size = DWC_READ_REG32(&global_regs->grxfsiz);
++	core_if->nperio_tx_fifo_size =
++	    DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16;
++
++	DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
++	DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
++	DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
++		    core_if->nperio_tx_fifo_size);
++
++	/* This programming sequence needs to happen in FS mode before any other
++	 * programming occurs */
++	if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
++	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
++		/* If FS mode with FS PHY */
++
++		/* core_init() is now called on every switch so only call the
++		 * following for the first time through. */
++		if (!core_if->phy_init_done) {
++			core_if->phy_init_done = 1;
++			DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
++			usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++			usbcfg.b.physel = 1;
++			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++			/* Reset after a PHY select */
++			dwc_otg_core_reset(core_if);
++		}
++
++		/* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.      Also
++		 * do this on HNP Dev/Host mode switches (done in dev_init and
++		 * host_init). */
++		if (dwc_otg_is_host_mode(core_if)) {
++			init_fslspclksel(core_if);
++		} else {
++			init_devspd(core_if);
++		}
++
++		if (core_if->core_params->i2c_enable) {
++			DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
++			/* Program GUSBCFG.OtgUtmifsSel to I2C */
++			usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++			usbcfg.b.otgutmifssel = 1;
++			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++			/* Program GI2CCTL.I2CEn */
++			i2cctl.d32 = DWC_READ_REG32(&global_regs->gi2cctl);
++			i2cctl.b.i2cdevaddr = 1;
++			i2cctl.b.i2cen = 0;
++			DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
++			i2cctl.b.i2cen = 1;
++			DWC_WRITE_REG32(&global_regs->gi2cctl, i2cctl.d32);
++		}
++
++	} /* endif speed == DWC_SPEED_PARAM_FULL */
++	else {
++		/* High speed PHY. */
++		if (!core_if->phy_init_done) {
++			core_if->phy_init_done = 1;
++			/* HS PHY parameters.  These parameters are preserved
++			 * during soft reset so only program the first time.  Do
++			 * a soft reset immediately after setting phyif.  */
++
++			if (core_if->core_params->phy_type == 2) {
++				/* ULPI interface */
++				usbcfg.b.ulpi_utmi_sel = 1;
++				usbcfg.b.phyif = 0;
++				usbcfg.b.ddrsel =
++				    core_if->core_params->phy_ulpi_ddr;
++			} else if (core_if->core_params->phy_type == 1) {
++				/* UTMI+ interface */
++				usbcfg.b.ulpi_utmi_sel = 0;
++				if (core_if->core_params->phy_utmi_width == 16) {
++					usbcfg.b.phyif = 1;
++
++				} else {
++					usbcfg.b.phyif = 0;
++				}
++			} else {
++				DWC_ERROR("FS PHY TYPE\n");
++			}
++			DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++			/* Reset after setting the PHY parameters */
++			dwc_otg_core_reset(core_if);
++		}
++	}
++
++	if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
++	    (core_if->hwcfg2.b.fs_phy_type == 1) &&
++	    (core_if->core_params->ulpi_fs_ls)) {
++		DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
++		usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++		usbcfg.b.ulpi_fsls = 1;
++		usbcfg.b.ulpi_clk_sus_m = 1;
++		DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++	} else {
++		usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++		usbcfg.b.ulpi_fsls = 0;
++		usbcfg.b.ulpi_clk_sus_m = 0;
++		DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++	}
++
++	/* Program the GAHBCFG Register. */
++	switch (core_if->hwcfg2.b.architecture) {
++
++	case DWC_SLAVE_ONLY_ARCH:
++		DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
++		ahbcfg.b.nptxfemplvl_txfemplvl =
++		    DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
++		ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
++		core_if->dma_enable = 0;
++		core_if->dma_desc_enable = 0;
++		break;
++
++	case DWC_EXT_DMA_ARCH:
++		DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
++		{
++			uint8_t brst_sz = core_if->core_params->dma_burst_size;
++			ahbcfg.b.hburstlen = 0;
++			while (brst_sz > 1) {
++				ahbcfg.b.hburstlen++;
++				brst_sz >>= 1;
++			}
++		}
++		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
++		core_if->dma_desc_enable =
++		    (core_if->core_params->dma_desc_enable != 0);
++		break;
++
++	case DWC_INT_DMA_ARCH:
++		DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
++		/* Old value was DWC_GAHBCFG_INT_DMA_BURST_INCR - done for
++		  Host mode ISOC in issue fix - vahrama */
++		/* Broadcom had altered to (1<<3)|(0<<0) - WRESP=1, max 4 beats */
++		ahbcfg.b.hburstlen = (1<<3)|(0<<0);//DWC_GAHBCFG_INT_DMA_BURST_INCR4;
++		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
++		core_if->dma_desc_enable =
++		    (core_if->core_params->dma_desc_enable != 0);
++		break;
++
++	}
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable) {
++			DWC_PRINTF("Using Descriptor DMA mode\n");
++		} else {
++			DWC_PRINTF("Using Buffer DMA mode\n");
++
++		}
++	} else {
++		DWC_PRINTF("Using Slave mode\n");
++		core_if->dma_desc_enable = 0;
++	}
++
++	if (core_if->core_params->ahb_single) {
++		ahbcfg.b.ahbsingle = 1;
++	}
++
++	ahbcfg.b.dmaenable = core_if->dma_enable;
++	DWC_WRITE_REG32(&global_regs->gahbcfg, ahbcfg.d32);
++
++	core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
++
++	core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
++	core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
++	DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
++		   ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
++	DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
++		   ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
++
++	/*
++	 * Program the GUSBCFG register.
++	 */
++	usbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg);
++
++	switch (core_if->hwcfg2.b.op_mode) {
++	case DWC_MODE_HNP_SRP_CAPABLE:
++		usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
++				   DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_SRP_ONLY_CAPABLE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_NO_HNP_SRP_CAPABLE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = 0;
++		break;
++
++	case DWC_MODE_SRP_CAPABLE_DEVICE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = 0;
++		break;
++
++	case DWC_MODE_SRP_CAPABLE_HOST:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
++				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
++		break;
++
++	case DWC_MODE_NO_SRP_CAPABLE_HOST:
++		usbcfg.b.hnpcap = 0;
++		usbcfg.b.srpcap = 0;
++		break;
++	}
++
++	DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
++
++#ifdef CONFIG_USB_DWC_OTG_LPM
++	if (core_if->core_params->lpm_enable) {
++		glpmcfg_data_t lpmcfg = {.d32 = 0 };
++
++		/* To enable LPM support set lpm_cap_en bit */
++		lpmcfg.b.lpm_cap_en = 1;
++
++		/* Make AppL1Res ACK */
++		lpmcfg.b.appl_resp = 1;
++
++		/* Retry 3 times */
++		lpmcfg.b.retry_count = 3;
++
++		DWC_MODIFY_REG32(&core_if->core_global_regs->glpmcfg,
++				 0, lpmcfg.d32);
++
++	}
++#endif
++	if (core_if->core_params->ic_usb_cap) {
++		gusbcfg_data_t gusbcfg = {.d32 = 0 };
++		gusbcfg.b.ic_usb_cap = 1;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gusbcfg,
++				 0, gusbcfg.d32);
++	}
++	{
++		gotgctl_data_t gotgctl = {.d32 = 0 };
++		gotgctl.b.otgver = core_if->core_params->otg_ver;
++		DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, 0,
++				 gotgctl.d32);
++		/* Set OTG version supported */
++		core_if->otg_ver = core_if->core_params->otg_ver;
++		DWC_PRINTF("OTG VER PARAM: %d, OTG VER FLAG: %d\n",
++			   core_if->core_params->otg_ver, core_if->otg_ver);
++	}
++
++
++	/* Enable common interrupts */
++	dwc_otg_enable_common_interrupts(core_if);
++
++	/* Do device or host intialization based on mode during PCD
++	 * and HCD initialization  */
++	if (dwc_otg_is_host_mode(core_if)) {
++		DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
++		core_if->op_state = A_HOST;
++	} else {
++		DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
++		core_if->op_state = B_PERIPHERAL;
++#ifdef DWC_DEVICE_ONLY
++		dwc_otg_core_dev_init(core_if);
++#endif
++	}
++}
++
++/**
++ * This function enables the Device mode interrupts.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
++{
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++
++	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
++
++	/* Disable all interrupts. */
++	DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++	/* Clear any pending interrupts */
++	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Enable the common interrupts */
++	dwc_otg_enable_common_interrupts(core_if);
++
++	/* Enable interrupts */
++	intr_mask.b.usbreset = 1;
++	intr_mask.b.enumdone = 1;
++	/* Disable Disconnect interrupt in Device mode */
++	intr_mask.b.disconnect = 0;
++
++	if (!core_if->multiproc_int_enable) {
++		intr_mask.b.inepintr = 1;
++		intr_mask.b.outepintr = 1;
++	}
++
++	intr_mask.b.erlysuspend = 1;
++
++	if (core_if->en_multiple_tx_fifo == 0) {
++		intr_mask.b.epmismatch = 1;
++	}
++
++	//intr_mask.b.incomplisoout = 1;
++	intr_mask.b.incomplisoin = 1;
++
++/* Enable the ignore frame number for ISOC xfers - MAS */
++/* Disable to support high bandwith ISOC transfers - manukz */
++#if 0
++#ifdef DWC_UTE_PER_IO
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable) {
++			dctl_data_t dctl1 = {.d32 = 0 };
++			dctl1.b.ifrmnum = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, 0, dctl1.d32);
++			DWC_DEBUG("----Enabled Ignore frame number (0x%08x)",
++				  DWC_READ_REG32(&core_if->dev_if->
++						 dev_global_regs->dctl));
++		}
++	}
++#endif
++#endif
++#ifdef DWC_EN_ISOC
++	if (core_if->dma_enable) {
++		if (core_if->dma_desc_enable == 0) {
++			if (core_if->pti_enh_enable) {
++				dctl_data_t dctl = {.d32 = 0 };
++				dctl.b.ifrmnum = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 dev_if->dev_global_regs->dctl,
++						 0, dctl.d32);
++			} else {
++				intr_mask.b.incomplisoin = 1;
++				intr_mask.b.incomplisoout = 1;
++			}
++		}
++	} else {
++		intr_mask.b.incomplisoin = 1;
++		intr_mask.b.incomplisoout = 1;
++	}
++#endif /* DWC_EN_ISOC */
++
++	/** @todo NGS: Should this be a module parameter? */
++#ifdef USE_PERIODIC_EP
++	intr_mask.b.isooutdrop = 1;
++	intr_mask.b.eopframe = 1;
++	intr_mask.b.incomplisoin = 1;
++	intr_mask.b.incomplisoout = 1;
++#endif
++
++	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
++
++	DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
++		    DWC_READ_REG32(&global_regs->gintmsk));
++}
++
++/**
++ * This function initializes the DWC_otg controller registers for
++ * device mode.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ */
++void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	dcfg_data_t dcfg = {.d32 = 0 };
++	depctl_data_t diepctl = {.d32 = 0 };
++	grstctl_t resetctl = {.d32 = 0 };
++	uint32_t rx_fifo_size;
++	fifosize_data_t nptxfifosize;
++	fifosize_data_t txfifosize;
++	dthrctl_data_t dthrctl;
++	fifosize_data_t ptxfifosize;
++	uint16_t rxfsiz, nptxfsiz;
++	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
++	hwcfg3_data_t hwcfg3 = {.d32 = 0 };
++
++	/* Restart the Phy Clock */
++	DWC_WRITE_REG32(core_if->pcgcctl, 0);
++
++	/* Device configuration register */
++	init_devspd(core_if);
++	dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++	dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
++	dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
++	/* Enable Device OUT NAK in case of DDMA mode*/
++	if (core_if->core_params->dev_out_nak) {
++		dcfg.b.endevoutnak = 1;
++	}
++
++	if (core_if->core_params->cont_on_bna) {
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.b.encontonbna = 1;
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
++	}
++
++
++	DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++	/* Configure data FIFO sizes */
++	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
++		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
++			    core_if->total_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
++			    params->dev_rx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
++			    params->dev_nperio_tx_fifo_size);
++
++		/* Rx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++
++#ifdef DWC_UTE_CFI
++		core_if->pwron_rxfsiz = DWC_READ_REG32(&global_regs->grxfsiz);
++		core_if->init_rxfsiz = params->dev_rx_fifo_size;
++#endif
++		rx_fifo_size = params->dev_rx_fifo_size;
++		DWC_WRITE_REG32(&global_regs->grxfsiz, rx_fifo_size);
++
++		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++
++		/** Set Periodic Tx FIFO Mask all bits 0 */
++		core_if->p_tx_msk = 0;
++
++		/** Set Tx FIFO Mask all bits 0 */
++		core_if->tx_msk = 0;
++
++		if (core_if->en_multiple_tx_fifo == 0) {
++			/* Non-periodic Tx FIFO */
++			DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++			nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++			nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
++
++			DWC_WRITE_REG32(&global_regs->gnptxfsiz,
++					nptxfifosize.d32);
++
++			DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++			/**@todo NGS: Fix Periodic FIFO Sizing! */
++			/*
++			 * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
++			 * Indexes of the FIFO size module parameters in the
++			 * dev_perio_tx_fifo_size array and the FIFO size registers in
++			 * the dptxfsiz array run from 0 to 14.
++			 */
++			/** @todo Finish debug of this */
++			ptxfifosize.b.startaddr =
++			    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++			for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
++				ptxfifosize.b.depth =
++				    params->dev_perio_tx_fifo_size[i];
++				DWC_DEBUGPL(DBG_CIL,
++					    "initial dtxfsiz[%d]=%08x\n", i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++						ptxfifosize.d32);
++				DWC_DEBUGPL(DBG_CIL, "new dtxfsiz[%d]=%08x\n",
++					    i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++				ptxfifosize.b.startaddr += ptxfifosize.b.depth;
++			}
++		} else {
++			/*
++			 * Tx FIFOs These FIFOs are numbered from 1 to 15.
++			 * Indexes of the FIFO size module parameters in the
++			 * dev_tx_fifo_size array and the FIFO size registers in
++			 * the dtxfsiz array run from 0 to 14.
++			 */
++
++			/* Non-periodic Tx FIFO */
++			DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++#ifdef DWC_UTE_CFI
++			core_if->pwron_gnptxfsiz =
++			    (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
++			core_if->init_gnptxfsiz =
++			    params->dev_nperio_tx_fifo_size;
++#endif
++			nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
++			nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
++
++			DWC_WRITE_REG32(&global_regs->gnptxfsiz,
++					nptxfifosize.d32);
++
++			DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++				    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++			txfifosize.b.startaddr =
++			    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++
++			for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
++
++				txfifosize.b.depth =
++				    params->dev_tx_fifo_size[i];
++
++				DWC_DEBUGPL(DBG_CIL,
++					    "initial dtxfsiz[%d]=%08x\n",
++					    i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++
++#ifdef DWC_UTE_CFI
++				core_if->pwron_txfsiz[i] =
++				    (DWC_READ_REG32
++				     (&global_regs->dtxfsiz[i]) >> 16);
++				core_if->init_txfsiz[i] =
++				    params->dev_tx_fifo_size[i];
++#endif
++				DWC_WRITE_REG32(&global_regs->dtxfsiz[i],
++						txfifosize.d32);
++
++				DWC_DEBUGPL(DBG_CIL,
++					    "new dtxfsiz[%d]=%08x\n",
++					    i,
++					    DWC_READ_REG32(&global_regs->dtxfsiz
++							   [i]));
++
++				txfifosize.b.startaddr += txfifosize.b.depth;
++			}
++			if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
++				/* Calculating DFIFOCFG for Device mode to include RxFIFO and NPTXFIFO */
++				gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
++				hwcfg3.d32 = DWC_READ_REG32(&global_regs->ghwcfg3);
++				gdfifocfg.b.gdfifocfg = (DWC_READ_REG32(&global_regs->ghwcfg3) >> 16);
++				DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
++				rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
++				nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
++				gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz;
++				DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
++			}
++		}
++
++		/* Flush the FIFOs */
++		dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
++		dwc_otg_flush_rx_fifo(core_if);
++
++		/* Flush the Learning Queue. */
++		resetctl.b.intknqflsh = 1;
++		DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32);
++
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) {
++			core_if->start_predict = 0;
++			for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) {
++				core_if->nextep_seq[i] = 0xff;	// 0xff - EP not active
++			}
++			core_if->nextep_seq[0] = 0;
++			core_if->first_in_nextep_seq = 0;
++			diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
++			diepctl.b.nextep = 0;
++			DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
++
++			/* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */
++			dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++			dcfg.b.epmscnt = 2;
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++			DWC_DEBUGPL(DBG_CILV,"%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++				__func__, core_if->first_in_nextep_seq);
++			for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
++				DWC_DEBUGPL(DBG_CILV, "%2d ", core_if->nextep_seq[i]);
++			}
++			DWC_DEBUGPL(DBG_CILV,"\n");
++		}
++
++		/* Clear all pending Device Interrupts */
++		/** @todo - if the condition needed to be checked
++		 *  or in any case all pending interrutps should be cleared?
++	     */
++		if (core_if->multiproc_int_enable) {
++			for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
++				DWC_WRITE_REG32(&dev_if->
++						dev_global_regs->diepeachintmsk[i], 0);
++			}
++		}
++
++		for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
++			DWC_WRITE_REG32(&dev_if->
++					dev_global_regs->doepeachintmsk[i], 0);
++		}
++
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, 0);
++	} else {
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, 0);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, 0);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, 0);
++	}
++
++	for (i = 0; i <= dev_if->num_in_eps; i++) {
++		depctl_data_t depctl;
++		depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl);
++		if (depctl.b.epena) {
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			depctl.b.snak = 1;
++		} else {
++			depctl.d32 = 0;
++		}
++
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
++
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, 0);
++		DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
++	}
++
++	for (i = 0; i <= dev_if->num_out_eps; i++) {
++		depctl_data_t depctl;
++		depctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl);
++		if (depctl.b.epena) {
++			dctl_data_t dctl = {.d32 = 0 };
++			gintmsk_data_t gintsts = {.d32 = 0 };
++			doepint_data_t doepint = {.d32 = 0 };
++			dctl.b.sgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++			do {
++				dwc_udelay(10);
++				gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			} while (!gintsts.b.goutnakeff);
++			gintsts.d32 = 0;
++			gintsts.b.goutnakeff = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			depctl.b.snak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepctl, depctl.d32);
++			do {
++				dwc_udelay(10);
++				doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++					out_ep_regs[i]->doepint);
++			} while (!doepint.b.epdisabled);
++
++			doepint.b.epdisabled = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->doepint, doepint.d32);
++
++			dctl.d32 = 0;
++			dctl.b.cgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++		} else {
++			depctl.d32 = 0;
++		}
++
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
++
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepdma, 0);
++		DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
++	}
++
++	if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
++		dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
++		dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
++		dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
++
++		dev_if->rx_thr_length = params->rx_thr_length;
++		dev_if->tx_thr_length = params->tx_thr_length;
++
++		dev_if->setup_desc_index = 0;
++
++		dthrctl.d32 = 0;
++		dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
++		dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
++		dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
++		dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
++		dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
++		dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
++
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
++				dthrctl.d32);
++
++		DWC_DEBUGPL(DBG_CIL,
++			    "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
++			    dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
++			    dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
++			    dthrctl.b.rx_thr_len);
++
++	}
++
++	dwc_otg_enable_device_interrupts(core_if);
++
++	{
++		diepmsk_data_t msk = {.d32 = 0 };
++		msk.b.txfifoundrn = 1;
++		if (core_if->multiproc_int_enable) {
++			DWC_MODIFY_REG32(&dev_if->dev_global_regs->
++					 diepeachintmsk[0], msk.d32, msk.d32);
++		} else {
++			DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk,
++					 msk.d32, msk.d32);
++		}
++	}
++
++	if (core_if->multiproc_int_enable) {
++		/* Set NAK on Babble */
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.b.nakonbble = 1;
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
++	}
++
++	if (core_if->snpsid >= OTG_CORE_REV_2_94a) {
++		dctl_data_t dctl = {.d32 = 0 };
++		dctl.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dctl);
++		dctl.b.sftdiscon = 0;
++		DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, dctl.d32);
++	}
++}
++
++/**
++ * This function enables the Host mode interrupts.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if);
++
++	/* Disable all interrupts. */
++	DWC_WRITE_REG32(&global_regs->gintmsk, 0);
++
++	/* Clear any pending interrupts. */
++	DWC_WRITE_REG32(&global_regs->gintsts, 0xFFFFFFFF);
++
++	/* Enable the common interrupts */
++	dwc_otg_enable_common_interrupts(core_if);
++
++	/*
++	 * Enable host mode interrupts without disturbing common
++	 * interrupts.
++	 */
++
++	intr_mask.b.disconnect = 1;
++	intr_mask.b.portintr = 1;
++	intr_mask.b.hcintr = 1;
++
++	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
++}
++
++/**
++ * This function disables the Host Mode interrupts.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ */
++void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
++
++	/*
++	 * Disable host mode interrupts without disturbing common
++	 * interrupts.
++	 */
++	intr_mask.b.sofintr = 1;
++	intr_mask.b.portintr = 1;
++	intr_mask.b.hcintr = 1;
++	intr_mask.b.ptxfempty = 1;
++	intr_mask.b.nptxfempty = 1;
++
++	DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, 0);
++}
++
++/**
++ * This function initializes the DWC_otg controller registers for
++ * host mode.
++ *
++ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
++ * request queues. Host channels are reset to ensure that they are ready for
++ * performing transfers.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ *
++ */
++void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
++{
++	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
++	dwc_otg_host_if_t *host_if = core_if->host_if;
++	dwc_otg_core_params_t *params = core_if->core_params;
++	hprt0_data_t hprt0 = {.d32 = 0 };
++	fifosize_data_t nptxfifosize;
++	fifosize_data_t ptxfifosize;
++	uint16_t rxfsiz, nptxfsiz, hptxfsiz;
++	gdfifocfg_data_t gdfifocfg = {.d32 = 0 };
++	int i;
++	hcchar_data_t hcchar;
++	hcfg_data_t hcfg;
++	hfir_data_t hfir;
++	dwc_otg_hc_regs_t *hc_regs;
++	int num_channels;
++	gotgctl_data_t gotgctl = {.d32 = 0 };
++
++	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
++
++	/* Restart the Phy Clock */
++	DWC_WRITE_REG32(core_if->pcgcctl, 0);
++
++	/* Initialize Host Configuration Register */
++	init_fslspclksel(core_if);
++	if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
++		hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
++		hcfg.b.fslssupp = 1;
++		DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
++
++	}
++
++	/* This bit allows dynamic reloading of the HFIR register
++	 * during runtime. This bit needs to be programmed during
++	 * initial configuration and its value must not be changed
++	 * during runtime.*/
++	if (core_if->core_params->reload_ctl == 1) {
++		hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir);
++		hfir.b.hfirrldctrl = 1;
++		DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32);
++	}
++
++	if (core_if->core_params->dma_desc_enable) {
++		uint8_t op_mode = core_if->hwcfg2.b.op_mode;
++		if (!
++		    (core_if->hwcfg4.b.desc_dma
++		     && (core_if->snpsid >= OTG_CORE_REV_2_90a)
++		     && ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
++			 || (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
++			 || (op_mode ==
++			     DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG)
++			 || (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)
++			 || (op_mode ==
++			     DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
++
++			DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
++				  "Either core version is below 2.90a or "
++				  "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
++				  "To run the driver in Buffer DMA host mode set dma_desc_enable "
++				  "module parameter to 0.\n");
++			return;
++		}
++		hcfg.d32 = DWC_READ_REG32(&host_if->host_global_regs->hcfg);
++		hcfg.b.descdma = 1;
++		DWC_WRITE_REG32(&host_if->host_global_regs->hcfg, hcfg.d32);
++	}
++
++	/* Configure data FIFO sizes */
++	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
++		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
++			    core_if->total_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
++			    params->host_rx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
++			    params->host_nperio_tx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
++			    params->host_perio_tx_fifo_size);
++
++		/* Rx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++		DWC_WRITE_REG32(&global_regs->grxfsiz,
++				params->host_rx_fifo_size);
++		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->grxfsiz));
++
++		/* Non-periodic Tx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->gnptxfsiz));
++		nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
++		nptxfifosize.b.startaddr = params->host_rx_fifo_size;
++		DWC_WRITE_REG32(&global_regs->gnptxfsiz, nptxfifosize.d32);
++		DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->gnptxfsiz));
++
++		/* Periodic Tx FIFO */
++		DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->hptxfsiz));
++		ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
++		ptxfifosize.b.startaddr =
++		    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
++		DWC_WRITE_REG32(&global_regs->hptxfsiz, ptxfifosize.d32);
++		DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
++			    DWC_READ_REG32(&global_regs->hptxfsiz));
++
++		if (core_if->en_multiple_tx_fifo
++		    && core_if->snpsid <= OTG_CORE_REV_2_94a) {
++			/* Global DFIFOCFG calculation for Host mode - include RxFIFO, NPTXFIFO and HPTXFIFO */
++			gdfifocfg.d32 = DWC_READ_REG32(&global_regs->gdfifocfg);
++			rxfsiz = (DWC_READ_REG32(&global_regs->grxfsiz) & 0x0000ffff);
++			nptxfsiz = (DWC_READ_REG32(&global_regs->gnptxfsiz) >> 16);
++			hptxfsiz = (DWC_READ_REG32(&global_regs->hptxfsiz) >> 16);
++			gdfifocfg.b.epinfobase = rxfsiz + nptxfsiz + hptxfsiz;
++			DWC_WRITE_REG32(&global_regs->gdfifocfg, gdfifocfg.d32);
++		}
++	}
++
++	/* TODO - check this */
++	/* Clear Host Set HNP Enable in the OTG Control Register */
++	gotgctl.b.hstsethnpen = 1;
++	DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++	/* Make sure the FIFOs are flushed. */
++	dwc_otg_flush_tx_fifo(core_if, 0x10 /* all TX FIFOs */ );
++	dwc_otg_flush_rx_fifo(core_if);
++
++	/* Clear Host Set HNP Enable in the OTG Control Register */
++	gotgctl.b.hstsethnpen = 1;
++	DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
++
++	if (!core_if->core_params->dma_desc_enable) {
++		/* Flush out any leftover queued requests. */
++		num_channels = core_if->core_params->host_channels;
++
++		for (i = 0; i < num_channels; i++) {
++			hc_regs = core_if->host_if->hc_regs[i];
++			hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++			hcchar.b.chen = 0;
++			hcchar.b.chdis = 1;
++			hcchar.b.epdir = 0;
++			DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		}
++
++		/* Halt all channels to put them into a known state. */
++		for (i = 0; i < num_channels; i++) {
++			int count = 0;
++			hc_regs = core_if->host_if->hc_regs[i];
++			hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++			hcchar.b.chen = 1;
++			hcchar.b.chdis = 1;
++			hcchar.b.epdir = 0;
++			DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++			DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs);
++			do {
++				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++				if (++count > 1000) {
++					DWC_ERROR
++					    ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n",
++					     __func__, i, hcchar.d32, &hc_regs->hcchar);
++					break;
++				}
++				dwc_udelay(1);
++			} while (hcchar.b.chen);
++		}
++	}
++
++	/* Turn on the vbus power. */
++	DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
++	if (core_if->op_state == A_HOST) {
++		hprt0.d32 = dwc_otg_read_hprt0(core_if);
++		DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
++		if (hprt0.b.prtpwr == 0) {
++			hprt0.b.prtpwr = 1;
++			DWC_WRITE_REG32(host_if->hprt0, hprt0.d32);
++		}
++	}
++
++	dwc_otg_enable_host_interrupts(core_if);
++}
++
++/**
++ * Prepares a host channel for transferring packets to/from a specific
++ * endpoint. The HCCHARn register is set up with the characteristics specified
++ * in _hc. Host channel interrupts that may need to be serviced while this
++ * transfer is in progress are enabled.
++ *
++ * @param core_if Programming view of DWC_otg controller
++ * @param hc Information needed to initialize the host channel
++ */
++void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	hcintmsk_data_t hc_intr_mask;
++	hcchar_data_t hcchar;
++	hcsplt_data_t hcsplt;
++
++	uint8_t hc_num = hc->hc_num;
++	dwc_otg_host_if_t *host_if = core_if->host_if;
++	dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
++
++	/* Clear old interrupt conditions for this host channel. */
++	hc_intr_mask.d32 = 0xFFFFFFFF;
++	hc_intr_mask.b.reserved14_31 = 0;
++	DWC_WRITE_REG32(&hc_regs->hcint, hc_intr_mask.d32);
++
++	/* Enable channel interrupts required for this transfer. */
++	hc_intr_mask.d32 = 0;
++	hc_intr_mask.b.chhltd = 1;
++	if (core_if->dma_enable) {
++		/* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
++		if (!core_if->dma_desc_enable)
++			hc_intr_mask.b.ahberr = 1;
++		else {
++			if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++				hc_intr_mask.b.xfercompl = 1;
++		}
++
++		if (hc->error_state && !hc->do_split &&
++		    hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
++			hc_intr_mask.b.ack = 1;
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.datatglerr = 1;
++				if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
++					hc_intr_mask.b.nak = 1;
++				}
++			}
++		}
++	} else {
++		switch (hc->ep_type) {
++		case DWC_OTG_EP_TYPE_CONTROL:
++		case DWC_OTG_EP_TYPE_BULK:
++			hc_intr_mask.b.xfercompl = 1;
++			hc_intr_mask.b.stall = 1;
++			hc_intr_mask.b.xacterr = 1;
++			hc_intr_mask.b.datatglerr = 1;
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.bblerr = 1;
++			} else {
++				hc_intr_mask.b.nak = 1;
++				hc_intr_mask.b.nyet = 1;
++				if (hc->do_ping) {
++					hc_intr_mask.b.ack = 1;
++				}
++			}
++
++			if (hc->do_split) {
++				hc_intr_mask.b.nak = 1;
++				if (hc->complete_split) {
++					hc_intr_mask.b.nyet = 1;
++				} else {
++					hc_intr_mask.b.ack = 1;
++				}
++			}
++
++			if (hc->error_state) {
++				hc_intr_mask.b.ack = 1;
++			}
++			break;
++		case DWC_OTG_EP_TYPE_INTR:
++			hc_intr_mask.b.xfercompl = 1;
++			hc_intr_mask.b.nak = 1;
++			hc_intr_mask.b.stall = 1;
++			hc_intr_mask.b.xacterr = 1;
++			hc_intr_mask.b.datatglerr = 1;
++			hc_intr_mask.b.frmovrun = 1;
++
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.bblerr = 1;
++			}
++			if (hc->error_state) {
++				hc_intr_mask.b.ack = 1;
++			}
++			if (hc->do_split) {
++				if (hc->complete_split) {
++					hc_intr_mask.b.nyet = 1;
++				} else {
++					hc_intr_mask.b.ack = 1;
++				}
++			}
++			break;
++		case DWC_OTG_EP_TYPE_ISOC:
++			hc_intr_mask.b.xfercompl = 1;
++			hc_intr_mask.b.frmovrun = 1;
++			hc_intr_mask.b.ack = 1;
++
++			if (hc->ep_is_in) {
++				hc_intr_mask.b.xacterr = 1;
++				hc_intr_mask.b.bblerr = 1;
++			}
++			break;
++		}
++	}
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, hc_intr_mask.d32);
++
++	/*
++	 * Program the HCCHARn register with the endpoint characteristics for
++	 * the current transfer.
++	 */
++	hcchar.d32 = 0;
++	hcchar.b.devaddr = hc->dev_addr;
++	hcchar.b.epnum = hc->ep_num;
++	hcchar.b.epdir = hc->ep_is_in;
++	hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
++	hcchar.b.eptype = hc->ep_type;
++	hcchar.b.mps = hc->max_packet;
++
++	DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d, Dev Addr %d, EP #%d\n",
++                    __func__, hc->hc_num, hcchar.b.devaddr, hcchar.b.epnum);
++	DWC_DEBUGPL(DBG_HCDV, "	 Is In %d, Is Low Speed %d, EP Type %d, "
++                                "Max Pkt %d, Multi Cnt %d\n",
++                    hcchar.b.epdir, hcchar.b.lspddev, hcchar.b.eptype,
++                    hcchar.b.mps, hcchar.b.multicnt);
++
++	/*
++	 * Program the HCSPLIT register for SPLITs
++	 */
++	hcsplt.d32 = 0;
++	if (hc->do_split) {
++		DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
++			    hc->hc_num,
++			    hc->complete_split ? "CSPLIT" : "SSPLIT");
++		hcsplt.b.compsplt = hc->complete_split;
++		hcsplt.b.xactpos = hc->xact_pos;
++		hcsplt.b.hubaddr = hc->hub_addr;
++		hcsplt.b.prtaddr = hc->port_addr;
++		DWC_DEBUGPL(DBG_HCDV, "\t  comp split %d\n", hc->complete_split);
++		DWC_DEBUGPL(DBG_HCDV, "\t  xact pos %d\n", hc->xact_pos);
++		DWC_DEBUGPL(DBG_HCDV, "\t  hub addr %d\n", hc->hub_addr);
++		DWC_DEBUGPL(DBG_HCDV, "\t  port addr %d\n", hc->port_addr);
++		DWC_DEBUGPL(DBG_HCDV, "\t  is_in %d\n", hc->ep_is_in);
++		DWC_DEBUGPL(DBG_HCDV, "\t  Max Pkt: %d\n", hcchar.b.mps);
++		DWC_DEBUGPL(DBG_HCDV, "\t  xferlen: %d\n", hc->xfer_len);
++	}
++	DWC_WRITE_REG32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
++
++}
++
++/**
++ * Attempts to halt a host channel. This function should only be called in
++ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
++ * normal circumstances in DMA mode, the controller halts the channel when the
++ * transfer is complete or a condition occurs that requires application
++ * intervention.
++ *
++ * In slave mode, checks for a free request queue entry, then sets the Channel
++ * Enable and Channel Disable bits of the Host Channel Characteristics
++ * register of the specified channel to intiate the halt. If there is no free
++ * request queue entry, sets only the Channel Disable bit of the HCCHARn
++ * register to flush requests for this channel. In the latter case, sets a
++ * flag to indicate that the host channel needs to be halted when a request
++ * queue slot is open.
++ *
++ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
++ * HCCHARn register. The controller ensures there is space in the request
++ * queue before submitting the halt request.
++ *
++ * Some time may elapse before the core flushes any posted requests for this
++ * host channel and halts. The Channel Halted interrupt handler completes the
++ * deactivation of the host channel.
++ *
++ * @param core_if Controller register interface.
++ * @param hc Host channel to halt.
++ * @param halt_status Reason for halting the channel.
++ */
++void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
++		     dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
++{
++	gnptxsts_data_t nptxsts;
++	hptxsts_data_t hptxsts;
++	hcchar_data_t hcchar;
++	dwc_otg_hc_regs_t *hc_regs;
++	dwc_otg_core_global_regs_t *global_regs;
++	dwc_otg_host_global_regs_t *host_global_regs;
++
++	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++	global_regs = core_if->core_global_regs;
++	host_global_regs = core_if->host_if->host_global_regs;
++
++	DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
++		   "halt_status = %d\n", halt_status);
++
++	if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
++	    halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
++		/*
++		 * Disable all channel interrupts except Ch Halted. The QTD
++		 * and QH state associated with this transfer has been cleared
++		 * (in the case of URB_DEQUEUE), so the channel needs to be
++		 * shut down carefully to prevent crashes.
++		 */
++		hcintmsk_data_t hcintmsk;
++		hcintmsk.d32 = 0;
++		hcintmsk.b.chhltd = 1;
++		DWC_WRITE_REG32(&hc_regs->hcintmsk, hcintmsk.d32);
++
++		/*
++		 * Make sure no other interrupts besides halt are currently
++		 * pending. Handling another interrupt could cause a crash due
++		 * to the QTD and QH state.
++		 */
++		DWC_WRITE_REG32(&hc_regs->hcint, ~hcintmsk.d32);
++
++		/*
++		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
++		 * even if the channel was already halted for some other
++		 * reason.
++		 */
++		hc->halt_status = halt_status;
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++		if (hcchar.b.chen == 0) {
++			/*
++			 * The channel is either already halted or it hasn't
++			 * started yet. In DMA mode, the transfer may halt if
++			 * it finishes normally or a condition occurs that
++			 * requires driver intervention. Don't want to halt
++			 * the channel again. In either Slave or DMA mode,
++			 * it's possible that the transfer has been assigned
++			 * to a channel, but not started yet when an URB is
++			 * dequeued. Don't want to halt a channel that hasn't
++			 * started yet.
++			 */
++			return;
++		}
++	}
++	if (hc->halt_pending) {
++		/*
++		 * A halt has already been issued for this channel. This might
++		 * happen when a transfer is aborted by a higher level in
++		 * the stack.
++		 */
++#ifdef DEBUG
++		DWC_PRINTF
++		    ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
++		     __func__, hc->hc_num);
++
++#endif
++		return;
++	}
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++
++	/* No need to set the bit in DDMA for disabling the channel */
++	//TODO check it everywhere channel is disabled
++	if (!core_if->core_params->dma_desc_enable)
++		hcchar.b.chen = 1;
++	hcchar.b.chdis = 1;
++
++	if (!core_if->dma_enable) {
++		/* Check for space in the request queue to issue the halt. */
++		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
++			nptxsts.d32 = DWC_READ_REG32(&global_regs->gnptxsts);
++			if (nptxsts.b.nptxqspcavail == 0) {
++				hcchar.b.chen = 0;
++			}
++		} else {
++			hptxsts.d32 =
++			    DWC_READ_REG32(&host_global_regs->hptxsts);
++			if ((hptxsts.b.ptxqspcavail == 0)
++			    || (core_if->queuing_high_bandwidth)) {
++				hcchar.b.chen = 0;
++			}
++		}
++	}
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	hc->halt_status = halt_status;
++
++	if (hcchar.b.chen) {
++		hc->halt_pending = 1;
++		hc->halt_on_queue = 0;
++	} else {
++		hc->halt_on_queue = 1;
++	}
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 hcchar: 0x%08x\n", hcchar.d32);
++	DWC_DEBUGPL(DBG_HCDV, "	 halt_pending: %d\n", hc->halt_pending);
++	DWC_DEBUGPL(DBG_HCDV, "	 halt_on_queue: %d\n", hc->halt_on_queue);
++	DWC_DEBUGPL(DBG_HCDV, "	 halt_status: %d\n", hc->halt_status);
++
++	return;
++}
++
++/**
++ * Clears the transfer state for a host channel. This function is normally
++ * called after a transfer is done and the host channel is being released.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Identifies the host channel to clean up.
++ */
++void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	dwc_otg_hc_regs_t *hc_regs;
++
++	hc->xfer_started = 0;
++
++	/*
++	 * Clear channel interrupt enables and any unhandled channel interrupt
++	 * conditions.
++	 */
++	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++	DWC_WRITE_REG32(&hc_regs->hcintmsk, 0);
++	DWC_WRITE_REG32(&hc_regs->hcint, 0xFFFFFFFF);
++#ifdef DEBUG
++	DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
++#endif
++}
++
++/**
++ * Sets the channel property that indicates in which frame a periodic transfer
++ * should occur. This is always set to the _next_ frame. This function has no
++ * effect on non-periodic transfers.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Identifies the host channel to set up and its properties.
++ * @param hcchar Current value of the HCCHAR register for the specified host
++ * channel.
++ */
++static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
++					 dwc_hc_t * hc, hcchar_data_t * hcchar)
++{
++	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++		hfnum_data_t hfnum;
++		hfnum.d32 =
++		    DWC_READ_REG32(&core_if->host_if->host_global_regs->hfnum);
++
++		/* 1 if _next_ frame is odd, 0 if it's even */
++		hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
++#ifdef DEBUG
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
++		    && !hc->complete_split) {
++			switch (hfnum.b.frnum & 0x7) {
++			case 7:
++				core_if->hfnum_7_samples++;
++				core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
++				break;
++			case 0:
++				core_if->hfnum_0_samples++;
++				core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
++				break;
++			default:
++				core_if->hfnum_other_samples++;
++				core_if->hfnum_other_frrem_accum +=
++				    hfnum.b.frrem;
++				break;
++			}
++		}
++#endif
++	}
++}
++
++#ifdef DEBUG
++void hc_xfer_timeout(void *ptr)
++{
++	hc_xfer_info_t *xfer_info = NULL;
++	int hc_num = 0;
++
++	if (ptr)
++		xfer_info = (hc_xfer_info_t *) ptr;
++
++	if (!xfer_info->hc) {
++		DWC_ERROR("xfer_info->hc = %p\n", xfer_info->hc);
++		return;
++	}
++
++	hc_num = xfer_info->hc->hc_num;
++	DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
++	DWC_WARN("	start_hcchar_val 0x%08x\n",
++		 xfer_info->core_if->start_hcchar_val[hc_num]);
++}
++#endif
++
++void ep_xfer_timeout(void *ptr)
++{
++	ep_xfer_info_t *xfer_info = NULL;
++	int ep_num = 0;
++	dctl_data_t dctl = {.d32 = 0 };
++	gintsts_data_t gintsts = {.d32 = 0 };
++	gintmsk_data_t gintmsk = {.d32 = 0 };
++
++	if (ptr)
++		xfer_info = (ep_xfer_info_t *) ptr;
++
++	if (!xfer_info->ep) {
++		DWC_ERROR("xfer_info->ep = %p\n", xfer_info->ep);
++		return;
++	}
++
++	ep_num = xfer_info->ep->num;
++	DWC_WARN("%s: timeout on endpoit %d\n", __func__, ep_num);
++	/* Put the sate to 2 as it was time outed */
++	xfer_info->state = 2;
++
++	dctl.d32 =
++	    DWC_READ_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl);
++	gintsts.d32 =
++	    DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintsts);
++	gintmsk.d32 =
++	    DWC_READ_REG32(&xfer_info->core_if->core_global_regs->gintmsk);
++
++	if (!gintmsk.b.goutnakeff) {
++		/* Unmask it */
++		gintmsk.b.goutnakeff = 1;
++		DWC_WRITE_REG32(&xfer_info->core_if->core_global_regs->gintmsk,
++				gintmsk.d32);
++
++	}
++
++	if (!gintsts.b.goutnakeff) {
++		dctl.b.sgoutnak = 1;
++	}
++	DWC_WRITE_REG32(&xfer_info->core_if->dev_if->dev_global_regs->dctl,
++			dctl.d32);
++
++}
++
++void set_pid_isoc(dwc_hc_t * hc)
++{
++	/* Set up the initial PID for the transfer. */
++	if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
++		if (hc->ep_is_in) {
++			if (hc->multi_count == 1) {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++			} else if (hc->multi_count == 2) {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
++			} else {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA2;
++			}
++		} else {
++			if (hc->multi_count == 1) {
++				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++			} else {
++				hc->data_pid_start = DWC_OTG_HC_PID_MDATA;
++			}
++		}
++	} else {
++		hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
++	}
++}
++
++/**
++ * This function does the setup for a data transfer for a host channel and
++ * starts the transfer. May be called in either Slave mode or DMA mode. In
++ * Slave mode, the caller must ensure that there is sufficient space in the
++ * request queue and Tx Data FIFO.
++ *
++ * For an OUT transfer in Slave mode, it loads a data packet into the
++ * appropriate FIFO. If necessary, additional data packets will be loaded in
++ * the Host ISR.
++ *
++ * For an IN transfer in Slave mode, a data packet is requested. The data
++ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
++ * additional data packets are requested in the Host ISR.
++ *
++ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
++ * register along with a packet count of 1 and the channel is enabled. This
++ * causes a single PING transaction to occur. Other fields in HCTSIZ are
++ * simply set to 0 since no data transfer occurs in this case.
++ *
++ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
++ * all the information required to perform the subsequent data transfer. In
++ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
++ * controller performs the entire PING protocol, then starts the data
++ * transfer.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Information needed to initialize the host channel. The xfer_len
++ * value may be reduced to accommodate the max widths of the XferSize and
++ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
++ * to reflect the final xfer_len value.
++ */
++void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	uint16_t num_packets;
++	uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
++	uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
++	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++
++	hctsiz.d32 = 0;
++
++	if (hc->do_ping) {
++		if (!core_if->dma_enable) {
++			dwc_otg_hc_do_ping(core_if, hc);
++			hc->xfer_started = 1;
++			return;
++		} else {
++			hctsiz.b.dopng = 1;
++		}
++	}
++
++	if (hc->do_split) {
++		num_packets = 1;
++
++		if (hc->complete_split && !hc->ep_is_in) {
++			/* For CSPLIT OUT Transfer, set the size to 0 so the
++			 * core doesn't expect any data written to the FIFO */
++			hc->xfer_len = 0;
++		} else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
++			hc->xfer_len = hc->max_packet;
++		} else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
++			hc->xfer_len = 188;
++		}
++
++		hctsiz.b.xfersize = hc->xfer_len;
++	} else {
++		/*
++		 * Ensure that the transfer length and packet count will fit
++		 * in the widths allocated for them in the HCTSIZn register.
++		 */
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++			/*
++			 * Make sure the transfer size is no larger than one
++			 * (micro)frame's worth of data. (A check was done
++			 * when the periodic transfer was accepted to ensure
++			 * that a (micro)frame's worth of data can be
++			 * programmed into a channel.)
++			 */
++			uint32_t max_periodic_len =
++			    hc->multi_count * hc->max_packet;
++			if (hc->xfer_len > max_periodic_len) {
++				hc->xfer_len = max_periodic_len;
++			} else {
++			}
++		} else if (hc->xfer_len > max_hc_xfer_size) {
++			/* Make sure that xfer_len is a multiple of max packet size. */
++			hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
++		}
++
++		if (hc->xfer_len > 0) {
++			num_packets =
++			    (hc->xfer_len + hc->max_packet -
++			     1) / hc->max_packet;
++			if (num_packets > max_hc_pkt_count) {
++				num_packets = max_hc_pkt_count;
++				hc->xfer_len = num_packets * hc->max_packet;
++			}
++		} else {
++			/* Need 1 packet for transfer length of 0. */
++			num_packets = 1;
++		}
++
++		if (hc->ep_is_in) {
++			/* Always program an integral # of max packets for IN transfers. */
++			hc->xfer_len = num_packets * hc->max_packet;
++		}
++
++		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++			/*
++			 * Make sure that the multi_count field matches the
++			 * actual transfer length.
++			 */
++			hc->multi_count = num_packets;
++		}
++
++		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++			set_pid_isoc(hc);
++
++		hctsiz.b.xfersize = hc->xfer_len;
++	}
++
++	hc->start_pkt_count = num_packets;
++	hctsiz.b.pktcnt = num_packets;
++	hctsiz.b.pid = hc->data_pid_start;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 Xfer Size: %d\n", hctsiz.b.xfersize);
++	DWC_DEBUGPL(DBG_HCDV, "	 Num Pkts: %d\n", hctsiz.b.pktcnt);
++	DWC_DEBUGPL(DBG_HCDV, "	 Start PID: %d\n", hctsiz.b.pid);
++
++	if (core_if->dma_enable) {
++		dwc_dma_t dma_addr;
++		if (hc->align_buff) {
++			dma_addr = hc->align_buff;
++		} else {
++			dma_addr = ((unsigned long)hc->xfer_buff & 0xffffffff);
++		}
++		DWC_WRITE_REG32(&hc_regs->hcdma, dma_addr);
++	}
++
++	/* Start the split */
++	if (hc->do_split) {
++		hcsplt_data_t hcsplt;
++		hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt);
++		hcsplt.b.spltena = 1;
++		DWC_WRITE_REG32(&hc_regs->hcsplt, hcsplt.d32);
++	}
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.multicnt = hc->multi_count;
++	hc_set_even_odd_frame(core_if, hc, &hcchar);
++#ifdef DEBUG
++	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
++	if (hcchar.b.chdis) {
++		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
++			 __func__, hc->hc_num, hcchar.d32);
++	}
++#endif
++
++	/* Set host channel enable after all other setup is complete. */
++	hcchar.b.chen = 1;
++	hcchar.b.chdis = 0;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	hc->xfer_started = 1;
++	hc->requests++;
++
++	if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
++		/* Load OUT packet into the appropriate Tx FIFO. */
++		dwc_otg_hc_write_packet(core_if, hc);
++	}
++#ifdef DEBUG
++	if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
++                DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n",
++                            hc->hc_num, core_if);//GRAYG
++		core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
++		core_if->hc_xfer_info[hc->hc_num].hc = hc;
++
++		/* Start a timer for this transfer. */
++		DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
++	}
++#endif
++}
++
++/**
++ * This function does the setup for a data transfer for a host channel
++ * and starts the transfer in Descriptor DMA mode.
++ *
++ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
++ * Sets PID and NTD values. For periodic transfers
++ * initializes SCHED_INFO field with micro-frame bitmap.
++ *
++ * Initializes HCDMA register with descriptor list address and CTD value
++ * then starts the transfer via enabling the channel.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param hc Information needed to initialize the host channel.
++ */
++void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	hcdma_data_t hcdma;
++
++	hctsiz.d32 = 0;
++
++	if (hc->do_ping)
++		hctsiz.b_ddma.dopng = 1;
++
++	if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
++		set_pid_isoc(hc);
++
++	/* Packet Count and Xfer Size are not used in Descriptor DMA mode */
++	hctsiz.b_ddma.pid = hc->data_pid_start;
++	hctsiz.b_ddma.ntd = hc->ntd - 1;	/* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
++	hctsiz.b_ddma.schinfo = hc->schinfo;	/* Non-zero only for high-speed interrupt endpoints */
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++	DWC_DEBUGPL(DBG_HCDV, "	 Start PID: %d\n", hctsiz.b.pid);
++	DWC_DEBUGPL(DBG_HCDV, "	 NTD: %d\n", hctsiz.b_ddma.ntd);
++
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	hcdma.d32 = 0;
++	hcdma.b.dma_addr = ((uint32_t) hc->desc_list_addr) >> 11;
++
++	/* Always start from first descriptor. */
++	hcdma.b.ctd = 0;
++	DWC_WRITE_REG32(&hc_regs->hcdma, hcdma.d32);
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.multicnt = hc->multi_count;
++
++#ifdef DEBUG
++	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
++	if (hcchar.b.chdis) {
++		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
++			 __func__, hc->hc_num, hcchar.d32);
++	}
++#endif
++
++	/* Set host channel enable after all other setup is complete. */
++	hcchar.b.chen = 1;
++	hcchar.b.chdis = 0;
++
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++
++	hc->xfer_started = 1;
++	hc->requests++;
++
++#ifdef DEBUG
++	if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR)
++	    && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
++                DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n",
++                            hc->hc_num, core_if);//GRAYG
++		core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
++		core_if->hc_xfer_info[hc->hc_num].hc = hc;
++		/* Start a timer for this transfer. */
++		DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
++	}
++#endif
++
++}
++
++/**
++ * This function continues a data transfer that was started by previous call
++ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
++ * sufficient space in the request queue and Tx Data FIFO. This function
++ * should only be called in Slave mode. In DMA mode, the controller acts
++ * autonomously to complete transfers programmed to a host channel.
++ *
++ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
++ * if there is any data remaining to be queued. For an IN transfer, another
++ * data packet is always requested. For the SETUP phase of a control transfer,
++ * this function does nothing.
++ *
++ * @return 1 if a new request is queued, 0 if no more requests are required
++ * for this transfer.
++ */
++int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++
++	if (hc->do_split) {
++		/* SPLITs always queue just once per channel */
++		return 0;
++	} else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
++		/* SETUPs are queued only once since they can't be NAKed. */
++		return 0;
++	} else if (hc->ep_is_in) {
++		/*
++		 * Always queue another request for other IN transfers. If
++		 * back-to-back INs are issued and NAKs are received for both,
++		 * the driver may still be processing the first NAK when the
++		 * second NAK is received. When the interrupt handler clears
++		 * the NAK interrupt for the first NAK, the second NAK will
++		 * not be seen. So we can't depend on the NAK interrupt
++		 * handler to requeue a NAKed request. Instead, IN requests
++		 * are issued each time this function is called. When the
++		 * transfer completes, the extra requests for the channel will
++		 * be flushed.
++		 */
++		hcchar_data_t hcchar;
++		dwc_otg_hc_regs_t *hc_regs =
++		    core_if->host_if->hc_regs[hc->hc_num];
++
++		hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++		hc_set_even_odd_frame(core_if, hc, &hcchar);
++		hcchar.b.chen = 1;
++		hcchar.b.chdis = 0;
++		DWC_DEBUGPL(DBG_HCDV, "	 IN xfer: hcchar = 0x%08x\n",
++			    hcchar.d32);
++		DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++		hc->requests++;
++		return 1;
++	} else {
++		/* OUT transfers. */
++		if (hc->xfer_count < hc->xfer_len) {
++			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
++			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
++				hcchar_data_t hcchar;
++				dwc_otg_hc_regs_t *hc_regs;
++				hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++				hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++				hc_set_even_odd_frame(core_if, hc, &hcchar);
++			}
++
++			/* Load OUT packet into the appropriate Tx FIFO. */
++			dwc_otg_hc_write_packet(core_if, hc);
++			hc->requests++;
++			return 1;
++		} else {
++			return 0;
++		}
++	}
++}
++
++/**
++ * Starts a PING transfer. This function should only be called in Slave mode.
++ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
++ */
++void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	hcchar_data_t hcchar;
++	hctsiz_data_t hctsiz;
++	dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
++
++	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
++
++	hctsiz.d32 = 0;
++	hctsiz.b.dopng = 1;
++	hctsiz.b.pktcnt = 1;
++	DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32);
++
++	hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
++	hcchar.b.chen = 1;
++	hcchar.b.chdis = 0;
++	DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32);
++}
++
++/*
++ * This function writes a packet into the Tx FIFO associated with the Host
++ * Channel. For a channel associated with a non-periodic EP, the non-periodic
++ * Tx FIFO is written. For a channel associated with a periodic EP, the
++ * periodic Tx FIFO is written. This function should only be called in Slave
++ * mode.
++ *
++ * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
++ * then number of bytes written to the Tx FIFO.
++ */
++void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
++{
++	uint32_t i;
++	uint32_t remaining_count;
++	uint32_t byte_count;
++	uint32_t dword_count;
++
++	uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
++	uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
++
++	remaining_count = hc->xfer_len - hc->xfer_count;
++	if (remaining_count > hc->max_packet) {
++		byte_count = hc->max_packet;
++	} else {
++		byte_count = remaining_count;
++	}
++
++	dword_count = (byte_count + 3) / 4;
++
++	if ((((unsigned long)data_buff) & 0x3) == 0) {
++		/* xfer_buff is DWORD aligned. */
++		for (i = 0; i < dword_count; i++, data_buff++) {
++			DWC_WRITE_REG32(data_fifo, *data_buff);
++		}
++	} else {
++		/* xfer_buff is not DWORD aligned. */
++		for (i = 0; i < dword_count; i++, data_buff++) {
++			uint32_t data;
++			data =
++			    (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
++			     16 | data_buff[3] << 24);
++			DWC_WRITE_REG32(data_fifo, data);
++		}
++	}
++
++	hc->xfer_count += byte_count;
++	hc->xfer_buff += byte_count;
++}
++
++/**
++ * Gets the current USB frame number. This is the frame number from the last
++ * SOF packet.
++ */
++uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
++{
++	dsts_data_t dsts;
++	dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
++
++	/* read current frame/microframe number from DSTS register */
++	return dsts.b.soffn;
++}
++
++/**
++ * Calculates and gets the frame Interval value of HFIR register according PHY
++ * type and speed.The application can modify a value of HFIR register only after
++ * the Port Enable bit of the Host Port Control and Status register
++ * (HPRT.PrtEnaPort) has been set.
++*/
++
++uint32_t calc_frame_interval(dwc_otg_core_if_t * core_if)
++{
++	gusbcfg_data_t usbcfg;
++	hwcfg2_data_t hwcfg2;
++	hprt0_data_t hprt0;
++	int clock = 60;		// default value
++	usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg);
++	hwcfg2.d32 = DWC_READ_REG32(&core_if->core_global_regs->ghwcfg2);
++	hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0);
++	if (!usbcfg.b.physel && usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
++		clock = 60;
++	if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 3)
++		clock = 48;
++	if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
++	    !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
++		clock = 30;
++	if (!usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
++	    !usbcfg.b.ulpi_utmi_sel && !usbcfg.b.phyif)
++		clock = 60;
++	if (usbcfg.b.phylpwrclksel && !usbcfg.b.physel &&
++	    !usbcfg.b.ulpi_utmi_sel && usbcfg.b.phyif)
++		clock = 48;
++	if (usbcfg.b.physel && !usbcfg.b.phyif && hwcfg2.b.fs_phy_type == 2)
++		clock = 48;
++	if (usbcfg.b.physel && hwcfg2.b.fs_phy_type == 1)
++		clock = 48;
++	if (hprt0.b.prtspd == 0)
++		/* High speed case */
++		return 125 * clock;
++	else
++		/* FS/LS case */
++		return 1000 * clock;
++}
++
++/**
++ * This function reads a setup packet from the Rx FIFO into the destination
++ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl)
++ * Interrupt routine when a SETUP packet has been received in Slave mode.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dest Destination buffer for packet data.
++ */
++void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
++{
++	device_grxsts_data_t status;
++	/* Get the 8 bytes of a setup transaction data */
++
++	/* Pop 2 DWORDS off the receive data FIFO into memory */
++	dest[0] = DWC_READ_REG32(core_if->data_fifo[0]);
++	dest[1] = DWC_READ_REG32(core_if->data_fifo[0]);
++	if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++		status.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->grxstsp);
++		DWC_DEBUGPL(DBG_ANY,
++			    "EP:%d BCnt:%d " "pktsts:%x Frame:%d(0x%0x)\n",
++			    status.b.epnum, status.b.bcnt, status.b.pktsts,
++			    status.b.fn, status.b.fn);
++	}
++}
++
++/**
++ * This function enables EP0 OUT to receive SETUP packets and configures EP0
++ * IN for transmitting packets. It is normally called when the
++ * "Enumeration Done" interrupt occurs.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP0 data.
++ */
++void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dsts_data_t dsts;
++	depctl_data_t diepctl;
++	depctl_data_t doepctl;
++	dctl_data_t dctl = {.d32 = 0 };
++
++	ep->stp_rollover = 0;
++	/* Read the Device Status and Endpoint 0 Control registers */
++	dsts.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dsts);
++	diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl);
++	doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl);
++
++	/* Set the MPS of the IN EP based on the enumeration speed */
++	switch (dsts.b.enumspd) {
++	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
++	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
++	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
++		diepctl.b.mps = DWC_DEP0CTL_MPS_64;
++		break;
++	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
++		diepctl.b.mps = DWC_DEP0CTL_MPS_8;
++		break;
++	}
++
++	DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
++
++	/* Enable OUT EP for receive */
++	if (core_if->snpsid <= OTG_CORE_REV_2_94a) {
++	doepctl.b.epena = 1;
++	DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
++	}
++#ifdef VERBOSE
++	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
++		    DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl));
++	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
++		    DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl));
++#endif
++	dctl.b.cgnpinnak = 1;
++
++	DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
++	DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
++		    DWC_READ_REG32(&dev_if->dev_global_regs->dctl));
++
++}
++
++/**
++ * This function activates an EP.  The Device EP control register for
++ * the EP is configured as defined in the ep structure. Note: This
++ * function is not used for EP0.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to activate.
++ */
++void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	depctl_data_t depctl;
++	volatile uint32_t *addr;
++	daint_data_t daintmsk = {.d32 = 0 };
++	dcfg_data_t dcfg;
++	uint8_t i;
++
++	DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
++		    (ep->is_in ? "IN" : "OUT"));
++
++#ifdef DWC_UTE_PER_IO
++	ep->xiso_frame_num = 0xFFFFFFFF;
++	ep->xiso_active_xfers = 0;
++	ep->xiso_queued_xfers = 0;
++#endif
++	/* Read DEPCTLn register */
++	if (ep->is_in == 1) {
++		addr = &dev_if->in_ep_regs[ep->num]->diepctl;
++		daintmsk.ep.in = 1 << ep->num;
++	} else {
++		addr = &dev_if->out_ep_regs[ep->num]->doepctl;
++		daintmsk.ep.out = 1 << ep->num;
++	}
++
++	/* If the EP is already active don't change the EP Control
++	 * register. */
++	depctl.d32 = DWC_READ_REG32(addr);
++	if (!depctl.b.usbactep) {
++		depctl.b.mps = ep->maxpacket;
++		depctl.b.eptype = ep->type;
++		depctl.b.txfnum = ep->tx_fifo_num;
++
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			depctl.b.setd0pid = 1;	// ???
++		} else {
++			depctl.b.setd0pid = 1;
++		}
++		depctl.b.usbactep = 1;
++
++		/* Update nextep_seq array and EPMSCNT in DCFG*/
++		if (!(depctl.b.eptype & 1) && (ep->is_in == 1)) {	// NP IN EP
++			for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++				if (core_if->nextep_seq[i] == core_if->first_in_nextep_seq)
++				break;
++			}
++			core_if->nextep_seq[i] = ep->num;
++			core_if->nextep_seq[ep->num] = core_if->first_in_nextep_seq;
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++			dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg);
++			dcfg.b.epmscnt++;
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
++
++			DWC_DEBUGPL(DBG_PCDV,
++				    "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++				__func__, core_if->first_in_nextep_seq);
++			for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
++				DWC_DEBUGPL(DBG_PCDV, "%2d\n",
++					    core_if->nextep_seq[i]);
++			}
++
++		}
++
++
++		DWC_WRITE_REG32(addr, depctl.d32);
++		DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", DWC_READ_REG32(addr));
++	}
++
++	/* Enable the Interrupt for this EP */
++	if (core_if->multiproc_int_enable) {
++		if (ep->is_in == 1) {
++			diepmsk_data_t diepmsk = {.d32 = 0 };
++			diepmsk.b.xfercompl = 1;
++			diepmsk.b.timeout = 1;
++			diepmsk.b.epdisabled = 1;
++			diepmsk.b.ahberr = 1;
++			diepmsk.b.intknepmis = 1;
++			if (!core_if->en_multiple_tx_fifo && core_if->dma_enable)
++				diepmsk.b.intknepmis = 0;
++			diepmsk.b.txfifoundrn = 1;	//?????
++			if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++				diepmsk.b.nak = 1;
++			}
++
++
++
++/*
++			if (core_if->dma_desc_enable) {
++				diepmsk.b.bna = 1;
++			}
++*/
++/*
++			if (core_if->dma_enable) {
++				doepmsk.b.nak = 1;
++			}
++*/
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->
++					diepeachintmsk[ep->num], diepmsk.d32);
++
++		} else {
++			doepmsk_data_t doepmsk = {.d32 = 0 };
++			doepmsk.b.xfercompl = 1;
++			doepmsk.b.ahberr = 1;
++			doepmsk.b.epdisabled = 1;
++			if (ep->type == DWC_OTG_EP_TYPE_ISOC)
++				doepmsk.b.outtknepdis = 1;
++
++/*
++
++			if (core_if->dma_desc_enable) {
++				doepmsk.b.bna = 1;
++			}
++*/
++/*
++			doepmsk.b.babble = 1;
++			doepmsk.b.nyet = 1;
++			doepmsk.b.nak = 1;
++*/
++			DWC_WRITE_REG32(&dev_if->dev_global_regs->
++					doepeachintmsk[ep->num], doepmsk.d32);
++		}
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->deachintmsk,
++				 0, daintmsk.d32);
++	} else {
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			if (ep->is_in) {
++				diepmsk_data_t diepmsk = {.d32 = 0 };
++				diepmsk.b.nak = 1;
++				DWC_MODIFY_REG32(&dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32);
++			} else {
++				doepmsk_data_t doepmsk = {.d32 = 0 };
++				doepmsk.b.outtknepdis = 1;
++				DWC_MODIFY_REG32(&dev_if->dev_global_regs->doepmsk, 0, doepmsk.d32);
++			}
++		}
++		DWC_MODIFY_REG32(&dev_if->dev_global_regs->daintmsk,
++				 0, daintmsk.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
++		    DWC_READ_REG32(&dev_if->dev_global_regs->daintmsk));
++
++	ep->stall_clear_flag = 0;
++
++	return;
++}
++
++/**
++ * This function deactivates an EP. This is done by clearing the USB Active
++ * EP bit in the Device EP control register. Note: This function is not used
++ * for EP0. EP0 cannot be deactivated.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to deactivate.
++ */
++void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl = {.d32 = 0 };
++	volatile uint32_t *addr;
++	daint_data_t daintmsk = {.d32 = 0 };
++	dcfg_data_t dcfg;
++	uint8_t i = 0;
++
++#ifdef DWC_UTE_PER_IO
++	ep->xiso_frame_num = 0xFFFFFFFF;
++	ep->xiso_active_xfers = 0;
++	ep->xiso_queued_xfers = 0;
++#endif
++
++	/* Read DEPCTLn register */
++	if (ep->is_in == 1) {
++		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
++		daintmsk.ep.in = 1 << ep->num;
++	} else {
++		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
++		daintmsk.ep.out = 1 << ep->num;
++	}
++
++	depctl.d32 = DWC_READ_REG32(addr);
++
++	depctl.b.usbactep = 0;
++
++	/* Update nextep_seq array and EPMSCNT in DCFG*/
++	if (!(depctl.b.eptype & 1) && ep->is_in == 1) {	// NP EP IN
++		for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
++			if (core_if->nextep_seq[i] == ep->num)
++			break;
++		}
++		core_if->nextep_seq[i] = core_if->nextep_seq[ep->num];
++		if (core_if->first_in_nextep_seq == ep->num)
++			core_if->first_in_nextep_seq = i;
++		core_if->nextep_seq[ep->num] = 0xff;
++		depctl.b.nextep = 0;
++		dcfg.d32 =
++		    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dcfg);
++		dcfg.b.epmscnt--;
++		DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
++				dcfg.d32);
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "%s first_in_nextep_seq= %2d; nextep_seq[]:\n",
++				__func__, core_if->first_in_nextep_seq);
++			for (i=0; i <= core_if->dev_if->num_in_eps; i++) {
++				DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]);
++			}
++	}
++
++	if (ep->is_in == 1)
++		depctl.b.txfnum = 0;
++
++	if (core_if->dma_desc_enable)
++		depctl.b.epdis = 1;
++
++	DWC_WRITE_REG32(addr, depctl.d32);
++	depctl.d32 = DWC_READ_REG32(addr);
++	if (core_if->dma_enable && ep->type == DWC_OTG_EP_TYPE_ISOC
++	    && depctl.b.epena) {
++		depctl_data_t depctl = {.d32 = 0};
++		if (ep->is_in) {
++			diepint_data_t diepint = {.d32 = 0};
++
++			depctl.b.snak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepctl, depctl.d32);
++			do {
++				dwc_udelay(10);
++				diepint.d32 =
++				    DWC_READ_REG32(&core_if->
++						   dev_if->in_ep_regs[ep->num]->
++						   diepint);
++			} while (!diepint.b.inepnakeff);
++			diepint.b.inepnakeff = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepint, diepint.d32);
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepctl, depctl.d32);
++			do {
++				dwc_udelay(10);
++				diepint.d32 =
++				    DWC_READ_REG32(&core_if->
++						   dev_if->in_ep_regs[ep->num]->
++						   diepint);
++			} while (!diepint.b.epdisabled);
++			diepint.b.epdisabled = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]->
++					diepint, diepint.d32);
++		} else {
++			dctl_data_t dctl = {.d32 = 0};
++			gintmsk_data_t gintsts = {.d32 = 0};
++			doepint_data_t doepint = {.d32 = 0};
++			dctl.b.sgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->
++					 dctl, 0, dctl.d32);
++			do {
++				dwc_udelay(10);
++				gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
++			} while (!gintsts.b.goutnakeff);
++			gintsts.d32 = 0;
++			gintsts.b.goutnakeff = 1;
++			DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
++
++			depctl.d32 = 0;
++			depctl.b.epdis = 1;
++			depctl.b.snak = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepctl, depctl.d32);
++			do
++			{
++				dwc_udelay(10);
++				doepint.d32 = DWC_READ_REG32(&core_if->dev_if->
++											out_ep_regs[ep->num]->doepint);
++			} while (!doepint.b.epdisabled);
++
++			doepint.b.epdisabled = 1;
++			DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]->doepint, doepint.d32);
++
++			dctl.d32 = 0;
++			dctl.b.cgoutnak = 1;
++			DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32);
++		}
++	}
++
++	/* Disable the Interrupt for this EP */
++	if (core_if->multiproc_int_enable) {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
++				 daintmsk.d32, 0);
++
++		if (ep->is_in == 1) {
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++					diepeachintmsk[ep->num], 0);
++		} else {
++			DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
++					doepeachintmsk[ep->num], 0);
++		}
++	} else {
++		DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->daintmsk,
++				 daintmsk.d32, 0);
++	}
++
++}
++
++/**
++ * This function initializes dma descriptor chain.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	dwc_otg_dev_dma_desc_t *dma_desc;
++	uint32_t offset;
++	uint32_t xfer_est;
++	int i;
++	unsigned maxxfer_local, total_len;
++
++	if (!ep->is_in && ep->type == DWC_OTG_EP_TYPE_INTR &&
++					(ep->maxpacket%4)) {
++		maxxfer_local = ep->maxpacket;
++		total_len = ep->xfer_len;
++	} else {
++		maxxfer_local = ep->maxxfer;
++		total_len = ep->total_len;
++	}
++
++	ep->desc_cnt = (total_len / maxxfer_local) +
++            ((total_len % maxxfer_local) ? 1 : 0);
++
++	if (!ep->desc_cnt)
++		ep->desc_cnt = 1;
++
++	if (ep->desc_cnt > MAX_DMA_DESC_CNT)
++		ep->desc_cnt = MAX_DMA_DESC_CNT;
++
++	dma_desc = ep->desc_addr;
++	if (maxxfer_local == ep->maxpacket) {
++		if ((total_len % maxxfer_local) &&
++				(total_len/maxxfer_local < MAX_DMA_DESC_CNT)) {
++			xfer_est = (ep->desc_cnt - 1) * maxxfer_local +
++					(total_len % maxxfer_local);
++		} else
++			xfer_est = ep->desc_cnt * maxxfer_local;
++	} else
++		xfer_est = total_len;
++	offset = 0;
++	for (i = 0; i < ep->desc_cnt; ++i) {
++		/** DMA Descriptor Setup */
++		if (xfer_est > maxxfer_local) {
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 0;
++			dma_desc->status.b.ioc = 0;
++			dma_desc->status.b.sp = 0;
++			dma_desc->status.b.bytes = maxxfer_local;
++			dma_desc->buf = ep->dma_addr + offset;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			xfer_est -= maxxfer_local;
++			offset += maxxfer_local;
++		} else {
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			if (ep->is_in) {
++				dma_desc->status.b.sp =
++				    (xfer_est %
++				     ep->maxpacket) ? 1 : ((ep->
++							    sent_zlp) ? 1 : 0);
++				dma_desc->status.b.bytes = xfer_est;
++			} else {
++				if (maxxfer_local == ep->maxpacket)
++					dma_desc->status.b.bytes = xfer_est;
++				else
++					dma_desc->status.b.bytes =
++						xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
++			}
++
++			dma_desc->buf = ep->dma_addr + offset;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++		}
++		dma_desc++;
++	}
++}
++/**
++ * This function is called when to write ISOC data into appropriate dedicated
++ * periodic FIFO.
++ */
++static int32_t write_isoc_tx_fifo(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
++{
++	dwc_otg_dev_if_t *dev_if = core_if->dev_if;
++	dwc_otg_dev_in_ep_regs_t *ep_regs;
++	dtxfsts_data_t txstatus = {.d32 = 0 };
++	uint32_t len = 0;
++	int epnum = dwc_ep->num;
++	int dwords;
++
++	DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
++
++	ep_regs = core_if->dev_if->in_ep_regs[epnum];
++
++	len = dwc_ep->xfer_len - dwc_ep->xfer_count;
++
++	if (len > dwc_ep->maxpacket) {
++		len = dwc_ep->maxpacket;
++	}
++
++	dwords = (len + 3) / 4;
++
++	/* While there is space in the queue and space in the FIFO and
++	 * More data to tranfer, Write packets to the Tx FIFO */
++	txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
++
++	while (txstatus.b.txfspcavail > dwords &&
++	       dwc_ep->xfer_count < dwc_ep->xfer_len && dwc_ep->xfer_len != 0) {
++		/* Write the FIFO */
++		dwc_otg_ep_write_packet(core_if, dwc_ep, 0);
++
++		len = dwc_ep->xfer_len - dwc_ep->xfer_count;
++		if (len > dwc_ep->maxpacket) {
++			len = dwc_ep->maxpacket;
++		}
++
++		dwords = (len + 3) / 4;
++		txstatus.d32 =
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts);
++		DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
++			    txstatus.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
++		    DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts));
++
++	return 1;
++}
++/**
++ * This function does the setup for a data transfer for an EP and
++ * starts the transfer. For an IN transfer, the packets will be
++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
++ * the packets are unloaded from the Rx FIFO in the ISR.  the ISR.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ */
++
++void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	deptsiz_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
++	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++		    "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
++		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
++		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
++		    ep->total_len);
++	/* IN endpoint */
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[ep->num];
++
++		gnptxsts_data_t gtxstatus;
++
++		gtxstatus.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
++
++		if (core_if->en_multiple_tx_fifo == 0
++		    && gtxstatus.b.nptxqspcavail == 0 && !core_if->dma_enable) {
++#ifdef DEBUG
++			DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
++#endif
++			return;
++		}
++
++		depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
++
++		if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
++			ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
++				ep->maxxfer : (ep->total_len - ep->xfer_len);
++		else
++			ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len - ep->xfer_len)) ?
++				 MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
++
++
++		/* Zero Length Packet? */
++		if ((ep->xfer_len - ep->xfer_count) == 0) {
++			deptsiz.b.xfersize = 0;
++			deptsiz.b.pktcnt = 1;
++		} else {
++			/* Program the transfer size and packet count
++			 *      as follows: xfersize = N * maxpacket +
++			 *      short_packet pktcnt = N + (short_packet
++			 *      exist ? 1 : 0)
++			 */
++			deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
++			deptsiz.b.pktcnt =
++			    (ep->xfer_len - ep->xfer_count - 1 +
++			     ep->maxpacket) / ep->maxpacket;
++			if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
++				deptsiz.b.pktcnt = MAX_PKT_CNT;
++				deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
++			}
++			if (ep->type == DWC_OTG_EP_TYPE_ISOC)
++				deptsiz.b.mc = deptsiz.b.pktcnt;
++		}
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				if (ep->type != DWC_OTG_EP_TYPE_ISOC)
++					deptsiz.b.mc = 1;
++				DWC_WRITE_REG32(&in_regs->dieptsiz,
++						deptsiz.d32);
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++#ifdef DWC_UTE_CFI
++				/* The descriptor chain should be already initialized by now */
++				if (ep->buff_mode != BM_STANDARD) {
++					DWC_WRITE_REG32(&in_regs->diepdma,
++							ep->descs_dma_addr);
++				} else {
++#endif
++					init_dma_desc_chain(core_if, ep);
++				/** DIEPDMAn Register write */
++					DWC_WRITE_REG32(&in_regs->diepdma,
++							ep->dma_desc_addr);
++#ifdef DWC_UTE_CFI
++				}
++#endif
++			}
++		} else {
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++			if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
++				/**
++				 * Enable the Non-Periodic Tx FIFO empty interrupt,
++				 * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
++				 * the data will be written into the fifo by the ISR.
++				 */
++				if (core_if->en_multiple_tx_fifo == 0) {
++					intr_mask.b.nptxfempty = 1;
++					DWC_MODIFY_REG32
++					    (&core_if->core_global_regs->gintmsk,
++					     intr_mask.d32, intr_mask.d32);
++				} else {
++					/* Enable the Tx FIFO Empty Interrupt for this EP */
++					if (ep->xfer_len > 0) {
++						uint32_t fifoemptymsk = 0;
++						fifoemptymsk = 1 << ep->num;
++						DWC_MODIFY_REG32
++						    (&core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++						     0, fifoemptymsk);
++
++					}
++				}
++			}  else {
++					 write_isoc_tx_fifo(core_if, ep);
++			}
++		}
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			dsts_data_t dsts = {.d32 = 0};
++			if (ep->bInterval == 1) {
++				dsts.d32 =
++				    DWC_READ_REG32(&core_if->dev_if->
++						   dev_global_regs->dsts);
++				ep->frame_num = dsts.b.soffn + ep->bInterval;
++				if (ep->frame_num > 0x3FFF) {
++					ep->frm_overrun = 1;
++					ep->frame_num &= 0x3FFF;
++				} else
++					ep->frm_overrun = 0;
++				if (ep->frame_num & 0x1) {
++					depctl.b.setd1pid = 1;
++				} else {
++					depctl.b.setd0pid = 1;
++				}
++			}
++		}
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++	} else {
++		/* OUT endpoint */
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[ep->num];
++
++		depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
++
++		if (!core_if->dma_desc_enable) {
++			if (ep->maxpacket > ep->maxxfer / MAX_PKT_CNT)
++				ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
++				ep->maxxfer : (ep->total_len - ep->xfer_len);
++                else
++					ep->xfer_len += (MAX_PKT_CNT * ep->maxpacket < (ep->total_len
++					- ep->xfer_len)) ? MAX_PKT_CNT * ep->maxpacket : (ep->total_len - ep->xfer_len);
++		}
++
++		/* Program the transfer size and packet count as follows:
++		 *
++		 *      pktcnt = N
++		 *      xfersize = N * maxpacket
++		 */
++		if ((ep->xfer_len - ep->xfer_count) == 0) {
++			/* Zero Length Packet */
++			deptsiz.b.xfersize = ep->maxpacket;
++			deptsiz.b.pktcnt = 1;
++		} else {
++			deptsiz.b.pktcnt =
++			    (ep->xfer_len - ep->xfer_count +
++			     (ep->maxpacket - 1)) / ep->maxpacket;
++			if (deptsiz.b.pktcnt > MAX_PKT_CNT) {
++				deptsiz.b.pktcnt = MAX_PKT_CNT;
++			}
++			if (!core_if->dma_desc_enable) {
++				ep->xfer_len =
++					deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
++			}
++			deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
++		}
++
++		DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
++			    ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++		if (core_if->dma_enable) {
++			if (!core_if->dma_desc_enable) {
++				DWC_WRITE_REG32(&out_regs->doeptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++#ifdef DWC_UTE_CFI
++				/* The descriptor chain should be already initialized by now */
++				if (ep->buff_mode != BM_STANDARD) {
++					DWC_WRITE_REG32(&out_regs->doepdma,
++							ep->descs_dma_addr);
++				} else {
++#endif
++					/** This is used for interrupt out transfers*/
++					if (!ep->xfer_len)
++						ep->xfer_len = ep->total_len;
++					init_dma_desc_chain(core_if, ep);
++
++					if (core_if->core_params->dev_out_nak) {
++						if (ep->type == DWC_OTG_EP_TYPE_BULK) {
++							deptsiz.b.pktcnt = (ep->total_len +
++								(ep->maxpacket - 1)) / ep->maxpacket;
++							deptsiz.b.xfersize = ep->total_len;
++							/* Remember initial value of doeptsiz */
++							core_if->start_doeptsiz_val[ep->num] = deptsiz.d32;
++							DWC_WRITE_REG32(&out_regs->doeptsiz,
++								deptsiz.d32);
++						}
++					}
++				/** DOEPDMAn Register write */
++					DWC_WRITE_REG32(&out_regs->doepdma,
++							ep->dma_desc_addr);
++#ifdef DWC_UTE_CFI
++				}
++#endif
++			}
++		} else {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		}
++
++		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
++			dsts_data_t dsts = {.d32 = 0};
++			if (ep->bInterval == 1) {
++				dsts.d32 =
++				    DWC_READ_REG32(&core_if->dev_if->
++						   dev_global_regs->dsts);
++				ep->frame_num = dsts.b.soffn + ep->bInterval;
++				if (ep->frame_num > 0x3FFF) {
++					ep->frm_overrun = 1;
++					ep->frame_num &= 0x3FFF;
++				} else
++					ep->frm_overrun = 0;
++
++				if (ep->frame_num & 0x1) {
++					depctl.b.setd1pid = 1;
++				} else {
++					depctl.b.setd0pid = 1;
++				}
++			}
++		}
++
++		/* EP enable */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++
++		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
++
++		DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
++			    DWC_READ_REG32(&out_regs->doepctl),
++			    DWC_READ_REG32(&out_regs->doeptsiz));
++		DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
++			    DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
++					   daintmsk),
++			    DWC_READ_REG32(&core_if->core_global_regs->
++					   gintmsk));
++
++		/* Timer is scheduling only for out bulk transfers for
++		 * "Device DDMA OUT NAK Enhancement" feature to inform user
++		 * about received data payload in case of timeout
++		 */
++		if (core_if->core_params->dev_out_nak) {
++			if (ep->type == DWC_OTG_EP_TYPE_BULK) {
++				core_if->ep_xfer_info[ep->num].core_if = core_if;
++				core_if->ep_xfer_info[ep->num].ep = ep;
++				core_if->ep_xfer_info[ep->num].state = 1;
++
++				/* Start a timer for this transfer. */
++				DWC_TIMER_SCHEDULE(core_if->ep_xfer_timer[ep->num], 10000);
++			}
++		}
++	}
++}
++
++/**
++ * This function setup a zero length transfer in Buffer DMA and
++ * Slave modes for usb requests with zero field set
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to start the transfer on.
++ *
++ */
++void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++
++	depctl_data_t depctl;
++	deptsiz_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
++	DWC_PRINTF("zero length transfer is called\n");
++
++	/* IN endpoint */
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[ep->num];
++
++		depctl.d32 = DWC_READ_REG32(&(in_regs->diepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(in_regs->dieptsiz));
++
++		deptsiz.b.xfersize = 0;
++		deptsiz.b.pktcnt = 1;
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				deptsiz.b.mc = 1;
++				DWC_WRITE_REG32(&in_regs->dieptsiz,
++						deptsiz.d32);
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++			/**
++			 * Enable the Non-Periodic Tx FIFO empty interrupt,
++			 * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode,
++			 * the data will be written into the fifo by the ISR.
++			 */
++			if (core_if->en_multiple_tx_fifo == 0) {
++				intr_mask.b.nptxfempty = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gintmsk,
++						 intr_mask.d32, intr_mask.d32);
++			} else {
++				/* Enable the Tx FIFO Empty Interrupt for this EP */
++				if (ep->xfer_len > 0) {
++					uint32_t fifoemptymsk = 0;
++					fifoemptymsk = 1 << ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 0, fifoemptymsk);
++				}
++			}
++		}
++
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++	} else {
++		/* OUT endpoint */
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[ep->num];
++
++		depctl.d32 = DWC_READ_REG32(&(out_regs->doepctl));
++		deptsiz.d32 = DWC_READ_REG32(&(out_regs->doeptsiz));
++
++		/* Zero Length Packet */
++		deptsiz.b.xfersize = ep->maxpacket;
++		deptsiz.b.pktcnt = 1;
++
++		if (core_if->dma_enable) {
++			if (!core_if->dma_desc_enable) {
++				DWC_WRITE_REG32(&out_regs->doeptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		}
++
++		/* EP enable */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++
++		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
++
++	}
++}
++
++/**
++ * This function does the setup for a data transfer for EP0 and starts
++ * the transfer.  For an IN transfer, the packets will be loaded into
++ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
++ * unloaded from the Rx FIFO in the ISR.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP0 data.
++ */
++void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	deptsiz0_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_dev_dma_desc_t *dma_desc;
++
++	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
++		    "xfer_buff=%p start_xfer_buff=%p \n",
++		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
++		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
++
++	ep->total_len = ep->xfer_len;
++
++	/* IN endpoint */
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[0];
++
++		gnptxsts_data_t gtxstatus;
++
++		if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++			depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
++			if (depctl.b.epena)
++				return;
++		}
++
++		gtxstatus.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
++
++		/* If dedicated FIFO every time flush fifo before enable ep*/
++		if (core_if->en_multiple_tx_fifo && core_if->snpsid >= OTG_CORE_REV_3_00a)
++			dwc_otg_flush_tx_fifo(core_if, ep->tx_fifo_num);
++
++		if (core_if->en_multiple_tx_fifo == 0
++		    && gtxstatus.b.nptxqspcavail == 0
++		    && !core_if->dma_enable) {
++#ifdef DEBUG
++			deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
++			DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
++				    DWC_READ_REG32(&in_regs->diepctl));
++			DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
++				    deptsiz.d32,
++				    deptsiz.b.xfersize, deptsiz.b.pktcnt);
++			DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
++				   gtxstatus.d32);
++#endif
++			return;
++		}
++
++		depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
++		deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
++
++		/* Zero Length Packet? */
++		if (ep->xfer_len == 0) {
++			deptsiz.b.xfersize = 0;
++			deptsiz.b.pktcnt = 1;
++		} else {
++			/* Program the transfer size and packet count
++			 *      as follows: xfersize = N * maxpacket +
++			 *      short_packet pktcnt = N + (short_packet
++			 *      exist ? 1 : 0)
++			 */
++			if (ep->xfer_len > ep->maxpacket) {
++				ep->xfer_len = ep->maxpacket;
++				deptsiz.b.xfersize = ep->maxpacket;
++			} else {
++				deptsiz.b.xfersize = ep->xfer_len;
++			}
++			deptsiz.b.pktcnt = 1;
++
++		}
++		DWC_DEBUGPL(DBG_PCDV,
++			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
++			    deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->dma_enable) {
++			if (core_if->dma_desc_enable == 0) {
++				DWC_WRITE_REG32(&in_regs->dieptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++				dma_desc = core_if->dev_if->in_desc_addr;
++
++				/** DMA Descriptor Setup */
++				dma_desc->status.b.bs = BS_HOST_BUSY;
++				dma_desc->status.b.l = 1;
++				dma_desc->status.b.ioc = 1;
++				dma_desc->status.b.sp =
++				    (ep->xfer_len == ep->maxpacket) ? 0 : 1;
++				dma_desc->status.b.bytes = ep->xfer_len;
++				dma_desc->buf = ep->dma_addr;
++				dma_desc->status.b.sts = 0;
++				dma_desc->status.b.bs = BS_HOST_READY;
++
++				/** DIEPDMA0 Register write */
++				DWC_WRITE_REG32(&in_regs->diepdma,
++						core_if->
++						dev_if->dma_in_desc_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++		}
++
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++		/**
++		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
++		 * data will be written into the fifo by the ISR.
++		 */
++		if (!core_if->dma_enable) {
++			if (core_if->en_multiple_tx_fifo == 0) {
++				intr_mask.b.nptxfempty = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gintmsk,
++						 intr_mask.d32, intr_mask.d32);
++			} else {
++				/* Enable the Tx FIFO Empty Interrupt for this EP */
++				if (ep->xfer_len > 0) {
++					uint32_t fifoemptymsk = 0;
++					fifoemptymsk |= 1 << ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 0, fifoemptymsk);
++				}
++			}
++		}
++	} else {
++		/* OUT endpoint */
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[0];
++
++		depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
++		deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
++
++		/* Program the transfer size and packet count as follows:
++		 *      xfersize = N * (maxpacket + 4 - (maxpacket % 4))
++		 *      pktcnt = N                                                                                      */
++		/* Zero Length Packet */
++		deptsiz.b.xfersize = ep->maxpacket;
++		deptsiz.b.pktcnt = 1;
++		if (core_if->snpsid >= OTG_CORE_REV_3_00a)
++			deptsiz.b.supcnt = 3;
++
++		DWC_DEBUGPL(DBG_PCDV, "len=%d  xfersize=%d pktcnt=%d\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
++
++		if (core_if->dma_enable) {
++			if (!core_if->dma_desc_enable) {
++				DWC_WRITE_REG32(&out_regs->doeptsiz,
++						deptsiz.d32);
++
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++			} else {
++				dma_desc = core_if->dev_if->out_desc_addr;
++
++				/** DMA Descriptor Setup */
++				dma_desc->status.b.bs = BS_HOST_BUSY;
++				if (core_if->snpsid >= OTG_CORE_REV_3_00a) {
++					dma_desc->status.b.mtrf = 0;
++					dma_desc->status.b.sr = 0;
++				}
++				dma_desc->status.b.l = 1;
++				dma_desc->status.b.ioc = 1;
++				dma_desc->status.b.bytes = ep->maxpacket;
++				dma_desc->buf = ep->dma_addr;
++				dma_desc->status.b.sts = 0;
++				dma_desc->status.b.bs = BS_HOST_READY;
++
++				/** DOEPDMA0 Register write */
++				DWC_WRITE_REG32(&out_regs->doepdma,
++						core_if->dev_if->
++						dma_out_desc_addr);
++			}
++		} else {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		}
++
++		/* EP enable */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&(out_regs->doepctl), depctl.d32);
++	}
++}
++
++/**
++ * This function continues control IN transfers started by
++ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
++ * single packet.  NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
++ * bit for the packet count.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP0 data.
++ */
++void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	deptsiz0_data_t deptsiz;
++	gintmsk_data_t intr_mask = {.d32 = 0 };
++	dwc_otg_dev_dma_desc_t *dma_desc;
++
++	if (ep->is_in == 1) {
++		dwc_otg_dev_in_ep_regs_t *in_regs =
++		    core_if->dev_if->in_ep_regs[0];
++		gnptxsts_data_t tx_status = {.d32 = 0 };
++
++		tx_status.d32 =
++		    DWC_READ_REG32(&core_if->core_global_regs->gnptxsts);
++		/** @todo Should there be check for room in the Tx
++		 * Status Queue.  If not remove the code above this comment. */
++
++		depctl.d32 = DWC_READ_REG32(&in_regs->diepctl);
++		deptsiz.d32 = DWC_READ_REG32(&in_regs->dieptsiz);
++
++		/* Program the transfer size and packet count
++		 *      as follows: xfersize = N * maxpacket +
++		 *      short_packet pktcnt = N + (short_packet
++		 *      exist ? 1 : 0)
++		 */
++
++		if (core_if->dma_desc_enable == 0) {
++			deptsiz.b.xfersize =
++			    (ep->total_len - ep->xfer_count) >
++			    ep->maxpacket ? ep->maxpacket : (ep->total_len -
++							     ep->xfer_count);
++			deptsiz.b.pktcnt = 1;
++			if (core_if->dma_enable == 0) {
++				ep->xfer_len += deptsiz.b.xfersize;
++			} else {
++				ep->xfer_len = deptsiz.b.xfersize;
++			}
++			DWC_WRITE_REG32(&in_regs->dieptsiz, deptsiz.d32);
++		} else {
++			ep->xfer_len =
++			    (ep->total_len - ep->xfer_count) >
++			    ep->maxpacket ? ep->maxpacket : (ep->total_len -
++							     ep->xfer_count);
++
++			dma_desc = core_if->dev_if->in_desc_addr;
++
++			/** DMA Descriptor Setup */
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			dma_desc->status.b.sp =
++			    (ep->xfer_len == ep->maxpacket) ? 0 : 1;
++			dma_desc->status.b.bytes = ep->xfer_len;
++			dma_desc->buf = ep->dma_addr;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			/** DIEPDMA0 Register write */
++			DWC_WRITE_REG32(&in_regs->diepdma,
++					core_if->dev_if->dma_in_desc_addr);
++		}
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
++			    deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
++			if (core_if->dma_desc_enable == 0)
++				DWC_WRITE_REG32(&(in_regs->diepdma),
++						(uint32_t) ep->dma_addr);
++		}
++		if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable)
++			depctl.b.nextep = core_if->nextep_seq[ep->num];
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&in_regs->diepctl, depctl.d32);
++
++		/**
++		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
++		 * data will be written into the fifo by the ISR.
++		 */
++		if (!core_if->dma_enable) {
++			if (core_if->en_multiple_tx_fifo == 0) {
++				/* First clear it from GINTSTS */
++				intr_mask.b.nptxfempty = 1;
++				DWC_MODIFY_REG32(&core_if->
++						 core_global_regs->gintmsk,
++						 intr_mask.d32, intr_mask.d32);
++
++			} else {
++				/* Enable the Tx FIFO Empty Interrupt for this EP */
++				if (ep->xfer_len > 0) {
++					uint32_t fifoemptymsk = 0;
++					fifoemptymsk |= 1 << ep->num;
++					DWC_MODIFY_REG32(&core_if->
++							 dev_if->dev_global_regs->dtknqr4_fifoemptymsk,
++							 0, fifoemptymsk);
++				}
++			}
++		}
++	} else {
++		dwc_otg_dev_out_ep_regs_t *out_regs =
++		    core_if->dev_if->out_ep_regs[0];
++
++		depctl.d32 = DWC_READ_REG32(&out_regs->doepctl);
++		deptsiz.d32 = DWC_READ_REG32(&out_regs->doeptsiz);
++
++		/* Program the transfer size and packet count
++		 *      as follows: xfersize = N * maxpacket +
++		 *      short_packet pktcnt = N + (short_packet
++		 *      exist ? 1 : 0)
++		 */
++		deptsiz.b.xfersize = ep->maxpacket;
++		deptsiz.b.pktcnt = 1;
++
++		if (core_if->dma_desc_enable == 0) {
++			DWC_WRITE_REG32(&out_regs->doeptsiz, deptsiz.d32);
++		} else {
++			dma_desc = core_if->dev_if->out_desc_addr;
++
++			/** DMA Descriptor Setup */
++			dma_desc->status.b.bs = BS_HOST_BUSY;
++			dma_desc->status.b.l = 1;
++			dma_desc->status.b.ioc = 1;
++			dma_desc->status.b.bytes = ep->maxpacket;
++			dma_desc->buf = ep->dma_addr;
++			dma_desc->status.b.sts = 0;
++			dma_desc->status.b.bs = BS_HOST_READY;
++
++			/** DOEPDMA0 Register write */
++			DWC_WRITE_REG32(&out_regs->doepdma,
++					core_if->dev_if->dma_out_desc_addr);
++		}
++
++		DWC_DEBUGPL(DBG_PCDV,
++			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
++			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
++			    deptsiz.d32);
++
++		/* Write the DMA register */
++		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
++			if (core_if->dma_desc_enable == 0)
++				DWC_WRITE_REG32(&(out_regs->doepdma),
++						(uint32_t) ep->dma_addr);
++
++		}
++
++		/* EP enable, IN data in FIFO */
++		depctl.b.cnak = 1;
++		depctl.b.epena = 1;
++		DWC_WRITE_REG32(&out_regs->doepctl, depctl.d32);
++
++	}
++}
++
++#ifdef DEBUG
++void dump_msg(const u8 * buf, unsigned int length)
++{
++	unsigned int start, num, i;
++	char line[52], *p;
++
++	if (length >= 512)
++		return;
++	start = 0;
++	while (length > 0) {
++		num = length < 16u ? length : 16u;
++		p = line;
++		for (i = 0; i < num; ++i) {
++			if (i == 8)
++				*p++ = ' ';
++			DWC_SPRINTF(p, " %02x", buf[i]);
++			p += 3;
++		}
++		*p = 0;
++		DWC_PRINTF("%6x: %s\n", start, line);
++		buf += num;
++		start += num;
++		length -= num;
++	}
++}
++#else
++static inline void dump_msg(const u8 * buf, unsigned int length)
++{
++}
++#endif
++
++/**
++ * This function writes a packet into the Tx FIFO associated with the
++ * EP. For non-periodic EPs the non-periodic Tx FIFO is written.  For
++ * periodic EPs the periodic Tx FIFO associated with the EP is written
++ * with all packets for the next micro-frame.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to write packet for.
++ * @param dma Indicates if DMA is being used.
++ */
++void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
++			     int dma)
++{
++	/**
++	 * The buffer is padded to DWORD on a per packet basis in
++	 * slave/dma mode if the MPS is not DWORD aligned. The last
++	 * packet, if short, is also padded to a multiple of DWORD.
++	 *
++	 * ep->xfer_buff always starts DWORD aligned in memory and is a
++	 * multiple of DWORD in length
++	 *
++	 * ep->xfer_len can be any number of bytes
++	 *
++	 * ep->xfer_count is a multiple of ep->maxpacket until the last
++	 *	packet
++	 *
++	 * FIFO access is DWORD */
++
++	uint32_t i;
++	uint32_t byte_count;
++	uint32_t dword_count;
++	uint32_t *fifo;
++	uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
++		    ep);
++	if (ep->xfer_count >= ep->xfer_len) {
++		DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
++		return;
++	}
++
++	/* Find the byte length of the packet either short packet or MPS */
++	if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
++		byte_count = ep->xfer_len - ep->xfer_count;
++	} else {
++		byte_count = ep->maxpacket;
++	}
++
++	/* Find the DWORD length, padded by extra bytes as neccessary if MPS
++	 * is not a multiple of DWORD */
++	dword_count = (byte_count + 3) / 4;
++
++#ifdef VERBOSE
++	dump_msg(ep->xfer_buff, byte_count);
++#endif
++
++	/**@todo NGS Where are the Periodic Tx FIFO addresses
++	 * intialized?	What should this be? */
++
++	fifo = core_if->data_fifo[ep->num];
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
++		    fifo, data_buff, *data_buff, byte_count);
++
++	if (!dma) {
++		for (i = 0; i < dword_count; i++, data_buff++) {
++			DWC_WRITE_REG32(fifo, *data_buff);
++		}
++	}
++
++	ep->xfer_count += byte_count;
++	ep->xfer_buff += byte_count;
++	ep->dma_addr += byte_count;
++}
++
++/**
++ * Set the EP STALL.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to set the stall on.
++ */
++void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	volatile uint32_t *depctl_addr;
++
++	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
++		    (ep->is_in ? "IN" : "OUT"));
++
++	if (ep->is_in == 1) {
++		depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
++		depctl.d32 = DWC_READ_REG32(depctl_addr);
++
++		/* set the disable and stall bits */
++		if (depctl.b.epena) {
++			depctl.b.epdis = 1;
++		}
++		depctl.b.stall = 1;
++		DWC_WRITE_REG32(depctl_addr, depctl.d32);
++	} else {
++		depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
++		depctl.d32 = DWC_READ_REG32(depctl_addr);
++
++		/* set the stall bit */
++		depctl.b.stall = 1;
++		DWC_WRITE_REG32(depctl_addr, depctl.d32);
++	}
++
++	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
++
++	return;
++}
++
++/**
++ * Clear the EP STALL.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param ep The EP to clear stall from.
++ */
++void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
++{
++	depctl_data_t depctl;
++	volatile uint32_t *depctl_addr;
++
++	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
++		    (ep->is_in ? "IN" : "OUT"));
++
++	if (ep->is_in == 1) {
++		depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
++	} else {
++		depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
++	}
++
++	depctl.d32 = DWC_READ_REG32(depctl_addr);
++
++	/* clear the stall bits */
++	depctl.b.stall = 0;
++
++	/*
++	 * USB Spec 9.4.5: For endpoints using data toggle, regardless
++	 * of whether an endpoint has the Halt feature set, a
++	 * ClearFeature(ENDPOINT_HALT) request always results in the
++	 * data toggle being reinitialized to DATA0.
++	 */
++	if (ep->type == DWC_OTG_EP_TYPE_INTR ||
++	    ep->type == DWC_OTG_EP_TYPE_BULK) {
++		depctl.b.setd0pid = 1;	/* DATA0 */
++	}
++
++	DWC_WRITE_REG32(depctl_addr, depctl.d32);
++	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", DWC_READ_REG32(depctl_addr));
++	return;
++}
++
++/**
++ * This function reads a packet from the Rx FIFO into the destination
++ * buffer. To read SETUP data use dwc_otg_read_setup_packet.
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ * @param dest	  Destination buffer for the packet.
++ * @param bytes  Number of bytes to copy to the destination.
++ */
++void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
++			 uint8_t * dest, uint16_t bytes)
++{
++	int i;
++	int word_count = (bytes + 3) / 4;
++
++	volatile uint32_t *fifo = core_if->data_fifo[0];
++	uint32_t *data_buff = (uint32_t *) dest;
++
++	/**
++	 * @todo Account for the case where _dest is not dword aligned. This
++	 * requires reading data from the FIFO into a uint32_t temp buffer,
++	 * then moving it into the data buffer.
++	 */
++
++	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
++		    core_if, dest, bytes);
++
++	for (i = 0; i < word_count; i++, data_buff++) {
++		*data_buff = DWC_READ_REG32(fifo);
++	}
++
++	return;
++}
++
++/**
++ * This functions reads the device registers and prints them
++ *
++ * @param core_if Programming view of DWC_otg controller.
++ */
++void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
++{
++	int i;
++	volatile uint32_t *addr;
++
++	DWC_PRINTF("Device Global Registers\n");
++	addr = &core_if->dev_if->dev_global_regs->dcfg;
++	DWC_PRINTF("DCFG		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->dctl;
++	DWC_PRINTF("DCTL		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)addr, DWC_READ_REG32(addr));
++	addr = &core_if->dev_if->dev_global_regs->dsts;
++	DWC_PRINTF("DSTS		 @0x%08lX : 0x%08X\n",
++		   (unsigned long)add