]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'dwc3-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Sep 2012 20:52:48 +0000 (13:52 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Sep 2012 20:52:48 +0000 (13:52 -0700)
usb: dwc3: patches for v3.7 merge window

Some much needed changes for our dwc3 driver. First there's a
rework on the ep0 handling due to some Silicon issue we uncovered
which affects all users of this IP core (there's a missing
XferNotReady(DATA) event in some conditions). This issue which
show up as a SETUP transfers which wouldn't complete ever and
we would fail TD 7.06 of the Link Layer Test from USB-IF and
Lecroy's USB3 Exerciser.

We also fix a long standing bug regarding EP0 enable sequencing
where we weren't setting a particular bit (Ignore Sequence
Number). Since we never saw any problems caused by that, it
didn't deserve being sent to stable tree.

On this pull request we also fix Burst Size initialization which
should be done only in SuperSpeed and we were mistakenly setting
Burst Size to the maximum value on non-SuperSpeed mode. Again,
since we never saw any problems caused by that, we're not sending
this patch to stable.

There's also a memory ordering fix regarding usage of bitmaps in
dwc3 driver.

You will also find some sparse warnings fix, a fix for missed
isochronous packets when the endpoint is already busy, and a
fix for synchronization delay on dwc3_stop_active_transfer().

1087 files changed:
Documentation/ABI/testing/sysfs-bus-usb
Documentation/ABI/testing/sysfs-platform-ideapad-laptop
Documentation/DocBook/filesystems.tmpl
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
Documentation/devicetree/bindings/regulator/tps6586x.txt
Documentation/devicetree/bindings/usb/platform-uhci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/pxa-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/twlxxxx-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/vt8500-ehci.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfat.txt
Documentation/filesystems/vfs.txt
Documentation/laptops/laptop-mode.txt
Documentation/networking/netconsole.txt
Documentation/pinctrl.txt
Documentation/security/Yama.txt
Documentation/sysctl/vm.txt
Documentation/usb/persist.txt
Documentation/vm/hugetlbpage.txt
Documentation/w1/slaves/w1_therm
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/include/asm/atomic.h
arch/alpha/include/asm/fpu.h
arch/alpha/include/asm/ptrace.h
arch/alpha/include/asm/socket.h
arch/alpha/include/asm/uaccess.h
arch/alpha/include/asm/unistd.h
arch/alpha/include/asm/word-at-a-time.h [new file with mode: 0644]
arch/alpha/kernel/alpha_ksyms.c
arch/alpha/kernel/entry.S
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/process.c
arch/alpha/kernel/systbls.S
arch/alpha/lib/Makefile
arch/alpha/lib/ev6-strncpy_from_user.S [deleted file]
arch/alpha/lib/ev67-strlen_user.S [deleted file]
arch/alpha/lib/strlen_user.S [deleted file]
arch/alpha/lib/strncpy_from_user.S [deleted file]
arch/alpha/mm/fault.c
arch/alpha/oprofile/common.c
arch/arm/Kconfig
arch/arm/boot/dts/imx23.dtsi
arch/arm/boot/dts/imx27-3ds.dts
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53-ard.dts
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6q-sabrelite.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/mxs_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/sched_clock.h
arch/arm/kernel/sched_clock.c
arch/arm/kernel/topology.c
arch/arm/lib/Makefile
arch/arm/lib/io-readsw-armv3.S [new file with mode: 0644]
arch/arm/lib/io-writesw-armv3.S [new file with mode: 0644]
arch/arm/lib/uaccess.S [new file with mode: 0644]
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-imx/clk-imx27.c
arch/arm/mach-imx/clk-imx31.c
arch/arm/mach-imx/clk-imx51-imx53.c
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-kirkwood/Makefile.boot
arch/arm/mach-mxs/Kconfig
arch/arm/mach-mxs/Makefile
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/omap_phy_internal.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-omap2/usb-musb.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-s3c24xx/Kconfig
arch/arm/mach-sa1100/leds-hackkit.c
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/board-harmony-power.c
arch/arm/mach-tegra/devices.c
arch/arm/mach-tegra/devices.h
arch/arm/mach-tegra/include/mach/usb_phy.h [deleted file]
arch/arm/mach-tegra/usb_phy.c [deleted file]
arch/arm/mach-vt8500/bv07.c
arch/arm/mach-vt8500/devices-vt8500.c
arch/arm/mach-vt8500/devices-wm8505.c
arch/arm/mach-vt8500/devices.c
arch/arm/mach-vt8500/devices.h
arch/arm/mach-vt8500/wm8505_7in.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/flush.c
arch/arm/mm/tlb-v7.S
arch/arm/plat-samsung/Kconfig
arch/arm/vfp/vfpmodule.c
arch/blackfin/kernel/setup.c
arch/c6x/Kconfig
arch/c6x/include/asm/cache.h
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/kernel/acpi.c
arch/m68k/Kconfig
arch/m68k/Kconfig.cpu
arch/m68k/apollo/config.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/MC68332.h [deleted file]
arch/m68k/include/asm/apollodma.h [deleted file]
arch/m68k/include/asm/apollohw.h
arch/m68k/include/asm/bitsperlong.h [deleted file]
arch/m68k/include/asm/cputime.h [deleted file]
arch/m68k/include/asm/delay.h
arch/m68k/include/asm/device.h [deleted file]
arch/m68k/include/asm/emergency-restart.h [deleted file]
arch/m68k/include/asm/errno.h [deleted file]
arch/m68k/include/asm/futex.h [deleted file]
arch/m68k/include/asm/ioctl.h [deleted file]
arch/m68k/include/asm/ipcbuf.h [deleted file]
arch/m68k/include/asm/irq_regs.h [deleted file]
arch/m68k/include/asm/kdebug.h [deleted file]
arch/m68k/include/asm/kmap_types.h [deleted file]
arch/m68k/include/asm/kvm_para.h [deleted file]
arch/m68k/include/asm/local.h [deleted file]
arch/m68k/include/asm/local64.h [deleted file]
arch/m68k/include/asm/mac_mouse.h [deleted file]
arch/m68k/include/asm/mcfmbus.h [deleted file]
arch/m68k/include/asm/mman.h [deleted file]
arch/m68k/include/asm/mutex.h [deleted file]
arch/m68k/include/asm/percpu.h [deleted file]
arch/m68k/include/asm/resource.h [deleted file]
arch/m68k/include/asm/sbus.h [deleted file]
arch/m68k/include/asm/scatterlist.h [deleted file]
arch/m68k/include/asm/sections.h [deleted file]
arch/m68k/include/asm/shm.h [deleted file]
arch/m68k/include/asm/siginfo.h [deleted file]
arch/m68k/include/asm/statfs.h [deleted file]
arch/m68k/include/asm/topology.h [deleted file]
arch/m68k/include/asm/types.h [deleted file]
arch/m68k/include/asm/unaligned.h
arch/m68k/include/asm/xor.h [deleted file]
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/vmlinux-nommu.lds
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/m68k/lib/muldi3.c
arch/m68k/mm/init_mm.c
arch/m68k/mm/init_no.c
arch/m68k/platform/68328/head-de2.S
arch/m68k/platform/68328/head-pilot.S
arch/m68k/platform/68328/head-ram.S
arch/m68k/platform/68328/head-rom.S
arch/m68k/platform/68360/head-ram.S
arch/m68k/platform/68360/head-rom.S
arch/m68k/platform/coldfire/head.S
arch/m68k/sun3/prom/init.c
arch/microblaze/include/asm/sections.h
arch/microblaze/kernel/microblaze_ksyms.c
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/vmlinux.lds.S
arch/s390/Kconfig
arch/s390/include/asm/sparsemem.h
arch/s390/include/asm/syscall.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/ptrace.c
arch/s390/kernel/sys_s390.c
arch/sh/drivers/dma/dma-sh.c
arch/sh/include/asm/sections.h
arch/sh/include/cpu-sh2a/cpu/sh7269.h
arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms_32.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/lib/mcount.S
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/mm/init_64.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/include/asm/mce.h
arch/x86/include/asm/perf_event.h
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/acpi/sleep.h
arch/x86/kernel/acpi/wakeup_32.S
arch/x86/kernel/acpi/wakeup_64.S
arch/x86/kernel/alternative.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd_ibs.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/irq.c
arch/x86/kernel/kdebugfs.c
arch/x86/kvm/i8259.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/hugetlbpage.c
arch/x86/mm/pageattr.c
arch/x86/mm/srat.c
arch/x86/platform/efi/efi.c
arch/x86/realmode/rm/Makefile
arch/x86/syscalls/syscall_64.tbl
arch/x86/xen/p2m.c
drivers/acpi/ac.c
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/hwesleep.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwxfsleep.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/fan.c
drivers/acpi/numa.c
drivers/acpi/pci_root.c
drivers/acpi/power.c
drivers/acpi/processor_driver.c
drivers/acpi/sbs.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/thermal.c
drivers/atm/iphase.c
drivers/base/core.c
drivers/base/power/clock_ops.c
drivers/base/power/common.c
drivers/base/power/runtime.c
drivers/bcma/host_pci.c
drivers/bcma/sprom.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/cciss_scsi.c
drivers/block/drbd/drbd_main.c
drivers/block/ub.c [deleted file]
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/hw_random/omap-rng.c
drivers/char/tpm/tpm_tis.c
drivers/clocksource/cs5535-clockevt.c
drivers/cpufreq/pcc-cpufreq.c
drivers/cpuidle/coupled.c
drivers/dma/imx-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/extcon/extcon_gpio.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-langwell.c
drivers/gpio/gpio-msic.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-samsung.c
drivers/gpio/gpio-sch.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_modes.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv84_fifo.c
drivers/gpu/drm/nouveau/nvc0_pm.c
drivers/gpu/drm/nouveau/nvd0_display.c
drivers/gpu/drm/nouveau/nve0_fifo.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_bios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/reg_srcs/r600
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/udl/Kconfig
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/udl/udl_modeset.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/vga/vga_switcheroo.c
drivers/hwmon/coretemp.c
drivers/hwmon/w83627hf.c
drivers/i2c/busses/i2c-diolan-u2c.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-tegra.c
drivers/idle/intel_idle.c
drivers/iio/frequency/adf4350.c
drivers/iio/light/adjd_s311.c
drivers/iio/light/lm3533-als.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/amso1100/c2_rnic.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_sd7220.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/touchscreen/eeti_ts.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/exynos-iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/tegra-smmu.c
drivers/isdn/isdnloop/isdnloop.c
drivers/isdn/mISDN/layer2.c
drivers/leds/led-triggers.c
drivers/leds/leds-lp8788.c
drivers/leds/leds-renesas-tpu.c
drivers/md/md.c
drivers/md/raid10.c
drivers/md/raid10.h
drivers/media/dvb/siano/smsusb.c
drivers/media/radio/radio-shark.c
drivers/media/radio/radio-shark2.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/rc/Kconfig
drivers/media/video/gspca/jl2005bcd.c
drivers/media/video/gspca/spca506.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_mediabus.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/v4l2-ioctl.c
drivers/mfd/Kconfig
drivers/mfd/asic3.c
drivers/mfd/ezx-pcap.c
drivers/misc/mei/interrupt.c
drivers/misc/mei/main.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/misc/ti-st/st_ll.c
drivers/mtd/maps/uclinux.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/omap2.c
drivers/net/appletalk/cops.c
drivers/net/appletalk/ltpc.c
drivers/net/bonding/bond_main.c
drivers/net/cris/eth_v10.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
drivers/net/ethernet/freescale/fs_enet/mii-fec.c
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/icm.c
drivers/net/ethernet/mellanox/mlx4/icm.h
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/mellanox/mlx4/profile.c
drivers/net/ethernet/mellanox/mlx4/sense.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/renesas/Kconfig
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/rndis_filter.c
drivers/net/irda/bfin_sir.c
drivers/net/irda/ks959-sir.c
drivers/net/irda/ksdazzle-sir.c
drivers/net/macvtap.c
drivers/net/netconsole.c
drivers/net/phy/mdio-mux-gpio.c
drivers/net/phy/mdio-mux.c
drivers/net/ppp/pptp.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/cdc-phonet.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/sierra_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/wan/dscc4.c
drivers/net/wimax/i2400m/fw.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/of/base.c
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pinctrl/core.c
drivers/pinctrl/pinctrl-imx23.c
drivers/pinctrl/pinctrl-imx28.c
drivers/pinctrl/pinctrl-imx51.c
drivers/pinctrl/pinctrl-nomadik-db8500.c
drivers/pinctrl/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-sirf.c
drivers/pinctrl/pinctrl-u300.c
drivers/platform/x86/Kconfig
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/fujitsu-tablet.c
drivers/platform/x86/hdaps.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/toshiba_bluetooth.c
drivers/platform/x86/xo15-ebook.c
drivers/pwm/Kconfig
drivers/pwm/core.c
drivers/pwm/pwm-samsung.c
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-vt8500.c
drivers/rapidio/devices/tsi721.c
drivers/regulator/ab3100.c
drivers/regulator/anatop-regulator.c
drivers/regulator/core.c
drivers/regulator/gpio-regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/tps6586x-regulator.c
drivers/regulator/twl-regulator.c
drivers/rtc/interface.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-rs5c348.c
drivers/s390/char/sclp_sdias.c
drivers/sh/intc/core.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-pl022.c
drivers/spi/spi-s3c64xx.c
drivers/staging/ccg/Kconfig
drivers/staging/ccg/Makefile
drivers/staging/ccg/ccg.c
drivers/staging/ccg/composite.c [new file with mode: 0644]
drivers/staging/ccg/composite.h [new file with mode: 0644]
drivers/staging/ccg/config.c [new file with mode: 0644]
drivers/staging/ccg/epautoconf.c [new file with mode: 0644]
drivers/staging/ccg/f_acm.c [new file with mode: 0644]
drivers/staging/ccg/f_fs.c [new file with mode: 0644]
drivers/staging/ccg/f_mass_storage.c [new file with mode: 0644]
drivers/staging/ccg/f_rndis.c [new file with mode: 0644]
drivers/staging/ccg/gadget_chips.h [new file with mode: 0644]
drivers/staging/ccg/ndis.h [new file with mode: 0644]
drivers/staging/ccg/rndis.c [new file with mode: 0644]
drivers/staging/ccg/rndis.h [new file with mode: 0644]
drivers/staging/ccg/storage_common.c [new file with mode: 0644]
drivers/staging/ccg/u_ether.c [new file with mode: 0644]
drivers/staging/ccg/u_ether.h [new file with mode: 0644]
drivers/staging/ccg/u_serial.c [new file with mode: 0644]
drivers/staging/ccg/u_serial.h [new file with mode: 0644]
drivers/staging/ccg/usbstring.c [new file with mode: 0644]
drivers/staging/comedi/drivers.c
drivers/staging/comedi/drivers/adv_pci1710.c
drivers/staging/comedi/drivers/adv_pci1723.c
drivers/staging/comedi/drivers/adv_pci_dio.c
drivers/staging/comedi/drivers/daqboard2000.c
drivers/staging/comedi/drivers/dt3000.c
drivers/staging/comedi/drivers/rtd520.c
drivers/staging/comedi/drivers/usbdux.c
drivers/staging/comedi/drivers/usbduxfast.c
drivers/staging/comedi/drivers/usbduxsigma.c
drivers/staging/csr/Kconfig
drivers/staging/iio/adc/ad7192.c
drivers/staging/iio/adc/ad7298_ring.c
drivers/staging/iio/adc/ad7780.c
drivers/staging/iio/adc/ad7793.c
drivers/staging/keucr/usb.c
drivers/staging/usbip/usbip_common.c
drivers/staging/vt6656/main_usb.c
drivers/staging/winbond/wbusb.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tcm_fc.h
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_sess.c
drivers/tty/serial/Kconfig
drivers/tty/serial/ifx6x60.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/pmac_zilog.c
drivers/usb/Kconfig
drivers/usb/atm/ueagle-atm.c
drivers/usb/chipidea/Kconfig
drivers/usb/class/cdc-acm.c
drivers/usb/core/config.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/endpoint.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/usb-acpi.c
drivers/usb/core/usb.h
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/early/ehci-dbgp.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/acm_ms.c
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/audio.c
drivers/usb/gadget/bcm63xx_udc.c [new file with mode: 0644]
drivers/usb/gadget/cdc2.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/config.c
drivers/usb/gadget/dbgp.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_hid.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_midi.c
drivers/usb/gadget/f_ncm.c
drivers/usb/gadget/f_sourcesink.c
drivers/usb/gadget/f_subset.c
drivers/usb/gadget/f_uac2.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/g_ffs.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/hid.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lpc32xx_udc.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/mass_storage.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/ncm.c
drivers/usb/gadget/nokia.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa25x_udc.h
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/rndis.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/tcm_usb_gadget.c
drivers/usb/gadget/tcm_usb_gadget.h
drivers/usb/gadget/u_ether.c
drivers/usb/gadget/udc-core.c
drivers/usb/gadget/usbstring.c
drivers/usb/gadget/webcam.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-cns3xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/ehci-grlib.c
drivers/usb/host/ehci-ixp4xx.c
drivers/usb/host/ehci-ls1x.c
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sead3.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci-vt8500.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/fhci-sched.c
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/ohci-nxp.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-xls.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-platform.c [new file with mode: 0644]
drivers/usb/host/whci/hcd.c
drivers/usb/host/whci/qset.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/emi62.c
drivers/usb/misc/legousbtower.c
drivers/usb/musb/Kconfig
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/tusb6010.c
drivers/usb/otg/Kconfig
drivers/usb/otg/fsl_otg.c
drivers/usb/otg/mxs-phy.c
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/otg/otg.c
drivers/usb/otg/twl4030-usb.c
drivers/usb/otg/twl6030-usb.c
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/isp1301.c
drivers/usb/phy/mv_u3d_phy.c [new file with mode: 0644]
drivers/usb/phy/mv_u3d_phy.h [new file with mode: 0644]
drivers/usb/phy/omap-usb2.c [new file with mode: 0644]
drivers/usb/phy/tegra_usb_phy.c [new file with mode: 0644]
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/serial/bus.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/ipw.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/usb-wwan.h
drivers/usb/serial/usb_wwan.c
drivers/usb/storage/Kconfig
drivers/usb/storage/Makefile
drivers/usb/storage/alauda.c
drivers/usb/storage/cypress_atacb.c
drivers/usb/storage/datafab.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/storage/freecom.c
drivers/usb/storage/isd200.c
drivers/usb/storage/jumpshot.c
drivers/usb/storage/karma.c
drivers/usb/storage/libusual.c [deleted file]
drivers/usb/storage/onetouch.c
drivers/usb/storage/realtek_cr.c
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr55.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/storage/usual-tables.c
drivers/usb/wusbcore/security.c
drivers/usb/wusbcore/wa-hc.c
drivers/vfio/vfio.c
drivers/vhost/Kconfig
drivers/vhost/Kconfig.tcm [new file with mode: 0644]
drivers/vhost/Makefile
drivers/vhost/tcm_vhost.c [new file with mode: 0644]
drivers/vhost/tcm_vhost.h [new file with mode: 0644]
drivers/video/console/fbcon.c
drivers/w1/slaves/w1_therm.c
drivers/w1/w1_family.h
drivers/zorro/zorro.c
fs/autofs4/expire.c
fs/bio.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/ceph/debugfs.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/compat.c
fs/eventpoll.c
fs/exofs/inode.c
fs/exofs/ore.c
fs/exofs/super.c
fs/ext3/inode.c
fs/ext3/super.c
fs/ext4/balloc.c
fs/ext4/bitmap.c
fs/ext4/extents.c
fs/ext4/inode.c
fs/ext4/super.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/meta_io.c
fs/hfs/mdb.c
fs/jbd/journal.c
fs/jbd2/journal.c
fs/namei.c
fs/nfs/Makefile
fs/nfs/client.c
fs/nfs/idmap.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4super.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/super.c
fs/nfs/write.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.h
fs/open.c
fs/super.c
fs/ubifs/file.c
fs/ubifs/super.c
include/acpi/acpixf.h
include/acpi/actypes.h
include/asm-generic/mutex-xchg.h
include/drm/drm_crtc.h
include/drm/drm_pciids.h
include/drm/radeon_drm.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/backing-dev.h
include/linux/bcd.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/can.h
include/linux/compaction.h
include/linux/efi.h
include/linux/fs.h
include/linux/fsl_devices.h
include/linux/ftrace_event.h
include/linux/fuse.h
include/linux/hardirq.h
include/linux/if_team.h
include/linux/iio/frequency/adf4350.h
include/linux/input/eeti_ts.h
include/linux/iommu.h
include/linux/ipv6.h
include/linux/irq.h
include/linux/jbd2.h
include/linux/jiffies.h
include/linux/kdb.h
include/linux/kref.h
include/linux/mfd/ezx-pcap.h
include/linux/netdevice.h
include/linux/netfilter/nf_conntrack_sip.h
include/linux/netpoll.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/of.h
include/linux/perf_event.h
include/linux/pinctrl/consumer.h
include/linux/sched.h
include/linux/security.h
include/linux/string.h
include/linux/timex.h
include/linux/topology.h
include/linux/usb.h
include/linux/usb/ch11.h
include/linux/usb/composite.h
include/linux/usb/ehci_pdriver.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/nop-usb-xceiv.h [new file with mode: 0644]
include/linux/usb/ohci_pdriver.h
include/linux/usb/omap_usb.h [new file with mode: 0644]
include/linux/usb/otg.h
include/linux/usb/phy.h [new file with mode: 0644]
include/linux/usb/phy_companion.h [new file with mode: 0644]
include/linux/usb/quirks.h
include/linux/usb/tegra_usb_phy.h [new file with mode: 0644]
include/linux/usb_usual.h
include/linux/usbdevice_fs.h
include/linux/writeback.h
include/net/cfg80211.h
include/net/codel.h
include/net/dst.h
include/net/inet_connection_sock.h
include/net/inet_sock.h
include/net/ip.h
include/net/llc.h
include/net/scm.h
include/net/sock.h
include/net/tcp.h
include/net/xfrm.h
include/sound/pcm.h
include/target/target_core_base.h
include/trace/events/sched.h
include/trace/ftrace.h
init/main.c
ipc/mqueue.c
kernel/audit_tree.c
kernel/debug/kdb/kdb_debugger.c
kernel/debug/kdb/kdb_io.c
kernel/debug/kdb/kdb_main.c
kernel/events/callchain.c
kernel/events/core.c
kernel/events/internal.h
kernel/futex.c
kernel/irq/manage.c
kernel/power/suspend.c
kernel/printk.c
kernel/sched/core.c
kernel/sched/cpupri.c
kernel/sched/fair.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stop_task.c
kernel/task_work.c
kernel/time/jiffies.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/timer.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_syscalls.c
kernel/trace/trace_uprobe.c
kernel/watchdog.c
lib/bcd.c
mm/backing-dev.c
mm/compaction.c
mm/internal.h
mm/mmap.c
mm/page-writeback.c
mm/page_alloc.c
net/8021q/vlan_dev.c
net/atm/common.c
net/atm/pvc.c
net/batman-adv/gateway_client.c
net/batman-adv/translation-table.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/bridge/br_device.c
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_private.h
net/caif/chnl_net.c
net/ceph/ceph_common.c
net/ceph/debugfs.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/core/dev.c
net/core/dst.c
net/core/netpoll.c
net/core/netprio_cgroup.c
net/core/scm.c
net/core/sock.c
net/dccp/ccid.h
net/dccp/ccids/ccid3.c
net/ipv4/fib_trie.c
net/ipv4/inet_connection_sock.c
net/ipv4/ip_output.c
net/ipv4/netfilter/nf_nat_sip.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/proc.c
net/ipv6/tcp_ipv6.c
net/ipv6/xfrm6_policy.c
net/l2tp/l2tp_ip6.c
net/llc/af_llc.c
net/llc/llc_input.c
net/llc/llc_station.c
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/scan.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_sip.c
net/netlink/af_netlink.c
net/packet/af_packet.c
net/sched/act_gact.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_pedit.c
net/sched/act_simple.c
net/sched/sch_qfq.c
net/socket.c
net/unix/af_unix.c
net/wireless/core.c
net/wireless/core.h
net/wireless/reg.c
net/wireless/util.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
scripts/checkpatch.pl
scripts/decodecode
scripts/kernel-doc
security/yama/yama_lsm.c
sound/arm/pxa2xx-ac97.c
sound/atmel/abdac.c
sound/atmel/ac97c.c
sound/core/sgbuf.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/pcsp/pcsp.c
sound/isa/als100.c
sound/oss/sb_audio.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/ctxfi/ctatc.c
sound/pci/emu10k1/memory.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/lx6464es/lx6464es.c
sound/pci/rme9652/hdspm.c
sound/pci/sis7019.c
sound/ppc/powermac.c
sound/ppc/snd_ps3.c
sound/soc/blackfin/bf6xx-sport.c
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/imx-ssi.c
sound/soc/mxs/Kconfig
sound/soc/mxs/mxs-saif.c
sound/soc/omap/mcbsp.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-pcm.c
sound/soc/samsung/pcm.c
sound/soc/soc-core.c
sound/soc/soc-jack.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_i2s.c
sound/soc/ux500/ux500_msp_i2s.h
sound/usb/endpoint.c
sound/usb/pcm.c
tools/perf/Makefile
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/intlist.c [new file with mode: 0644]
tools/perf/util/intlist.h [new file with mode: 0644]
tools/perf/util/parse-events-test.c
tools/perf/util/parse-options.c
tools/perf/util/python.c
tools/perf/util/rblist.c [new file with mode: 0644]
tools/perf/util/rblist.h [new file with mode: 0644]
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/strlist.c
tools/perf/util/strlist.h
tools/perf/util/symbol.c
tools/perf/util/target.c
tools/usb/testusb.c

index 5f75f8f7df341380d8bef013ad445ae509083916..13f3eeee1599a68f4400cdb7f4f81c59924f2782 100644 (file)
@@ -220,3 +220,34 @@ Description:
                If the device doesn't support LTM, the file will read "no".
                The file will be present for all speeds of USB devices, and will
                always read "no" for USB 1.1 and USB 2.0 devices.
+
+What:          /sys/bus/usb/devices/.../(hub interface)/portX
+Date:          August 2012
+Contact:       Lan Tianyu <tianyu.lan@intel.com>
+Description:
+               The /sys/bus/usb/devices/.../(hub interface)/portX
+               is usb port device's sysfs directory.
+
+What:          /sys/bus/usb/devices/.../(hub interface)/portX/control
+Date:          August 2012
+Contact:       Lan Tianyu <tianyu.lan@intel.com>
+Description:
+               The /sys/bus/usb/devices/.../(hub interface)/portX/control
+               attribute allows user space to control the power policy on
+               the usb port.
+
+               All ports have one of the following two values for control
+               "on" - port power must be on.
+               "off" - port power must be off.
+
+What:          /sys/bus/usb/devices/.../(hub interface)/portX/state
+Date:          August 2012
+Contact:       Lan Tianyu <tianyu.lan@intel.com>
+Description:
+               The /sys/bus/usb/devices/.../(hub interface)/portX/state
+               attribute allows user space to check hub port's power state.
+
+               All ports have three following states
+               "on"      -    port power on
+               "off"     -    port power off
+               "error"   -    can't get the hub port's power state
index 814b01354c414caf71337d115b41fc92c89769b8..b31e782bd9850628f77f683ba0f87a5ab6d169ae 100644 (file)
@@ -5,4 +5,15 @@ Contact:       "Ike Panhc <ike.pan@canonical.com>"
 Description:
                Control the power of camera module. 1 means on, 0 means off.
 
+What:          /sys/devices/platform/ideapad/fan_mode
+Date:          June 2012
+KernelVersion: 3.6
+Contact:       "Maxim Mikityanskiy <maxtram95@gmail.com>"
+Description:
+               Change fan mode
+               There are four available modes:
+                       * 0 -> Super Silent Mode
+                       * 1 -> Standard Mode
+                       * 2 -> Dust Cleaning
+                       * 4 -> Efficient Thermal Dissipation Mode
 
index 3fca32c41927130dae636a93504d7d8aacdee90e..25b58efd955dd2bebf2d716aea851fe283f792c1 100644 (file)
@@ -224,8 +224,8 @@ all your transactions.
 </para>
 
 <para>
-Then at umount time , in your put_super() (2.4) or write_super() (2.5)
-you can then call journal_destroy() to clean up your in-core journal object.
+Then at umount time , in your put_super() you can then call journal_destroy()
+to clean up your in-core journal object.
 </para>
 
 <para>
index 720395127904574b69db6dd2b042f46b3d14901b..701138f1209de10ae439aff4da056803fbb79713 100644 (file)
@@ -125,7 +125,7 @@ the structure refers to a radio tuner the
 <constant>V4L2_TUNER_CAP_NORM</constant> flags can't be used.</para>
 <para>If multiple frequency bands are supported, then
 <structfield>capability</structfield> is the union of all
-<structfield>capability></structfield> fields of each &v4l2-frequency-band;.
+<structfield>capability</structfield> fields of each &v4l2-frequency-band;.
 </para></entry>
          </row>
          <row>
index d156e1b5db1233c5ffdb2c0f54e1f5bd6234da34..da80c2ae0915e338af82e995ad64d78fdce82add 100644 (file)
@@ -9,9 +9,9 @@ Required properties:
 - regulators: list of regulators provided by this controller, must have
   property "regulator-compatible" to match their hardware counterparts:
   sm[0-2], ldo[0-9] and ldo_rtc
-- sm0-supply: The input supply for the SM0.
-- sm1-supply: The input supply for the SM1.
-- sm2-supply: The input supply for the SM2.
+- vin-sm0-supply: The input supply for the SM0.
+- vin-sm1-supply: The input supply for the SM1.
+- vin-sm2-supply: The input supply for the SM2.
 - vinldo01-supply: The input supply for the LDO1 and LDO2
 - vinldo23-supply: The input supply for the LDO2 and LDO3
 - vinldo4-supply: The input supply for the LDO4
@@ -30,9 +30,9 @@ Example:
                #gpio-cells = <2>;
                gpio-controller;
 
-               sm0-supply = <&some_reg>;
-               sm1-supply = <&some_reg>;
-               sm2-supply = <&some_reg>;
+               vin-sm0-supply = <&some_reg>;
+               vin-sm1-supply = <&some_reg>;
+               vin-sm2-supply = <&some_reg>;
                vinldo01-supply = <...>;
                vinldo23-supply = <...>;
                vinldo4-supply = <...>;
diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt
new file mode 100644 (file)
index 0000000..91477d6
--- /dev/null
@@ -0,0 +1,12 @@
+Generic Platform UHCI controllers.
+
+Required properties:
+ - compatible: Should be "platform-uhci".
+ - reg: Address range of the uhci registers
+ - interrupts: Should contain the uhci interrupt.
+
+usb: uhci@D8007301 {
+       compatible = "platform-uhci", "usb-uhci";
+       reg = <0xD8007301 0x200>;
+       interrupts = <0>;
+};
diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt
new file mode 100644 (file)
index 0000000..79729a9
--- /dev/null
@@ -0,0 +1,31 @@
+PXA USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "marvell,pxa-ohci" for USB controllers
+   used in host mode.
+
+Optional properties:
+ - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3"
+   If present, enables the appropriate USB port of the controller.
+ - "marvell,port-mode" selects the mode of the ports:
+       1 = PMM_NPS_MODE
+       2 = PMM_GLOBAL_MODE
+       3 = PMM_PERPORT_MODE
+ - "marvell,power-sense-low" - power sense pin is low-active.
+ - "marvell,power-control-low" - power control pin is low-active.
+ - "marvell,no-oc-protection" - disable over-current protection.
+ - "marvell,oc-mode-perport" - enable per-port over-current protection.
+ - "marvell,power_on_delay" Power On to Power Good time - in ms.
+
+Example:
+
+       usb0: ohci@4c000000 {
+               compatible = "marvell,pxa-ohci", "usb-ohci";
+               reg = <0x4c000000 0x100000>;
+               interrupts = <18>;
+               marvell,enable-port1;
+               marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */
+       };
+
diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
new file mode 100644 (file)
index 0000000..36b9aed
--- /dev/null
@@ -0,0 +1,40 @@
+USB COMPARATOR OF TWL CHIPS
+
+TWL6030 USB COMPARATOR
+ - compatible : Should be "ti,twl6030-usb"
+ - interrupts : Two interrupt numbers to the cpu should be specified. First
+   interrupt number is the otg interrupt number that raises ID interrupts when
+   the controller has to act as host and the second interrupt number is the
+   usb interrupt number that raises VBUS interrupts when the controller has to
+   act as device
+ - usb-supply : phandle to the regulator device tree node. It should be vusb
+   if it is twl6030 or ldousb if it is twl6025 subclass.
+
+twl6030-usb {
+       compatible = "ti,twl6030-usb";
+       interrupts = < 4 10 >;
+};
+
+Board specific device node entry
+&twl6030-usb {
+       usb-supply = <&vusb>;
+};
+
+TWL4030 USB PHY AND COMPARATOR
+ - compatible : Should be "ti,twl4030-usb"
+ - interrupts : The interrupt numbers to the cpu should be specified. First
+   interrupt number is the otg interrupt number that raises ID interrupts
+   and VBUS interrupts. The second interrupt number is optional.
+ - <supply-name>-supply : phandle to the regulator device tree node.
+   <supply-name> should be vusb1v5, vusb1v8 and vusb3v1
+ - usb_mode : The mode used by the phy to connect to the controller. "1"
+   specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
+
+twl4030-usb {
+       compatible = "ti,twl4030-usb";
+       interrupts = < 10 4 >;
+       usb1v5-supply = <&vusb1v5>;
+       usb1v8-supply = <&vusb1v8>;
+       usb3v1-supply = <&vusb3v1>;
+       usb_mode = <1>;
+};
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
new file mode 100644 (file)
index 0000000..80d4148
--- /dev/null
@@ -0,0 +1,17 @@
+USB PHY
+
+OMAP USB2 PHY
+
+Required properties:
+ - compatible: Should be "ti,omap-usb2"
+ - reg : Address and length of the register set for the device. Also
+add the address of control module dev conf register until a driver for
+control module is added
+
+This is usually a subnode of ocp2scp to which it is connected.
+
+usb2phy@4a0ad080 {
+       compatible = "ti,omap-usb2";
+       reg = <0x4a0ad080 0x58>,
+             <0x4a002300 0x4>;
+};
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
new file mode 100644 (file)
index 0000000..5fb8fd6
--- /dev/null
@@ -0,0 +1,12 @@
+VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
+
+Required properties:
+ - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
+ - reg: Address range of the ehci registers. size should be 0x200
+ - interrupts: Should contain the ehci interrupt.
+
+usb: ehci@D8007100 {
+       compatible = "wm,prizm-ehci", "usb-ehci";
+       reg = <0xD8007100 0x200>;
+       interrupts = <1>;
+};
index afaff312bf415acb59449aeb9bee4c848c197ff2..b9aa38bca04cf2fa6fbb9273c8eb7992b08f269c 100644 (file)
@@ -495,17 +495,6 @@ Who:       Bjorn Helgaas <bhelgaas@google.com>
 
 ----------------------------
 
-What:  Low Performance USB Block driver ("CONFIG_BLK_DEV_UB")
-When:  3.6
-Why:   This driver provides support for USB storage devices like "USB
-       sticks". As of now, it is deactivated in Debian, Fedora and
-        Ubuntu. All current users can switch over to usb-storage
-        (CONFIG_USB_STORAGE) which only drawback is the additional SCSI
-        stack.
-Who:   Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
-
-----------------------------
-
 What:  get_robust_list syscall
 When:  2013
 Why:   There appear to be no production users of the get_robust_list syscall,
index 0f103e39b4f6a025cb486cbdfb21126c78992738..e540a24e5d069d4f6372adaabfa792ff11897ca9 100644 (file)
@@ -114,7 +114,6 @@ prototypes:
        int (*drop_inode) (struct inode *);
        void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
-       void (*write_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
        int (*freeze_fs) (struct super_block *);
        int (*unfreeze_fs) (struct super_block *);
@@ -136,7 +135,6 @@ write_inode:
 drop_inode:                            !!!inode->i_lock!!!
 evict_inode:
 put_super:             write
-write_super:           read
 sync_fs:               read
 freeze_fs:             write
 unfreeze_fs:           write
index 2bef2b3843d1d4e09ead99fed121de4b2ab92db2..0742feebc6e221f9d79e400adab5feaba23098de 100644 (file)
@@ -94,9 +94,8 @@ protected.
 ---
 [mandatory]
 
-BKL is also moved from around sb operations.  ->write_super() Is now called 
-without BKL held.  BKL should have been shifted into individual fs sb_op
-functions.  If you don't need it, remove it.  
+BKL is also moved from around sb operations. BKL should have been shifted into
+individual fs sb_op functions.  If you don't need it, remove it.
 
 ---
 [informational]
index ead764b2728f8a20731ece907475b1966a35ce86..de1e6c4dccff047766f1bfc1801319ef28cdf0d1 100644 (file)
@@ -137,6 +137,17 @@ errors=panic|continue|remount-ro
                 without doing anything or remount the partition in
                 read-only mode (default behavior).
 
+discard       -- If set, issues discard/TRIM commands to the block
+                device when blocks are freed. This is useful for SSD devices
+                and sparse/thinly-provisoned LUNs.
+
+nfs           -- This option maintains an index (cache) of directory
+                inodes by i_logstart which is used by the nfs-related code to
+                improve look-ups.
+
+                Enable this only if you want to export the FAT filesystem
+                over NFS
+
 <bool>: 0,1,yes,no,true,false
 
 TODO
index 065aa2dc083538dcf05a9e2863e8b14fddb9b514..2ee133e030c3f51521321afd62d5dd3b1d1650fb 100644 (file)
@@ -216,7 +216,6 @@ struct super_operations {
         void (*drop_inode) (struct inode *);
         void (*delete_inode) (struct inode *);
         void (*put_super) (struct super_block *);
-        void (*write_super) (struct super_block *);
         int (*sync_fs)(struct super_block *sb, int wait);
         int (*freeze_fs) (struct super_block *);
         int (*unfreeze_fs) (struct super_block *);
@@ -273,9 +272,6 @@ or bottom half).
   put_super: called when the VFS wishes to free the superblock
        (i.e. unmount). This is called with the superblock lock held
 
-  write_super: called when the VFS superblock needs to be written to
-       disc. This method is optional
-
   sync_fs: called when VFS is writing out all dirty data associated with
        a superblock. The second parameter indicates whether the method
        should wait until the write out has been completed. Optional.
index 0bf25eebce948b4a330fe8868db387e742108278..4ebbfc3f1c6ea803b1cb7b5b71c1e98c6d8e3f17 100644 (file)
@@ -262,9 +262,9 @@ MINIMUM_BATTERY_MINUTES=10
 
 #
 # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
-# exceeded, the kernel will wake pdflush which will then reduce the amount
-# of dirty memory to dirty_background_ratio.  Set this nice and low, so once
-# some writeout has commenced, we do a lot of it.
+# exceeded, the kernel will wake flusher threads which will then reduce the
+# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
+# so once some writeout has commenced, we do a lot of it.
 #
 #DIRTY_BACKGROUND_RATIO=5
 
@@ -384,9 +384,9 @@ CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
 
 #
 # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
-# exceeded, the kernel will wake pdflush which will then reduce the amount
-# of dirty memory to dirty_background_ratio.  Set this nice and low, so once
-# some writeout has commenced, we do a lot of it.
+# exceeded, the kernel will wake flusher threads which will then reduce the
+# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
+# so once some writeout has commenced, we do a lot of it.
 #
 DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}
 
index 8d022073e3ef53933898c6756c3abf6d50104a79..2e9e0ae2cd453dc3ac0a605c1a40baf1096cf42f 100644 (file)
@@ -51,8 +51,23 @@ Built-in netconsole starts immediately after the TCP stack is
 initialized and attempts to bring up the supplied dev at the supplied
 address.
 
-The remote host can run either 'netcat -u -l -p <port>',
-'nc -l -u <port>' or syslogd.
+The remote host has several options to receive the kernel messages,
+for example:
+
+1) syslogd
+
+2) netcat
+
+   On distributions using a BSD-based netcat version (e.g. Fedora,
+   openSUSE and Ubuntu) the listening port must be specified without
+   the -p switch:
+
+   'nc -u -l -p <port>' / 'nc -u -l <port>' or
+   'netcat -u -l -p <port>' / 'netcat -u -l <port>'
+
+3) socat
+
+   'socat udp-recv:<port> -'
 
 Dynamic reconfiguration:
 ========================
index e40f4b4e1977c73d1f6984c705c1065878ad4ad4..1479aca2374441976c14668b7bc7e523fbb2211f 100644 (file)
@@ -840,9 +840,9 @@ static unsigned long i2c_pin_configs[] = {
 
 static struct pinctrl_map __initdata mapping[] = {
        PIN_MAP_MUX_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "i2c0"),
-       PIN_MAP_MUX_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
-       PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
-       PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
+       PIN_MAP_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
+       PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
+       PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
 };
 
 Finally, some devices expect the mapping table to contain certain specific
index e369de2d48cdf2f24c96a8373b8506d10800f28f..dd908cf64ecfcb7a809685a7eb2beb508cb30815 100644 (file)
@@ -46,14 +46,13 @@ restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...)
 so that any otherwise allowed process (even those in external pid namespaces)
 may attach.
 
-These restrictions do not change how ptrace via PTRACE_TRACEME operates.
-
-The sysctl settings are:
+The sysctl settings (writable only with CAP_SYS_PTRACE) are:
 
 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
     process running under the same uid, as long as it is dumpable (i.e.
     did not transition uids, start privileged, or have called
-    prctl(PR_SET_DUMPABLE...) already).
+    prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is
+    unchanged.
 
 1 - restricted ptrace: a process must have a predefined relationship
     with the inferior it wants to call PTRACE_ATTACH on. By default,
@@ -61,12 +60,13 @@ The sysctl settings are:
     classic criteria is also met. To change the relationship, an
     inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
     an allowed debugger PID to call PTRACE_ATTACH on the inferior.
+    Using PTRACE_TRACEME is unchanged.
 
 2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace
-    with PTRACE_ATTACH.
+    with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.
 
-3 - no attach: no processes may use ptrace with PTRACE_ATTACH. Once set,
-    this sysctl cannot be changed to a lower value.
+3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via
+    PTRACE_TRACEME. Once set, this sysctl value cannot be changed.
 
 The original children-only logic was based on the restrictions in grsecurity.
 
index dcc2a94ae34e7d4a976c8fd2f5613236c05968f3..078701fdbd4dd936dd485737abe7b5b60e554604 100644 (file)
@@ -76,8 +76,8 @@ huge pages although processes will also directly compact memory as required.
 
 dirty_background_bytes
 
-Contains the amount of dirty memory at which the pdflush background writeback
-daemon will start writeback.
+Contains the amount of dirty memory at which the background kernel
+flusher threads will start writeback.
 
 Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only
 one of them may be specified at a time. When one sysctl is written it is
@@ -89,7 +89,7 @@ other appears as 0 when read.
 dirty_background_ratio
 
 Contains, as a percentage of total system memory, the number of pages at which
-the pdflush background writeback daemon will start writing out dirty data.
+the background kernel flusher threads will start writing out dirty data.
 
 ==============================================================
 
@@ -112,9 +112,9 @@ retained.
 dirty_expire_centisecs
 
 This tunable is used to define when dirty data is old enough to be eligible
-for writeout by the pdflush daemons.  It is expressed in 100'ths of a second.
-Data which has been dirty in-memory for longer than this interval will be
-written out next time a pdflush daemon wakes up.
+for writeout by the kernel flusher threads.  It is expressed in 100'ths
+of a second.  Data which has been dirty in-memory for longer than this
+interval will be written out next time a flusher thread wakes up.
 
 ==============================================================
 
@@ -128,7 +128,7 @@ data.
 
 dirty_writeback_centisecs
 
-The pdflush writeback daemons will periodically wake up and write `old' data
+The kernel flusher threads will periodically wake up and write `old' data
 out to disk.  This tunable expresses the interval between those wakeups, in
 100'ths of a second.
 
index 074b159b77c20344aaa0a4abf7becc8603a2a065..35d70eda9ad627bf0eff7c1193f91fb451126e5b 100644 (file)
@@ -155,6 +155,9 @@ If the kernel gets fooled in this way, it's almost certain to cause
 data corruption and to crash your system.  You'll have no one to blame
 but yourself.
 
+For those devices with avoid_reset_quirk attribute being set, persist
+maybe fail because they may morph after reset.
+
 YOU HAVE BEEN WARNED!  USE AT YOUR OWN RISK!
 
 That having been said, most of the time there shouldn't be any trouble
index f8551b3879f8442350a94b9f88377961ed8e8abd..4ac359b7aa176d1d1b61a100bc196332d842029b 100644 (file)
@@ -299,11 +299,17 @@ map_hugetlb.c.
 *******************************************************************
 
 /*
- * hugepage-shm:  see Documentation/vm/hugepage-shm.c
+ * map_hugetlb: see tools/testing/selftests/vm/map_hugetlb.c
  */
 
 *******************************************************************
 
 /*
- * hugepage-mmap:  see Documentation/vm/hugepage-mmap.c
+ * hugepage-shm:  see tools/testing/selftests/vm/hugepage-shm.c
+ */
+
+*******************************************************************
+
+/*
+ * hugepage-mmap:  see tools/testing/selftests/vm/hugepage-mmap.c
  */
index 0403aaaba878edd18473ef7a536b38cfac4784c5..874a8ca93feb95c9783d9a41b3f89136b7485516 100644 (file)
@@ -3,6 +3,7 @@ Kernel driver w1_therm
 
 Supported chips:
   * Maxim ds18*20 based temperature sensors.
+  * Maxim ds1825 based temperature sensors.
 
 Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 
@@ -15,6 +16,7 @@ supported family codes:
 W1_THERM_DS18S20       0x10
 W1_THERM_DS1822                0x22
 W1_THERM_DS18B20       0x28
+W1_THERM_DS1825                0x3B
 
 Support is provided through the sysfs w1_slave file.  Each open and
 read sequence will initiate a temperature conversion then provide two
index 94b823f71e944d1f8805815c2b16b5bca437d3b7..fdc0119963e70f12c4f9e1eae3a613447e7d8781 100644 (file)
@@ -827,24 +827,24 @@ F:        arch/arm/mach-pxa/colibri-pxa270-income.c
 
 ARM/INTEL IOP32X ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IOP33X ARM ARCHITECTURE
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IOP13XX ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IQ81342EX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -869,7 +869,7 @@ F:  drivers/pcmcia/pxa2xx_stargate2.c
 
 ARM/INTEL XSC3 (MANZANO) ARM CORE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -925,14 +925,14 @@ S:        Maintained
 
 ARM/NOMADIK ARCHITECTURE
 M:     Alessandro Rubini <rubini@unipv.it>
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 M:     STEricsson <STEricsson_nomadik_linux@list.st.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-nomadik/
 F:     arch/arm/plat-nomadik/
 F:     drivers/i2c/busses/i2c-nomadik.c
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
 
 ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
 M:     Nelson Castillo <arhuaco@freaks-unidos.net>
@@ -1146,7 +1146,7 @@ F:        drivers/usb/host/ehci-w90x900.c
 F:     drivers/video/nuc900fb.c
 
 ARM/U300 MACHINE SUPPORT
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     arch/arm/mach-u300/
@@ -1161,15 +1161,20 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
 
 ARM/Ux500 ARM ARCHITECTURE
 M:     Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-ux500/
+F:     drivers/clocksource/clksrc-dbx500-prcmu.c
 F:     drivers/dma/ste_dma40*
+F:     drivers/hwspinlock/u8500_hsem.c
 F:     drivers/mfd/abx500*
 F:     drivers/mfd/ab8500*
-F:     drivers/mfd/stmpe*
+F:     drivers/mfd/dbx500*
+F:     drivers/mfd/db8500*
+F:     drivers/pinctrl/pinctrl-nomadik*
 F:     drivers/rtc/rtc-ab8500.c
+F:     drivers/rtc/rtc-pl031.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
 
 ARM/VFP SUPPORT
@@ -1227,9 +1232,9 @@ S:        Maintained
 F:     drivers/hwmon/asb100.c
 
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 W:     http://sourceforge.net/projects/xscaleiop
-S:     Supported
+S:     Maintained
 F:     Documentation/crypto/async-tx-api.txt
 F:     crypto/async_tx/
 F:     drivers/dma/
@@ -2212,7 +2217,7 @@ S:        Maintained
 F:     drivers/scsi/tmscsim.*
 
 DC395x SCSI driver
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 M:     Ali Akcaagac <aliakc@web.de>
 M:     Jamie Lenehan <lenehan@twibble.org>
 W:     http://twibble.org/dist/dc395x/
@@ -2359,7 +2364,7 @@ T:        git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:     Vinod Koul <vinod.koul@intel.com>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 S:     Supported
 F:     drivers/dma/
 F:     include/linux/dma*
@@ -3094,7 +3099,7 @@ F:        include/linux/gigaset_dev.h
 
 GPIO SUBSYSTEM
 M:     Grant Likely <grant.likely@secretlab.ca>
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 S:     Maintained
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 F:     Documentation/gpio.txt
@@ -3547,7 +3552,6 @@ K:        \b(ABS|SYN)_MT_
 
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:     Intel SCU Linux support <intel-linux-scu@intel.com>
-M:     Dan Williams <dan.j.williams@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 M:     Ed Nadolski <edmund.nadolski@intel.com>
 L:     linux-scsi@vger.kernel.org
@@ -3590,8 +3594,8 @@ F:        arch/x86/kernel/microcode_core.c
 F:     arch/x86/kernel/microcode_intel.c
 
 INTEL I/OAT DMA DRIVER
-M:     Dan Williams <dan.j.williams@intel.com>
-S:     Supported
+M:     Dan Williams <djbw@fb.com>
+S:     Maintained
 F:     drivers/dma/ioat*
 
 INTEL IOMMU (VT-d)
@@ -3603,8 +3607,8 @@ F:        drivers/iommu/intel-iommu.c
 F:     include/linux/intel-iommu.h
 
 INTEL IOP-ADMA DMA DRIVER
-M:     Dan Williams <dan.j.williams@intel.com>
-S:     Maintained
+M:     Dan Williams <djbw@fb.com>
+S:     Odd fixes
 F:     drivers/dma/iop-adma.c
 
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
@@ -4533,7 +4537,7 @@ S:        Supported
 F:     arch/microblaze/
 
 MICROTEK X6 SCANNER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 S:     Maintained
 F:     drivers/usb/image/microtek.*
 
@@ -5329,14 +5333,15 @@ PIN CONTROL SUBSYSTEM
 M:     Linus Walleij <linus.walleij@linaro.org>
 S:     Maintained
 F:     drivers/pinctrl/
+F:     include/linux/pinctrl/
 
 PIN CONTROLLER - ST SPEAR
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <viresh.linux@gmail.com>
 L:     spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
 S:     Maintained
-F:     driver/pinctrl/spear/
+F:     drivers/pinctrl/spear/
 
 PKTCDVD DRIVER
 M:     Peter Osterlund <petero2@telia.com>
@@ -7071,7 +7076,7 @@ F:        include/linux/mtd/ubi.h
 F:     include/mtd/ubi-user.h
 
 USB ACM DRIVER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     Documentation/usb/acm.txt
@@ -7092,7 +7097,7 @@ S:        Supported
 F:     drivers/block/ub.c
 
 USB CDC ETHERNET DRIVER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/net/usb/cdc_*.c
@@ -7165,7 +7170,7 @@ F:        drivers/usb/host/isp116x*
 F:     include/linux/usb/isp116x.h
 
 USB KAWASAKI LSI DRIVER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/serial/kl5kusb105.*
@@ -7283,6 +7288,12 @@ W:       http://www.connecttech.com
 S:     Supported
 F:     drivers/usb/serial/whiteheat*
 
+USB SMSC75XX ETHERNET DRIVER
+M:     Steve Glendinning <steve.glendinning@shawell.net>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/usb/smsc75xx.*
+
 USB SMSC95XX ETHERNET DRIVER
 M:     Steve Glendinning <steve.glendinning@shawell.net>
 L:     netdev@vger.kernel.org
@@ -7665,23 +7676,28 @@ S:      Supported
 F:     Documentation/hwmon/wm83??
 F:     arch/arm/mach-s3c64xx/mach-crag6410*
 F:     drivers/clk/clk-wm83*.c
+F:     drivers/extcon/extcon-arizona.c
 F:     drivers/leds/leds-wm83*.c
 F:     drivers/gpio/gpio-*wm*.c
+F:     drivers/gpio/gpio-arizona.c
 F:     drivers/hwmon/wm83??-hwmon.c
 F:     drivers/input/misc/wm831x-on.c
 F:     drivers/input/touchscreen/wm831x-ts.c
 F:     drivers/input/touchscreen/wm97*.c
-F:     drivers/mfd/wm8*.c
+F:     drivers/mfd/arizona*
+F:     drivers/mfd/wm*.c
 F:     drivers/power/wm83*.c
 F:     drivers/rtc/rtc-wm83*.c
 F:     drivers/regulator/wm8*.c
 F:     drivers/video/backlight/wm83*_bl.c
 F:     drivers/watchdog/wm83*_wdt.c
+F:     include/linux/mfd/arizona/
 F:     include/linux/mfd/wm831x/
 F:     include/linux/mfd/wm8350/
 F:     include/linux/mfd/wm8400*
 F:     include/linux/wm97xx.h
 F:     include/sound/wm????.h
+F:     sound/soc/codecs/arizona.?
 F:     sound/soc/codecs/wm*
 
 WORKQUEUE
index ddf5be952e456904ba009fbbe0d1c8e0a42470b7..354026873b13329e5add40f1863903ffc2fba9dc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc3
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
index d5b9b5e645cc7ad6ee66984d78434b306bc1aa13..9944dedee5b1b1b31abf08599a44421333bd9290 100644 (file)
@@ -18,6 +18,8 @@ config ALPHA
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_CMOS_UPDATE
+       select GENERIC_STRNCPY_FROM_USER
+       select GENERIC_STRNLEN_USER
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
index 3bb7ffeae3bc610010bb54a3eaba698c513c0c7d..c2cbe4fc391cd7d77d319cb0cbeabd19f7e5ecbb 100644 (file)
@@ -14,8 +14,8 @@
  */
 
 
-#define ATOMIC_INIT(i)         ( (atomic_t) { (i) } )
-#define ATOMIC64_INIT(i)       ( (atomic64_t) { (i) } )
+#define ATOMIC_INIT(i)         { (i) }
+#define ATOMIC64_INIT(i)       { (i) }
 
 #define atomic_read(v)         (*(volatile int *)&(v)->counter)
 #define atomic64_read(v)       (*(volatile long *)&(v)->counter)
index db00f7885faad8949db38886e5ebd798440f63f5..e477bcd5b94aaa3055486564c2ab2d54a5e44934 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef __ASM_ALPHA_FPU_H
 #define __ASM_ALPHA_FPU_H
 
+#ifdef __KERNEL__
 #include <asm/special_insns.h>
+#endif
 
 /*
  * Alpha floating-point control register defines:
index fd698a174f26a9358a2c8e63b663c68bc47a56c1..b87755a1955482f9a46282749ed68755afca4973 100644 (file)
@@ -76,7 +76,10 @@ struct switch_stack {
 #define task_pt_regs(task) \
   ((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
 
-#define force_successful_syscall_return() (task_pt_regs(current)->r0 = 0)
+#define current_pt_regs() \
+  ((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
+
+#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
 
 #endif
 
index dcb221a4b5be3505686b05fb3060307cde68f29b..7d2f75be932e6d16e4ceba058fe0e0c769a8be32 100644 (file)
 /* Instruct lower device to use last 4-bytes of skb data as FCS */
 #define SO_NOFCS               43
 
+#ifdef __KERNEL__
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
 #define SOCK_NONBLOCK  0x40000000
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_SOCKET_H */
index b49ec2f8d6e3e0220e4009793387c917f1b8e090..766fdfde2b7aa0329cc42681f2fb907b08ce9064 100644 (file)
@@ -433,36 +433,12 @@ clear_user(void __user *to, long len)
 #undef __module_address
 #undef __module_call
 
-/* Returns: -EFAULT if exception before terminator, N if the entire
-   buffer filled, else strlen.  */
+#define user_addr_max() \
+        (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
 
-extern long __strncpy_from_user(char *__to, const char __user *__from, long __to_len);
-
-extern inline long
-strncpy_from_user(char *to, const char __user *from, long n)
-{
-       long ret = -EFAULT;
-       if (__access_ok((unsigned long)from, 0, get_fs()))
-               ret = __strncpy_from_user(to, from, n);
-       return ret;
-}
-
-/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
-extern long __strlen_user(const char __user *);
-
-extern inline long strlen_user(const char __user *str)
-{
-       return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0;
-}
-
-/* Returns: 0 if exception before NUL or reaching the supplied limit (N),
- * a value greater than N if the limit would be exceeded, else strlen.  */
-extern long __strnlen_user(const char __user *, long);
-
-extern inline long strnlen_user(const char __user *str, long n)
-{
-       return access_ok(VERIFY_READ,str,0) ? __strnlen_user(str, n) : 0;
-}
+extern long strncpy_from_user(char *dest, const char __user *src, long count);
+extern __must_check long strlen_user(const char __user *str);
+extern __must_check long strnlen_user(const char __user *str, long n);
 
 /*
  * About the exception table:
index 633b23b0664ab2a4a075d648d26547dbc911a65d..a31a78eac9b99962cf6b55df76b1066cdcaf7b2b 100644 (file)
 #define __NR_setns                     501
 #define __NR_accept4                   502
 #define __NR_sendmmsg                  503
+#define __NR_process_vm_readv          504
+#define __NR_process_vm_writev         505
 
 #ifdef __KERNEL__
 
-#define NR_SYSCALLS                    504
+#define NR_SYSCALLS                    506
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
diff --git a/arch/alpha/include/asm/word-at-a-time.h b/arch/alpha/include/asm/word-at-a-time.h
new file mode 100644 (file)
index 0000000..6b340d0
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+#include <asm/compiler.h>
+
+/*
+ * word-at-a-time interface for Alpha.
+ */
+
+/*
+ * We do not use the word_at_a_time struct on Alpha, but it needs to be
+ * implemented to humour the generic code.
+ */
+struct word_at_a_time {
+       const unsigned long unused;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { 0 }
+
+/* Return nonzero if val has a zero */
+static inline unsigned long has_zero(unsigned long val, unsigned long *bits, const struct word_at_a_time *c)
+{
+       unsigned long zero_locations = __kernel_cmpbge(0, val);
+       *bits = zero_locations;
+       return zero_locations;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long val, unsigned long bits, const struct word_at_a_time *c)
+{
+       return bits;
+}
+
+#define create_zero_mask(bits) (bits)
+
+static inline unsigned long find_zero(unsigned long bits)
+{
+#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
+       /* Simple if have CIX instructions */
+       return __kernel_cttz(bits);
+#else
+       unsigned long t1, t2, t3;
+       /* Retain lowest set bit only */
+       bits &= -bits;
+       /* Binary search for lowest set bit */
+       t1 = bits & 0xf0;
+       t2 = bits & 0xcc;
+       t3 = bits & 0xaa;
+       if (t1) t1 = 4;
+       if (t2) t2 = 2;
+       if (t3) t3 = 1;
+       return t1 + t2 + t3;
+#endif
+}
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
index d96e742d4dc2c9d139e021ee34aae81eeabdda55..15fa821d09cd38ff58ea5390439617ee2ff4a2eb 100644 (file)
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(alpha_write_fp_reg_s);
 
 /* entry.S */
 EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(kernel_execve);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_tcpudp_magic);
@@ -74,8 +73,6 @@ EXPORT_SYMBOL(alpha_fp_emul);
  */
 EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(__do_clear_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__strnlen_user);
 
 /* 
  * SMP-specific symbols.
index 6d159cee5f2f43a48bc9aac8355069a3e588ef7f..ec0da0567ab515e6203d2310a9d960be7d4fc0e7 100644 (file)
@@ -663,58 +663,6 @@ kernel_thread:
        br      ret_to_kernel
 .end kernel_thread
 
-/*
- * kernel_execve(path, argv, envp)
- */
-       .align  4
-       .globl  kernel_execve
-       .ent    kernel_execve
-kernel_execve:
-       /* We can be called from a module.  */
-       ldgp    $gp, 0($27)
-       lda     $sp, -(32+SIZEOF_PT_REGS+8)($sp)
-       .frame  $sp, 32+SIZEOF_PT_REGS+8, $26, 0
-       stq     $26, 0($sp)
-       stq     $16, 8($sp)
-       stq     $17, 16($sp)
-       stq     $18, 24($sp)
-       .prologue 1
-
-       lda     $16, 32($sp)
-       lda     $17, 0
-       lda     $18, SIZEOF_PT_REGS
-       bsr     $26, memset             !samegp
-
-       /* Avoid the HAE being gratuitously wrong, which would cause us
-          to do the whole turn off interrupts thing and restore it.  */
-       ldq     $2, alpha_mv+HAE_CACHE
-       stq     $2, 152+32($sp)
-
-       ldq     $16, 8($sp)
-       ldq     $17, 16($sp)
-       ldq     $18, 24($sp)
-       lda     $19, 32($sp)
-       bsr     $26, do_execve          !samegp
-
-       ldq     $26, 0($sp)
-       bne     $0, 1f                  /* error! */
-
-       /* Move the temporary pt_regs struct from its current location
-          to the top of the kernel stack frame.  See copy_thread for
-          details for a normal process.  */
-       lda     $16, 0x4000 - SIZEOF_PT_REGS($8)
-       lda     $17, 32($sp)
-       lda     $18, SIZEOF_PT_REGS
-       bsr     $26, memmove            !samegp
-
-       /* Take that over as our new stack frame and visit userland!  */
-       lda     $sp, 0x4000 - SIZEOF_PT_REGS($8)
-       br      $31, ret_from_sys_call
-
-1:     lda     $sp, 32+SIZEOF_PT_REGS+8($sp)
-       ret
-.end kernel_execve
-
 \f
 /*
  * Special system calls.  Most of these are special in that they either
@@ -796,115 +744,6 @@ sys_rt_sigreturn:
        br      ret_from_sys_call
 .end sys_rt_sigreturn
 
-       .align  4
-       .globl  sys_sethae
-       .ent    sys_sethae
-sys_sethae:
-       .prologue 0
-       stq     $16, 152($sp)
-       ret
-.end sys_sethae
-
-       .align  4
-       .globl  osf_getpriority
-       .ent    osf_getpriority
-osf_getpriority:
-       lda     $sp, -16($sp)
-       stq     $26, 0($sp)
-       .prologue 0
-
-       jsr     $26, sys_getpriority
-
-       ldq     $26, 0($sp)
-       blt     $0, 1f
-
-       /* Return value is the unbiased priority, i.e. 20 - prio.
-          This does result in negative return values, so signal
-          no error by writing into the R0 slot.  */
-       lda     $1, 20
-       stq     $31, 16($sp)
-       subl    $1, $0, $0
-       unop
-
-1:     lda     $sp, 16($sp)
-       ret
-.end osf_getpriority
-
-       .align  4
-       .globl  sys_getxuid
-       .ent    sys_getxuid
-sys_getxuid:
-       .prologue 0
-       ldq     $2, TI_TASK($8)
-       ldq     $3, TASK_CRED($2)
-       ldl     $0, CRED_UID($3)
-       ldl     $1, CRED_EUID($3)
-       stq     $1, 80($sp)
-       ret
-.end sys_getxuid
-
-       .align  4
-       .globl  sys_getxgid
-       .ent    sys_getxgid
-sys_getxgid:
-       .prologue 0
-       ldq     $2, TI_TASK($8)
-       ldq     $3, TASK_CRED($2)
-       ldl     $0, CRED_GID($3)
-       ldl     $1, CRED_EGID($3)
-       stq     $1, 80($sp)
-       ret
-.end sys_getxgid
-
-       .align  4
-       .globl  sys_getxpid
-       .ent    sys_getxpid
-sys_getxpid:
-       .prologue 0
-       ldq     $2, TI_TASK($8)
-
-       /* See linux/kernel/timer.c sys_getppid for discussion
-          about this loop.  */
-       ldq     $3, TASK_GROUP_LEADER($2)
-       ldq     $4, TASK_REAL_PARENT($3)
-       ldl     $0, TASK_TGID($2)
-1:     ldl     $1, TASK_TGID($4)
-#ifdef CONFIG_SMP
-       mov     $4, $5
-       mb
-       ldq     $3, TASK_GROUP_LEADER($2)
-       ldq     $4, TASK_REAL_PARENT($3)
-       cmpeq   $4, $5, $5
-       beq     $5, 1b
-#endif
-       stq     $1, 80($sp)
-       ret
-.end sys_getxpid
-
-       .align  4
-       .globl  sys_alpha_pipe
-       .ent    sys_alpha_pipe
-sys_alpha_pipe:
-       lda     $sp, -16($sp)
-       stq     $26, 0($sp)
-       .prologue 0
-
-       mov     $31, $17
-       lda     $16, 8($sp)
-       jsr     $26, do_pipe_flags
-
-       ldq     $26, 0($sp)
-       bne     $0, 1f
-
-       /* The return values are in $0 and $20.  */
-       ldl     $1, 12($sp)
-       ldl     $0, 8($sp)
-
-       stq     $1, 80+16($sp)
-1:     lda     $sp, 16($sp)
-       ret
-.end sys_alpha_pipe
-
        .align  4
        .globl  sys_execve
        .ent    sys_execve
index 98a103621af6c24e04c219b318281d412ce5018d..bc1acdda7a5ed8ab3945b72559c09a9e763ec030 100644 (file)
@@ -1404,3 +1404,52 @@ SYSCALL_DEFINE3(osf_writev, unsigned long, fd,
 }
 
 #endif
+
+SYSCALL_DEFINE2(osf_getpriority, int, which, int, who)
+{
+       int prio = sys_getpriority(which, who);
+       if (prio >= 0) {
+               /* Return value is the unbiased priority, i.e. 20 - prio.
+                  This does result in negative return values, so signal
+                  no error */
+               force_successful_syscall_return();
+               prio = 20 - prio;
+       }
+       return prio;
+}
+
+SYSCALL_DEFINE0(getxuid)
+{
+       current_pt_regs()->r20 = sys_geteuid();
+       return sys_getuid();
+}
+
+SYSCALL_DEFINE0(getxgid)
+{
+       current_pt_regs()->r20 = sys_getegid();
+       return sys_getgid();
+}
+
+SYSCALL_DEFINE0(getxpid)
+{
+       current_pt_regs()->r20 = sys_getppid();
+       return sys_getpid();
+}
+
+SYSCALL_DEFINE0(alpha_pipe)
+{
+       int fd[2];
+       int res = do_pipe_flags(fd, 0);
+       if (!res) {
+               /* The return values are in $0 and $20.  */
+               current_pt_regs()->r20 = fd[1];
+               res = fd[0];
+       }
+       return res;
+}
+
+SYSCALL_DEFINE1(sethae, unsigned long, val)
+{
+       current_pt_regs()->hae = val;
+       return 0;
+}
index 153d3fce3e8e9b4adc84c64fe63483d815a1ec59..d6fde98b74b38bf87aac592c2b9697c1bc925558 100644 (file)
@@ -455,3 +455,22 @@ get_wchan(struct task_struct *p)
        }
        return pc;
 }
+
+int kernel_execve(const char *path, const char *const argv[], const char *const envp[])
+{
+       /* Avoid the HAE being gratuitously wrong, which would cause us
+          to do the whole turn off interrupts thing and restore it.  */
+       struct pt_regs regs = {.hae = alpha_mv.hae_cache};
+       int err = do_execve(path, argv, envp, &regs);
+       if (!err) {
+               struct pt_regs *p = current_pt_regs();
+               /* copy regs to normal position and off to userland we go... */
+               *p = regs;
+               __asm__ __volatile__ (
+                       "mov    %0, $sp;"
+                       "br     $31, ret_from_sys_call"
+                       : : "r"(p));
+       }
+       return err;
+}
+EXPORT_SYMBOL(kernel_execve);
index 87835235f114bd3d6619c8985833046b368eea96..2ac6b45c3e0005d542a084bfabcc652b4747f75e 100644 (file)
@@ -111,7 +111,7 @@ sys_call_table:
        .quad sys_socket
        .quad sys_connect
        .quad sys_accept
-       .quad osf_getpriority                   /* 100 */
+       .quad sys_osf_getpriority                       /* 100 */
        .quad sys_send
        .quad sys_recv
        .quad sys_sigreturn
@@ -522,6 +522,8 @@ sys_call_table:
        .quad sys_setns
        .quad sys_accept4
        .quad sys_sendmmsg
+       .quad sys_process_vm_readv
+       .quad sys_process_vm_writev             /* 505 */
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
index c0a83ab62b785f332d817b9f5b0036545295b640..59660743237cc489b4e4eef405e92ab66f7b25e8 100644 (file)
@@ -31,8 +31,6 @@ lib-y =       __divqu.o __remqu.o __divlu.o __remlu.o \
        $(ev6-y)memchr.o \
        $(ev6-y)copy_user.o \
        $(ev6-y)clear_user.o \
-       $(ev6-y)strncpy_from_user.o \
-       $(ev67-y)strlen_user.o \
        $(ev6-y)csum_ipv6_magic.o \
        $(ev6-y)clear_page.o \
        $(ev6-y)copy_page.o \
diff --git a/arch/alpha/lib/ev6-strncpy_from_user.S b/arch/alpha/lib/ev6-strncpy_from_user.S
deleted file mode 100644 (file)
index d2e2817..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * arch/alpha/lib/ev6-strncpy_from_user.S
- * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
- *
- * Just like strncpy except in the return value:
- *
- * -EFAULT       if an exception occurs before the terminator is copied.
- * N             if the buffer filled.
- *
- * Otherwise the length of the string is returned.
- *
- * Much of the information about 21264 scheduling/coding comes from:
- *     Compiler Writer's Guide for the Alpha 21264
- *     abbreviated as 'CWG' in other comments here
- *     ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
- * Scheduling notation:
- *     E       - either cluster
- *     U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
- *     L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
- * A bunch of instructions got moved and temp registers were changed
- * to aid in scheduling.  Control flow was also re-arranged to eliminate
- * branches, and to provide longer code sequences to enable better scheduling.
- * A total rewrite (using byte load/stores for start & tail sequences)
- * is desirable, but very difficult to do without a from-scratch rewrite.
- * Save that for the future.
- */
-
-
-#include <asm/errno.h>
-#include <asm/regdef.h>
-
-
-/* Allow an exception for an insn; exit if we get one.  */
-#define EX(x,y...)                     \
-       99: x,##y;                      \
-       .section __ex_table,"a";        \
-       .long 99b - .;                  \
-       lda $31, $exception-99b($0);    \
-       .previous
-
-
-       .set noat
-       .set noreorder
-       .text
-
-       .globl __strncpy_from_user
-       .ent __strncpy_from_user
-       .frame $30, 0, $26
-       .prologue 0
-
-       .align 4
-__strncpy_from_user:
-       and     a0, 7, t3       # E : find dest misalignment
-       beq     a2, $zerolength # U :
-
-       /* Are source and destination co-aligned?  */
-       mov     a0, v0          # E : save the string start
-       xor     a0, a1, t4      # E :
-       EX( ldq_u t1, 0(a1) )   # L : Latency=3 load first quadword
-       ldq_u   t0, 0(a0)       # L : load first (partial) aligned dest quadword
-
-       addq    a2, t3, a2      # E : bias count by dest misalignment
-       subq    a2, 1, a3       # E :
-       addq    zero, 1, t10    # E :
-       and     t4, 7, t4       # E : misalignment between the two
-
-       and     a3, 7, t6       # E : number of tail bytes
-       sll     t10, t6, t10    # E : t10 = bitmask of last count byte
-       bne     t4, $unaligned  # U :
-       lda     t2, -1          # E : build a mask against false zero
-
-       /*
-        * We are co-aligned; take care of a partial first word.
-        * On entry to this basic block:
-        * t0 == the first destination word for masking back in
-        * t1 == the first source word.
-        */
-
-       srl     a3, 3, a2       # E : a2 = loop counter = (count - 1)/8
-       addq    a1, 8, a1       # E :
-       mskqh   t2, a1, t2      # U :   detection in the src word
-       nop
-
-       /* Create the 1st output word and detect 0's in the 1st input word.  */
-       mskqh   t1, a1, t3      # U :
-       mskql   t0, a1, t0      # U : assemble the first output word
-       ornot   t1, t2, t2      # E :
-       nop
-
-       cmpbge  zero, t2, t8    # E : bits set iff null found
-       or      t0, t3, t0      # E :
-       beq     a2, $a_eoc      # U :
-       bne     t8, $a_eos      # U : 2nd branch in a quad.  Bad.
-
-       /* On entry to this basic block:
-        * t0 == a source quad not containing a null.
-        * a0 - current aligned destination address
-        * a1 - current aligned source address
-        * a2 - count of quadwords to move.
-        * NOTE: Loop improvement - unrolling this is going to be
-        *      a huge win, since we're going to stall otherwise.
-        *      Fix this later.  For _really_ large copies, look
-        *      at using wh64 on a look-ahead basis.  See the code
-        *      in clear_user.S and copy_user.S.
-        * Presumably, since (a0) and (a1) do not overlap (by C definition)
-        * Lots of nops here:
-        *      - Separate loads from stores
-        *      - Keep it to 1 branch/quadpack so the branch predictor
-        *        can train.
-        */
-$a_loop:
-       stq_u   t0, 0(a0)       # L :
-       addq    a0, 8, a0       # E :
-       nop
-       subq    a2, 1, a2       # E :
-
-       EX( ldq_u t0, 0(a1) )   # L :
-       addq    a1, 8, a1       # E :
-       cmpbge  zero, t0, t8    # E : Stall 2 cycles on t0
-       beq     a2, $a_eoc      # U :
-
-       beq     t8, $a_loop     # U :
-       nop
-       nop
-       nop
-
-       /* Take care of the final (partial) word store.  At this point
-        * the end-of-count bit is set in t8 iff it applies.
-        *
-        * On entry to this basic block we have:
-        * t0 == the source word containing the null
-        * t8 == the cmpbge mask that found it.
-        */
-$a_eos:
-       negq    t8, t12         # E : find low bit set
-       and     t8, t12, t12    # E : 
-
-       /* We're doing a partial word store and so need to combine
-          our source and original destination words.  */
-       ldq_u   t1, 0(a0)       # L :
-       subq    t12, 1, t6      # E :
-
-       or      t12, t6, t8     # E :
-       zapnot  t0, t8, t0      # U : clear src bytes > null
-       zap     t1, t8, t1      # U : clear dst bytes <= null
-       or      t0, t1, t0      # E :
-
-       stq_u   t0, 0(a0)       # L :
-       br      $finish_up      # L0 :
-       nop
-       nop
-
-       /* Add the end-of-count bit to the eos detection bitmask.  */
-       .align 4
-$a_eoc:
-       or      t10, t8, t8
-       br      $a_eos
-       nop
-       nop
-
-
-/* The source and destination are not co-aligned.  Align the destination
-   and cope.  We have to be very careful about not reading too much and
-   causing a SEGV.  */
-
-       .align 4
-$u_head:
-       /* We know just enough now to be able to assemble the first
-          full source word.  We can still find a zero at the end of it
-          that prevents us from outputting the whole thing.
-
-          On entry to this basic block:
-          t0 == the first dest word, unmasked
-          t1 == the shifted low bits of the first source word
-          t6 == bytemask that is -1 in dest word bytes */
-
-       EX( ldq_u t2, 8(a1) )   # L : load second src word
-       addq    a1, 8, a1       # E :
-       mskql   t0, a0, t0      # U : mask trailing garbage in dst
-       extqh   t2, a1, t4      # U :
-
-       or      t1, t4, t1      # E : first aligned src word complete
-       mskqh   t1, a0, t1      # U : mask leading garbage in src
-       or      t0, t1, t0      # E : first output word complete
-       or      t0, t6, t6      # E : mask original data for zero test
-
-       cmpbge  zero, t6, t8    # E :
-       beq     a2, $u_eocfin   # U :
-       bne     t8, $u_final    # U : bad news - 2nd branch in a quad
-       lda     t6, -1          # E : mask out the bits we have
-
-       mskql   t6, a1, t6      # U :   already seen
-       stq_u   t0, 0(a0)       # L : store first output word
-       or      t6, t2, t2      # E :
-       cmpbge  zero, t2, t8    # E : find nulls in second partial
-
-       addq    a0, 8, a0               # E :
-       subq    a2, 1, a2               # E :
-       bne     t8, $u_late_head_exit   # U :
-       nop
-
-       /* Finally, we've got all the stupid leading edge cases taken care
-          of and we can set up to enter the main loop.  */
-
-       extql   t2, a1, t1      # U : position hi-bits of lo word
-       EX( ldq_u t2, 8(a1) )   # L : read next high-order source word
-       addq    a1, 8, a1       # E :
-       cmpbge  zero, t2, t8    # E :
-
-       beq     a2, $u_eoc      # U :
-       bne     t8, $u_eos      # U :
-       nop
-       nop
-
-       /* Unaligned copy main loop.  In order to avoid reading too much,
-          the loop is structured to detect zeros in aligned source words.
-          This has, unfortunately, effectively pulled half of a loop
-          iteration out into the head and half into the tail, but it does
-          prevent nastiness from accumulating in the very thing we want
-          to run as fast as possible.
-
-          On entry to this basic block:
-          t1 == the shifted high-order bits from the previous source word
-          t2 == the unshifted current source word
-
-          We further know that t2 does not contain a null terminator.  */
-
-       /*
-        * Extra nops here:
-        *      separate load quads from store quads
-        *      only one branch/quad to permit predictor training
-        */
-
-       .align 4
-$u_loop:
-       extqh   t2, a1, t0      # U : extract high bits for current word
-       addq    a1, 8, a1       # E :
-       extql   t2, a1, t3      # U : extract low bits for next time
-       addq    a0, 8, a0       # E :
-
-       or      t0, t1, t0      # E : current dst word now complete
-       EX( ldq_u t2, 0(a1) )   # L : load high word for next time
-       subq    a2, 1, a2       # E :
-       nop
-
-       stq_u   t0, -8(a0)      # L : save the current word
-       mov     t3, t1          # E :
-       cmpbge  zero, t2, t8    # E : test new word for eos
-       beq     a2, $u_eoc      # U :
-
-       beq     t8, $u_loop     # U :
-       nop
-       nop
-       nop
-
-       /* We've found a zero somewhere in the source word we just read.
-          If it resides in the lower half, we have one (probably partial)
-          word to write out, and if it resides in the upper half, we
-          have one full and one partial word left to write out.
-
-          On entry to this basic block:
-          t1 == the shifted high-order bits from the previous source word
-          t2 == the unshifted current source word.  */
-       .align 4
-$u_eos:
-       extqh   t2, a1, t0      # U :
-       or      t0, t1, t0      # E : first (partial) source word complete
-       cmpbge  zero, t0, t8    # E : is the null in this first bit?
-       nop
-
-       bne     t8, $u_final    # U :
-       stq_u   t0, 0(a0)       # L : the null was in the high-order bits
-       addq    a0, 8, a0       # E :
-       subq    a2, 1, a2       # E :
-
-       .align 4
-$u_late_head_exit:
-       extql   t2, a1, t0      # U :
-       cmpbge  zero, t0, t8    # E :
-       or      t8, t10, t6     # E :
-       cmoveq  a2, t6, t8      # E :
-
-       /* Take care of a final (probably partial) result word.
-          On entry to this basic block:
-          t0 == assembled source word
-          t8 == cmpbge mask that found the null.  */
-       .align 4
-$u_final:
-       negq    t8, t6          # E : isolate low bit set
-       and     t6, t8, t12     # E :
-       ldq_u   t1, 0(a0)       # L :
-       subq    t12, 1, t6      # E :
-
-       or      t6, t12, t8     # E :
-       zapnot  t0, t8, t0      # U : kill source bytes > null
-       zap     t1, t8, t1      # U : kill dest bytes <= null
-       or      t0, t1, t0      # E :
-
-       stq_u   t0, 0(a0)       # E :
-       br      $finish_up      # U :
-       nop
-       nop
-
-       .align 4
-$u_eoc:                                # end-of-count
-       extqh   t2, a1, t0      # U :
-       or      t0, t1, t0      # E :
-       cmpbge  zero, t0, t8    # E :
-       nop
-
-       .align 4
-$u_eocfin:                     # end-of-count, final word
-       or      t10, t8, t8     # E :
-       br      $u_final        # U :
-       nop
-       nop
-
-       /* Unaligned copy entry point.  */
-       .align 4
-$unaligned:
-
-       srl     a3, 3, a2       # U : a2 = loop counter = (count - 1)/8
-       and     a0, 7, t4       # E : find dest misalignment
-       and     a1, 7, t5       # E : find src misalignment
-       mov     zero, t0        # E :
-
-       /* Conditionally load the first destination word and a bytemask
-          with 0xff indicating that the destination byte is sacrosanct.  */
-
-       mov     zero, t6        # E :
-       beq     t4, 1f          # U :
-       ldq_u   t0, 0(a0)       # L :
-       lda     t6, -1          # E :
-
-       mskql   t6, a0, t6      # E :
-       nop
-       nop
-       nop
-
-       .align 4
-1:
-       subq    a1, t4, a1      # E : sub dest misalignment from src addr
-       /* If source misalignment is larger than dest misalignment, we need
-          extra startup checks to avoid SEGV.  */
-       cmplt   t4, t5, t12     # E :
-       extql   t1, a1, t1      # U : shift src into place
-       lda     t2, -1          # E : for creating masks later
-
-       beq     t12, $u_head    # U :
-       mskqh   t2, t5, t2      # U : begin src byte validity mask
-       cmpbge  zero, t1, t8    # E : is there a zero?
-       nop
-
-       extql   t2, a1, t2      # U :
-       or      t8, t10, t5     # E : test for end-of-count too
-       cmpbge  zero, t2, t3    # E :
-       cmoveq  a2, t5, t8      # E : Latency=2, extra map slot
-
-       nop                     # E : goes with cmov
-       andnot  t8, t3, t8      # E :
-       beq     t8, $u_head     # U :
-       nop
-
-       /* At this point we've found a zero in the first partial word of
-          the source.  We need to isolate the valid source data and mask
-          it into the original destination data.  (Incidentally, we know
-          that we'll need at least one byte of that original dest word.) */
-
-       ldq_u   t0, 0(a0)       # L :
-       negq    t8, t6          # E : build bitmask of bytes <= zero
-       mskqh   t1, t4, t1      # U :
-       and     t6, t8, t12     # E :
-
-       subq    t12, 1, t6      # E :
-       or      t6, t12, t8     # E :
-       zapnot  t2, t8, t2      # U : prepare source word; mirror changes
-       zapnot  t1, t8, t1      # U : to source validity mask
-
-       andnot  t0, t2, t0      # E : zero place for source to reside
-       or      t0, t1, t0      # E : and put it there
-       stq_u   t0, 0(a0)       # L :
-       nop
-
-       .align 4
-$finish_up:
-       zapnot  t0, t12, t4     # U : was last byte written null?
-       and     t12, 0xf0, t3   # E : binary search for the address of the
-       cmovne  t4, 1, t4       # E : Latency=2, extra map slot
-       nop                     # E : with cmovne
-
-       and     t12, 0xcc, t2   # E : last byte written
-       and     t12, 0xaa, t1   # E :
-       cmovne  t3, 4, t3       # E : Latency=2, extra map slot
-       nop                     # E : with cmovne
-
-       bic     a0, 7, t0
-       cmovne  t2, 2, t2       # E : Latency=2, extra map slot
-       nop                     # E : with cmovne
-       nop
-
-       cmovne  t1, 1, t1       # E : Latency=2, extra map slot
-       nop                     # E : with cmovne
-       addq    t0, t3, t0      # E :
-       addq    t1, t2, t1      # E :
-
-       addq    t0, t1, t0      # E :
-       addq    t0, t4, t0      # add one if we filled the buffer
-       subq    t0, v0, v0      # find string length
-       ret                     # L0 :
-
-       .align 4
-$zerolength:
-       nop
-       nop
-       nop
-       clr     v0
-
-$exception:
-       nop
-       nop
-       nop
-       ret
-
-       .end __strncpy_from_user
diff --git a/arch/alpha/lib/ev67-strlen_user.S b/arch/alpha/lib/ev67-strlen_user.S
deleted file mode 100644 (file)
index 57e0d77..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * arch/alpha/lib/ev67-strlen_user.S
- * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
- *
- * Return the length of the string including the NULL terminator
- * (strlen+1) or zero if an error occurred.
- *
- * In places where it is critical to limit the processing time,
- * and the data is not trusted, strnlen_user() should be used.
- * It will return a value greater than its second argument if
- * that limit would be exceeded. This implementation is allowed
- * to access memory beyond the limit, but will not cross a page
- * boundary when doing so.
- *
- * Much of the information about 21264 scheduling/coding comes from:
- *      Compiler Writer's Guide for the Alpha 21264
- *      abbreviated as 'CWG' in other comments here
- *      ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
- * Scheduling notation:
- *      E       - either cluster
- *      U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
- *      L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
- * Try not to change the actual algorithm if possible for consistency.
- */
-
-#include <asm/regdef.h>
-
-
-/* Allow an exception for an insn; exit if we get one.  */
-#define EX(x,y...)                     \
-       99: x,##y;                      \
-       .section __ex_table,"a";        \
-       .long 99b - .;                  \
-       lda v0, $exception-99b(zero);   \
-       .previous
-
-
-       .set noreorder
-       .set noat
-       .text
-
-       .globl __strlen_user
-       .ent __strlen_user
-       .frame sp, 0, ra
-
-       .align 4
-__strlen_user:
-       ldah    a1, 32767(zero) # do not use plain strlen_user() for strings
-                               # that might be almost 2 GB long; you should
-                               # be using strnlen_user() instead
-       nop
-       nop
-       nop
-
-       .globl __strnlen_user
-
-       .align 4
-__strnlen_user:
-       .prologue 0
-       EX( ldq_u t0, 0(a0) )   # L : load first quadword (a0 may be misaligned)
-       lda     t1, -1(zero)    # E :
-
-       insqh   t1, a0, t1      # U :
-       andnot  a0, 7, v0       # E :
-       or      t1, t0, t0      # E :
-       subq    a0, 1, a0       # E : get our +1 for the return 
-
-       cmpbge  zero, t0, t1    # E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0
-       subq    a1, 7, t2       # E :
-       subq    a0, v0, t0      # E :
-       bne     t1, $found      # U :
-
-       addq    t2, t0, t2      # E :
-       addq    a1, 1, a1       # E :
-       nop                     # E :
-       nop                     # E :
-
-       .align 4
-$loop: ble     t2, $limit      # U :
-       EX( ldq t0, 8(v0) )     # L :
-       nop                     # E :
-       nop                     # E :
-
-       cmpbge  zero, t0, t1    # E :
-       subq    t2, 8, t2       # E :
-       addq    v0, 8, v0       # E : addr += 8
-       beq     t1, $loop       # U :
-
-$found: cttz   t1, t2          # U0 :
-       addq    v0, t2, v0      # E :
-       subq    v0, a0, v0      # E :
-       ret                     # L0 :
-
-$exception:
-       nop
-       nop
-       nop
-       ret
-
-       .align 4                # currently redundant
-$limit:
-       nop
-       nop
-       subq    a1, t2, v0
-       ret
-
-       .end __strlen_user
diff --git a/arch/alpha/lib/strlen_user.S b/arch/alpha/lib/strlen_user.S
deleted file mode 100644 (file)
index 508a18e..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * arch/alpha/lib/strlen_user.S
- *
- * Return the length of the string including the NUL terminator
- * (strlen+1) or zero if an error occurred.
- *
- * In places where it is critical to limit the processing time,
- * and the data is not trusted, strnlen_user() should be used.
- * It will return a value greater than its second argument if
- * that limit would be exceeded. This implementation is allowed
- * to access memory beyond the limit, but will not cross a page
- * boundary when doing so.
- */
-
-#include <asm/regdef.h>
-
-
-/* Allow an exception for an insn; exit if we get one.  */
-#define EX(x,y...)                     \
-       99: x,##y;                      \
-       .section __ex_table,"a";        \
-       .long 99b - .;                  \
-       lda v0, $exception-99b(zero);   \
-       .previous
-
-
-       .set noreorder
-       .set noat
-       .text
-
-       .globl __strlen_user
-       .ent __strlen_user
-       .frame sp, 0, ra
-
-       .align 3
-__strlen_user:
-       ldah    a1, 32767(zero) # do not use plain strlen_user() for strings
-                               # that might be almost 2 GB long; you should
-                               # be using strnlen_user() instead
-
-       .globl __strnlen_user
-
-       .align 3
-__strnlen_user:
-       .prologue 0
-
-       EX( ldq_u t0, 0(a0) )   # load first quadword (a0 may be misaligned)
-       lda     t1, -1(zero)
-       insqh   t1, a0, t1
-       andnot  a0, 7, v0
-       or      t1, t0, t0
-       subq    a0, 1, a0       # get our +1 for the return 
-       cmpbge  zero, t0, t1    # t1 <- bitmask: bit i == 1 <==> i-th byte == 0
-       subq    a1, 7, t2
-       subq    a0, v0, t0
-       bne     t1, $found
-
-       addq    t2, t0, t2
-       addq    a1, 1, a1
-
-       .align 3
-$loop: ble     t2, $limit
-       EX( ldq t0, 8(v0) )
-       subq    t2, 8, t2
-       addq    v0, 8, v0       # addr += 8
-       cmpbge  zero, t0, t1
-       beq     t1, $loop
-
-$found:        negq    t1, t2          # clear all but least set bit
-       and     t1, t2, t1
-
-       and     t1, 0xf0, t2    # binary search for that set bit
-       and     t1, 0xcc, t3
-       and     t1, 0xaa, t4
-       cmovne  t2, 4, t2
-       cmovne  t3, 2, t3
-       cmovne  t4, 1, t4
-       addq    t2, t3, t2
-       addq    v0, t4, v0
-       addq    v0, t2, v0
-       nop                     # dual issue next two on ev4 and ev5
-       subq    v0, a0, v0
-$exception:
-       ret
-
-       .align 3                # currently redundant
-$limit:
-       subq    a1, t2, v0
-       ret
-
-       .end __strlen_user
diff --git a/arch/alpha/lib/strncpy_from_user.S b/arch/alpha/lib/strncpy_from_user.S
deleted file mode 100644 (file)
index 73ee211..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * arch/alpha/lib/strncpy_from_user.S
- * Contributed by Richard Henderson (rth@tamu.edu)
- *
- * Just like strncpy except in the return value:
- *
- * -EFAULT       if an exception occurs before the terminator is copied.
- * N             if the buffer filled.
- *
- * Otherwise the length of the string is returned.
- */
-
-
-#include <asm/errno.h>
-#include <asm/regdef.h>
-
-
-/* Allow an exception for an insn; exit if we get one.  */
-#define EX(x,y...)                     \
-       99: x,##y;                      \
-       .section __ex_table,"a";        \
-       .long 99b - .;                  \
-       lda $31, $exception-99b($0);    \
-       .previous
-
-
-       .set noat
-       .set noreorder
-       .text
-
-       .globl __strncpy_from_user
-       .ent __strncpy_from_user
-       .frame $30, 0, $26
-       .prologue 0
-
-       .align 3
-$aligned:
-       /* On entry to this basic block:
-          t0 == the first destination word for masking back in
-          t1 == the first source word.  */
-
-       /* Create the 1st output word and detect 0's in the 1st input word.  */
-       lda     t2, -1          # e1    : build a mask against false zero
-       mskqh   t2, a1, t2      # e0    :   detection in the src word
-       mskqh   t1, a1, t3      # e0    :
-       ornot   t1, t2, t2      # .. e1 :
-       mskql   t0, a1, t0      # e0    : assemble the first output word
-       cmpbge  zero, t2, t8    # .. e1 : bits set iff null found
-       or      t0, t3, t0      # e0    :
-       beq     a2, $a_eoc      # .. e1 :
-       bne     t8, $a_eos      # .. e1 :
-
-       /* On entry to this basic block:
-          t0 == a source word not containing a null.  */
-
-$a_loop:
-       stq_u   t0, 0(a0)       # e0    :
-       addq    a0, 8, a0       # .. e1 :
-       EX( ldq_u t0, 0(a1) )   # e0    :
-       addq    a1, 8, a1       # .. e1 :
-       subq    a2, 1, a2       # e0    :
-       cmpbge  zero, t0, t8    # .. e1 (stall)
-       beq     a2, $a_eoc      # e1    :
-       beq     t8, $a_loop     # e1    :
-
-       /* Take care of the final (partial) word store.  At this point
-          the end-of-count bit is set in t8 iff it applies.
-
-          On entry to this basic block we have:
-          t0 == the source word containing the null
-          t8 == the cmpbge mask that found it.  */
-
-$a_eos:
-       negq    t8, t12         # e0    : find low bit set
-       and     t8, t12, t12    # e1 (stall)
-
-       /* For the sake of the cache, don't read a destination word
-          if we're not going to need it.  */
-       and     t12, 0x80, t6   # e0    :
-       bne     t6, 1f          # .. e1 (zdb)
-
-       /* We're doing a partial word store and so need to combine
-          our source and original destination words.  */
-       ldq_u   t1, 0(a0)       # e0    :
-       subq    t12, 1, t6      # .. e1 :
-       or      t12, t6, t8     # e0    :
-       unop                    #
-       zapnot  t0, t8, t0      # e0    : clear src bytes > null
-       zap     t1, t8, t1      # .. e1 : clear dst bytes <= null
-       or      t0, t1, t0      # e1    :
-
-1:     stq_u   t0, 0(a0)
-       br      $finish_up
-
-       /* Add the end-of-count bit to the eos detection bitmask.  */
-$a_eoc:
-       or      t10, t8, t8
-       br      $a_eos
-
-       /*** The Function Entry Point ***/
-       .align 3
-__strncpy_from_user:
-       mov     a0, v0          # save the string start
-       beq     a2, $zerolength
-
-       /* Are source and destination co-aligned?  */
-       xor     a0, a1, t1      # e0    :
-       and     a0, 7, t0       # .. e1 : find dest misalignment
-       and     t1, 7, t1       # e0    :
-       addq    a2, t0, a2      # .. e1 : bias count by dest misalignment
-       subq    a2, 1, a2       # e0    :
-       and     a2, 7, t2       # e1    :
-       srl     a2, 3, a2       # e0    : a2 = loop counter = (count - 1)/8
-       addq    zero, 1, t10    # .. e1 :
-       sll     t10, t2, t10    # e0    : t10 = bitmask of last count byte
-       bne     t1, $unaligned  # .. e1 :
-
-       /* We are co-aligned; take care of a partial first word.  */
-
-       EX( ldq_u t1, 0(a1) )   # e0    : load first src word
-       addq    a1, 8, a1       # .. e1 :
-
-       beq     t0, $aligned    # avoid loading dest word if not needed
-       ldq_u   t0, 0(a0)       # e0    :
-       br      $aligned        # .. e1 :
-
-
-/* The source and destination are not co-aligned.  Align the destination
-   and cope.  We have to be very careful about not reading too much and
-   causing a SEGV.  */
-
-       .align 3
-$u_head:
-       /* We know just enough now to be able to assemble the first
-          full source word.  We can still find a zero at the end of it
-          that prevents us from outputting the whole thing.
-
-          On entry to this basic block:
-          t0 == the first dest word, unmasked
-          t1 == the shifted low bits of the first source word
-          t6 == bytemask that is -1 in dest word bytes */
-
-       EX( ldq_u t2, 8(a1) )   # e0    : load second src word
-       addq    a1, 8, a1       # .. e1 :
-       mskql   t0, a0, t0      # e0    : mask trailing garbage in dst
-       extqh   t2, a1, t4      # e0    :
-       or      t1, t4, t1      # e1    : first aligned src word complete
-       mskqh   t1, a0, t1      # e0    : mask leading garbage in src
-       or      t0, t1, t0      # e0    : first output word complete
-       or      t0, t6, t6      # e1    : mask original data for zero test
-       cmpbge  zero, t6, t8    # e0    :
-       beq     a2, $u_eocfin   # .. e1 :
-       bne     t8, $u_final    # e1    :
-
-       lda     t6, -1                  # e1    : mask out the bits we have
-       mskql   t6, a1, t6              # e0    :   already seen
-       stq_u   t0, 0(a0)               # e0    : store first output word
-       or      t6, t2, t2              # .. e1 :
-       cmpbge  zero, t2, t8            # e0    : find nulls in second partial
-       addq    a0, 8, a0               # .. e1 :
-       subq    a2, 1, a2               # e0    :
-       bne     t8, $u_late_head_exit   # .. e1 :
-
-       /* Finally, we've got all the stupid leading edge cases taken care
-          of and we can set up to enter the main loop.  */
-
-       extql   t2, a1, t1      # e0    : position hi-bits of lo word
-       EX( ldq_u t2, 8(a1) )   # .. e1 : read next high-order source word
-       addq    a1, 8, a1       # e0    :
-       cmpbge  zero, t2, t8    # e1 (stall)
-       beq     a2, $u_eoc      # e1    :
-       bne     t8, $u_eos      # e1    :
-
-       /* Unaligned copy main loop.  In order to avoid reading too much,
-          the loop is structured to detect zeros in aligned source words.
-          This has, unfortunately, effectively pulled half of a loop
-          iteration out into the head and half into the tail, but it does
-          prevent nastiness from accumulating in the very thing we want
-          to run as fast as possible.
-
-          On entry to this basic block:
-          t1 == the shifted high-order bits from the previous source word
-          t2 == the unshifted current source word
-
-          We further know that t2 does not contain a null terminator.  */
-
-       .align 3
-$u_loop:
-       extqh   t2, a1, t0      # e0    : extract high bits for current word
-       addq    a1, 8, a1       # .. e1 :
-       extql   t2, a1, t3      # e0    : extract low bits for next time
-       addq    a0, 8, a0       # .. e1 :
-       or      t0, t1, t0      # e0    : current dst word now complete
-       EX( ldq_u t2, 0(a1) )   # .. e1 : load high word for next time
-       stq_u   t0, -8(a0)      # e0    : save the current word
-       mov     t3, t1          # .. e1 :
-       subq    a2, 1, a2       # e0    :
-       cmpbge  zero, t2, t8    # .. e1 : test new word for eos
-       beq     a2, $u_eoc      # e1    :
-       beq     t8, $u_loop     # e1    :
-
-       /* We've found a zero somewhere in the source word we just read.
-          If it resides in the lower half, we have one (probably partial)
-          word to write out, and if it resides in the upper half, we
-          have one full and one partial word left to write out.
-
-          On entry to this basic block:
-          t1 == the shifted high-order bits from the previous source word
-          t2 == the unshifted current source word.  */
-$u_eos:
-       extqh   t2, a1, t0      # e0    :
-       or      t0, t1, t0      # e1    : first (partial) source word complete
-
-       cmpbge  zero, t0, t8    # e0    : is the null in this first bit?
-       bne     t8, $u_final    # .. e1 (zdb)
-
-       stq_u   t0, 0(a0)       # e0    : the null was in the high-order bits
-       addq    a0, 8, a0       # .. e1 :
-       subq    a2, 1, a2       # e1    :
-
-$u_late_head_exit:
-       extql   t2, a1, t0      # .. e0 :
-       cmpbge  zero, t0, t8    # e0    :
-       or      t8, t10, t6     # e1    :
-       cmoveq  a2, t6, t8      # e0    :
-       nop                     # .. e1 :
-
-       /* Take care of a final (probably partial) result word.
-          On entry to this basic block:
-          t0 == assembled source word
-          t8 == cmpbge mask that found the null.  */
-$u_final:
-       negq    t8, t6          # e0    : isolate low bit set
-       and     t6, t8, t12     # e1    :
-
-       and     t12, 0x80, t6   # e0    : avoid dest word load if we can
-       bne     t6, 1f          # .. e1 (zdb)
-
-       ldq_u   t1, 0(a0)       # e0    :
-       subq    t12, 1, t6      # .. e1 :
-       or      t6, t12, t8     # e0    :
-       zapnot  t0, t8, t0      # .. e1 : kill source bytes > null
-       zap     t1, t8, t1      # e0    : kill dest bytes <= null
-       or      t0, t1, t0      # e1    :
-
-1:     stq_u   t0, 0(a0)       # e0    :
-       br      $finish_up
-
-$u_eoc:                                # end-of-count
-       extqh   t2, a1, t0
-       or      t0, t1, t0
-       cmpbge  zero, t0, t8
-
-$u_eocfin:                     # end-of-count, final word
-       or      t10, t8, t8
-       br      $u_final
-
-       /* Unaligned copy entry point.  */
-       .align 3
-$unaligned:
-
-       EX( ldq_u t1, 0(a1) )   # e0    : load first source word
-
-       and     a0, 7, t4       # .. e1 : find dest misalignment
-       and     a1, 7, t5       # e0    : find src misalignment
-
-       /* Conditionally load the first destination word and a bytemask
-          with 0xff indicating that the destination byte is sacrosanct.  */
-
-       mov     zero, t0        # .. e1 :
-       mov     zero, t6        # e0    :
-       beq     t4, 1f          # .. e1 :
-       ldq_u   t0, 0(a0)       # e0    :
-       lda     t6, -1          # .. e1 :
-       mskql   t6, a0, t6      # e0    :
-1:
-       subq    a1, t4, a1      # .. e1 : sub dest misalignment from src addr
-
-       /* If source misalignment is larger than dest misalignment, we need
-          extra startup checks to avoid SEGV.  */
-
-       cmplt   t4, t5, t12     # e1    :
-       extql   t1, a1, t1      # .. e0 : shift src into place
-       lda     t2, -1          # e0    : for creating masks later
-       beq     t12, $u_head    # e1    :
-
-       mskqh   t2, t5, t2      # e0    : begin src byte validity mask
-       cmpbge  zero, t1, t8    # .. e1 : is there a zero?
-       extql   t2, a1, t2      # e0    :
-       or      t8, t10, t5     # .. e1 : test for end-of-count too
-       cmpbge  zero, t2, t3    # e0    :
-       cmoveq  a2, t5, t8      # .. e1 :
-       andnot  t8, t3, t8      # e0    :
-       beq     t8, $u_head     # .. e1 (zdb)
-
-       /* At this point we've found a zero in the first partial word of
-          the source.  We need to isolate the valid source data and mask
-          it into the original destination data.  (Incidentally, we know
-          that we'll need at least one byte of that original dest word.) */
-
-       ldq_u   t0, 0(a0)       # e0    :
-       negq    t8, t6          # .. e1 : build bitmask of bytes <= zero
-       mskqh   t1, t4, t1      # e0    :
-       and     t6, t8, t12     # .. e1 :
-       subq    t12, 1, t6      # e0    :
-       or      t6, t12, t8     # e1    :
-
-       zapnot  t2, t8, t2      # e0    : prepare source word; mirror changes
-       zapnot  t1, t8, t1      # .. e1 : to source validity mask
-
-       andnot  t0, t2, t0      # e0    : zero place for source to reside
-       or      t0, t1, t0      # e1    : and put it there
-       stq_u   t0, 0(a0)       # e0    :
-
-$finish_up:
-       zapnot  t0, t12, t4     # was last byte written null?
-       cmovne  t4, 1, t4
-
-       and     t12, 0xf0, t3   # binary search for the address of the
-       and     t12, 0xcc, t2   # last byte written
-       and     t12, 0xaa, t1
-       bic     a0, 7, t0
-       cmovne  t3, 4, t3
-       cmovne  t2, 2, t2
-       cmovne  t1, 1, t1
-       addq    t0, t3, t0
-       addq    t1, t2, t1
-       addq    t0, t1, t0
-       addq    t0, t4, t0      # add one if we filled the buffer
-
-       subq    t0, v0, v0      # find string length
-       ret
-
-$zerolength:
-       clr     v0
-$exception:
-       ret
-
-       .end __strncpy_from_user
index 5eecab1a84efd3430deab218698ab3dab91c0e6a..0c4132dd3507a0b62b3c40c2fc6fd4065a325262 100644 (file)
@@ -89,6 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
        const struct exception_table_entry *fixup;
        int fault, si_code = SEGV_MAPERR;
        siginfo_t info;
+       unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+                             (cause > 0 ? FAULT_FLAG_WRITE : 0));
 
        /* As of EV6, a load into $31/$f31 is a prefetch, and never faults
           (or is suppressed by the PALcode).  Support that for older CPUs
@@ -114,6 +116,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
                goto vmalloc_fault;
 #endif
 
+retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
@@ -144,8 +147,11 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
        /* If for any reason at all we couldn't handle the fault,
           make sure we exit gracefully rather than endlessly redo
           the fault.  */
-       fault = handle_mm_fault(mm, vma, address, cause > 0 ? FAULT_FLAG_WRITE : 0);
-       up_read(&mm->mmap_sem);
+       fault = handle_mm_fault(mm, vma, address, flags);
+
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+               return;
+
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
@@ -153,10 +159,26 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
                        goto do_sigbus;
                BUG();
        }
-       if (fault & VM_FAULT_MAJOR)
-               current->maj_flt++;
-       else
-               current->min_flt++;
+
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               if (fault & VM_FAULT_MAJOR)
+                       current->maj_flt++;
+               else
+                       current->min_flt++;
+               if (fault & VM_FAULT_RETRY) {
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+                        /* No need to up_read(&mm->mmap_sem) as we would
+                        * have already released it in __lock_page_or_retry
+                        * in mm/filemap.c.
+                        */
+
+                       goto retry;
+               }
+       }
+
+       up_read(&mm->mmap_sem);
+
        return;
 
        /* Something tried to access memory that isn't in our memory map.
@@ -186,12 +208,14 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
        /* We ran out of memory, or some other thing happened to us that
           made us unable to handle the page fault gracefully.  */
  out_of_memory:
+       up_read(&mm->mmap_sem);
        if (!user_mode(regs))
                goto no_context;
        pagefault_out_of_memory();
        return;
 
  do_sigbus:
+       up_read(&mm->mmap_sem);
        /* Send a sigbus, regardless of whether we were in kernel
           or user mode.  */
        info.si_signo = SIGBUS;
index a0a5d27aa2150e48c840cfcdae78f43f5bc8c4dd..b8ce18f485d3ecce23d9903138eeb930ab62cb4d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <asm/ptrace.h>
+#include <asm/special_insns.h>
 
 #include "op_impl.h"
 
index e91c7cdc6fe5c5ae370fa8be0f3a3c51a0b49beb..6d6e18fee9fe08bacf876e749837d4b0156a5fd9 100644 (file)
@@ -38,7 +38,6 @@ config ARM
        select HARDIRQS_SW_RESEND
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
-       select GENERIC_IRQ_PROBE
        select ARCH_WANT_IPC_PARSE_VERSION
        select HARDIRQS_SW_RESEND
        select CPU_PM if (SUSPEND || CPU_IDLE)
@@ -126,11 +125,6 @@ config TRACE_IRQFLAGS_SUPPORT
        bool
        default y
 
-config GENERIC_LOCKBREAK
-       bool
-       default y
-       depends on SMP && PREEMPT
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
index a874dbfb5ae69da5d6771c75d9605ca3bbbcbcaa..e6138310e5ced961a269b903fadcfff6869c7be2 100644 (file)
 
                        dma-apbh@80004000 {
                                compatible = "fsl,imx23-dma-apbh";
-                               reg = <0x80004000 2000>;
+                               reg = <0x80004000 0x2000>;
                        };
 
                        ecc@80008000 {
-                               reg = <0x80008000 2000>;
+                               reg = <0x80008000 0x2000>;
                                status = "disabled";
                        };
 
@@ -63,7 +63,7 @@
                                compatible = "fsl,imx23-gpmi-nand";
                                #address-cells = <1>;
                                #size-cells = <1>;
-                               reg = <0x8000c000 2000>, <0x8000a000 2000>;
+                               reg = <0x8000c000 0x2000>, <0x8000a000 0x2000>;
                                reg-names = "gpmi-nand", "bch";
                                interrupts = <13>, <56>;
                                interrupt-names = "gpmi-dma", "bch";
                        };
 
                        ssp0: ssp@80010000 {
-                               reg = <0x80010000 2000>;
+                               reg = <0x80010000 0x2000>;
                                interrupts = <15 14>;
                                fsl,ssp-dma-channel = <1>;
                                status = "disabled";
                        };
 
                        etm@80014000 {
-                               reg = <0x80014000 2000>;
+                               reg = <0x80014000 0x2000>;
                                status = "disabled";
                        };
 
@@ -87,7 +87,7 @@
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx23-pinctrl", "simple-bus";
-                               reg = <0x80018000 2000>;
+                               reg = <0x80018000 0x2000>;
 
                                gpio0: gpio@0 {
                                        compatible = "fsl,imx23-gpio", "fsl,mxs-gpio";
                        };
 
                        emi@80020000 {
-                               reg = <0x80020000 2000>;
+                               reg = <0x80020000 0x2000>;
                                status = "disabled";
                        };
 
                        dma-apbx@80024000 {
                                compatible = "fsl,imx23-dma-apbx";
-                               reg = <0x80024000 2000>;
+                               reg = <0x80024000 0x2000>;
                        };
 
                        dcp@80028000 {
-                               reg = <0x80028000 2000>;
+                               reg = <0x80028000 0x2000>;
                                status = "disabled";
                        };
 
                        pxp@8002a000 {
-                               reg = <0x8002a000 2000>;
+                               reg = <0x8002a000 0x2000>;
                                status = "disabled";
                        };
 
                        ocotp@8002c000 {
-                               reg = <0x8002c000 2000>;
+                               reg = <0x8002c000 0x2000>;
                                status = "disabled";
                        };
 
                        axi-ahb@8002e000 {
-                               reg = <0x8002e000 2000>;
+                               reg = <0x8002e000 0x2000>;
                                status = "disabled";
                        };
 
                        };
 
                        ssp1: ssp@80034000 {
-                               reg = <0x80034000 2000>;
+                               reg = <0x80034000 0x2000>;
                                interrupts = <2 20>;
                                fsl,ssp-dma-channel = <2>;
                                status = "disabled";
                        };
 
                        tvenc@80038000 {
-                               reg = <0x80038000 2000>;
+                               reg = <0x80038000 0x2000>;
                                status = "disabled";
                        };
                 };
                        ranges;
 
                        clkctl@80040000 {
-                               reg = <0x80040000 2000>;
+                               reg = <0x80040000 0x2000>;
                                status = "disabled";
                        };
 
                        saif0: saif@80042000 {
-                               reg = <0x80042000 2000>;
+                               reg = <0x80042000 0x2000>;
                                status = "disabled";
                        };
 
                        power@80044000 {
-                               reg = <0x80044000 2000>;
+                               reg = <0x80044000 0x2000>;
                                status = "disabled";
                        };
 
                        saif1: saif@80046000 {
-                               reg = <0x80046000 2000>;
+                               reg = <0x80046000 0x2000>;
                                status = "disabled";
                        };
 
                        audio-out@80048000 {
-                               reg = <0x80048000 2000>;
+                               reg = <0x80048000 0x2000>;
                                status = "disabled";
                        };
 
                        audio-in@8004c000 {
-                               reg = <0x8004c000 2000>;
+                               reg = <0x8004c000 0x2000>;
                                status = "disabled";
                        };
 
                        lradc@80050000 {
-                               reg = <0x80050000 2000>;
+                               reg = <0x80050000 0x2000>;
                                status = "disabled";
                        };
 
                        };
 
                        i2c@80058000 {
-                               reg = <0x80058000 2000>;
+                               reg = <0x80058000 0x2000>;
                                status = "disabled";
                        };
 
                        rtc@8005c000 {
                                compatible = "fsl,imx23-rtc", "fsl,stmp3xxx-rtc";
-                               reg = <0x8005c000 2000>;
+                               reg = <0x8005c000 0x2000>;
                                interrupts = <22>;
                        };
 
                        pwm: pwm@80064000 {
                                compatible = "fsl,imx23-pwm";
-                               reg = <0x80064000 2000>;
+                               reg = <0x80064000 0x2000>;
                                #pwm-cells = <2>;
                                fsl,pwm-number = <5>;
                                status = "disabled";
                        };
 
                        timrot@80068000 {
-                               reg = <0x80068000 2000>;
+                               reg = <0x80068000 0x2000>;
                                status = "disabled";
                        };
 
                ranges;
 
                usbctrl@80080000 {
-                       reg = <0x80080000 0x10000>;
+                       reg = <0x80080000 0x40000>;
                        status = "disabled";
                };
        };
index d3f8296e19e0828ea1bd94e88ef04a9467327e21..0a8978a40ecef73d826c12be5d7970b2120195da 100644 (file)
@@ -27,7 +27,7 @@
                                status = "okay";
                        };
 
-                       uart@1000a000 {
+                       uart1: serial@1000a000 {
                                fsl,uart-has-rtscts;
                                status = "okay";
                        };
index 00bae3aad5ab601f7a21adf4da8539aa48880781..5303ab680a3461614e324b27ed455f7da01b253d 100644 (file)
                serial3 = &uart4;
                serial4 = &uart5;
                serial5 = &uart6;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+               gpio5 = &gpio6;
        };
 
        avic: avic-interrupt-controller@e0000000 {
index 787efac68da81b81f79318a0ac55817eb92c8879..3fa6d190fab4f9a2c1c4c47abc8904bce199b0da 100644 (file)
                        };
 
                        hsadc@80002000 {
-                               reg = <0x80002000 2000>;
+                               reg = <0x80002000 0x2000>;
                                interrupts = <13 87>;
                                status = "disabled";
                        };
 
                        dma-apbh@80004000 {
                                compatible = "fsl,imx28-dma-apbh";
-                               reg = <0x80004000 2000>;
+                               reg = <0x80004000 0x2000>;
                        };
 
                        perfmon@80006000 {
-                               reg = <0x80006000 800>;
+                               reg = <0x80006000 0x800>;
                                interrupts = <27>;
                                status = "disabled";
                        };
@@ -77,7 +77,7 @@
                                compatible = "fsl,imx28-gpmi-nand";
                                #address-cells = <1>;
                                #size-cells = <1>;
-                               reg = <0x8000c000 2000>, <0x8000a000 2000>;
+                               reg = <0x8000c000 0x2000>, <0x8000a000 0x2000>;
                                reg-names = "gpmi-nand", "bch";
                                interrupts = <88>, <41>;
                                interrupt-names = "gpmi-dma", "bch";
                        };
 
                        ssp0: ssp@80010000 {
-                               reg = <0x80010000 2000>;
+                               reg = <0x80010000 0x2000>;
                                interrupts = <96 82>;
                                fsl,ssp-dma-channel = <0>;
                                status = "disabled";
                        };
 
                        ssp1: ssp@80012000 {
-                               reg = <0x80012000 2000>;
+                               reg = <0x80012000 0x2000>;
                                interrupts = <97 83>;
                                fsl,ssp-dma-channel = <1>;
                                status = "disabled";
                        };
 
                        ssp2: ssp@80014000 {
-                               reg = <0x80014000 2000>;
+                               reg = <0x80014000 0x2000>;
                                interrupts = <98 84>;
                                fsl,ssp-dma-channel = <2>;
                                status = "disabled";
                        };
 
                        ssp3: ssp@80016000 {
-                               reg = <0x80016000 2000>;
+                               reg = <0x80016000 0x2000>;
                                interrupts = <99 85>;
                                fsl,ssp-dma-channel = <3>;
                                status = "disabled";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx28-pinctrl", "simple-bus";
-                               reg = <0x80018000 2000>;
+                               reg = <0x80018000 0x2000>;
 
                                gpio0: gpio@0 {
                                        compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
                        };
 
                        digctl@8001c000 {
-                               reg = <0x8001c000 2000>;
+                               reg = <0x8001c000 0x2000>;
                                interrupts = <89>;
                                status = "disabled";
                        };
 
                        etm@80022000 {
-                               reg = <0x80022000 2000>;
+                               reg = <0x80022000 0x2000>;
                                status = "disabled";
                        };
 
                        dma-apbx@80024000 {
                                compatible = "fsl,imx28-dma-apbx";
-                               reg = <0x80024000 2000>;
+                               reg = <0x80024000 0x2000>;
                        };
 
                        dcp@80028000 {
-                               reg = <0x80028000 2000>;
+                               reg = <0x80028000 0x2000>;
                                interrupts = <52 53 54>;
                                status = "disabled";
                        };
 
                        pxp@8002a000 {
-                               reg = <0x8002a000 2000>;
+                               reg = <0x8002a000 0x2000>;
                                interrupts = <39>;
                                status = "disabled";
                        };
 
                        ocotp@8002c000 {
-                               reg = <0x8002c000 2000>;
+                               reg = <0x8002c000 0x2000>;
                                status = "disabled";
                        };
 
                        axi-ahb@8002e000 {
-                               reg = <0x8002e000 2000>;
+                               reg = <0x8002e000 0x2000>;
                                status = "disabled";
                        };
 
                        lcdif@80030000 {
                                compatible = "fsl,imx28-lcdif";
-                               reg = <0x80030000 2000>;
+                               reg = <0x80030000 0x2000>;
                                interrupts = <38 86>;
                                status = "disabled";
                        };
 
                        can0: can@80032000 {
                                compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan";
-                               reg = <0x80032000 2000>;
+                               reg = <0x80032000 0x2000>;
                                interrupts = <8>;
                                status = "disabled";
                        };
 
                        can1: can@80034000 {
                                compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan";
-                               reg = <0x80034000 2000>;
+                               reg = <0x80034000 0x2000>;
                                interrupts = <9>;
                                status = "disabled";
                        };
 
                        simdbg@8003c000 {
-                               reg = <0x8003c000 200>;
+                               reg = <0x8003c000 0x200>;
                                status = "disabled";
                        };
 
                        simgpmisel@8003c200 {
-                               reg = <0x8003c200 100>;
+                               reg = <0x8003c200 0x100>;
                                status = "disabled";
                        };
 
                        simsspsel@8003c300 {
-                               reg = <0x8003c300 100>;
+                               reg = <0x8003c300 0x100>;
                                status = "disabled";
                        };
 
                        simmemsel@8003c400 {
-                               reg = <0x8003c400 100>;
+                               reg = <0x8003c400 0x100>;
                                status = "disabled";
                        };
 
                        gpiomon@8003c500 {
-                               reg = <0x8003c500 100>;
+                               reg = <0x8003c500 0x100>;
                                status = "disabled";
                        };
 
                        simenet@8003c700 {
-                               reg = <0x8003c700 100>;
+                               reg = <0x8003c700 0x100>;
                                status = "disabled";
                        };
 
                        armjtag@8003c800 {
-                               reg = <0x8003c800 100>;
+                               reg = <0x8003c800 0x100>;
                                status = "disabled";
                        };
                 };
                        ranges;
 
                        clkctl@80040000 {
-                               reg = <0x80040000 2000>;
+                               reg = <0x80040000 0x2000>;
                                status = "disabled";
                        };
 
                        saif0: saif@80042000 {
                                compatible = "fsl,imx28-saif";
-                               reg = <0x80042000 2000>;
+                               reg = <0x80042000 0x2000>;
                                interrupts = <59 80>;
                                fsl,saif-dma-channel = <4>;
                                status = "disabled";
                        };
 
                        power@80044000 {
-                               reg = <0x80044000 2000>;
+                               reg = <0x80044000 0x2000>;
                                status = "disabled";
                        };
 
                        saif1: saif@80046000 {
                                compatible = "fsl,imx28-saif";
-                               reg = <0x80046000 2000>;
+                               reg = <0x80046000 0x2000>;
                                interrupts = <58 81>;
                                fsl,saif-dma-channel = <5>;
                                status = "disabled";
                        };
 
                        lradc@80050000 {
-                               reg = <0x80050000 2000>;
+                               reg = <0x80050000 0x2000>;
                                status = "disabled";
                        };
 
                        spdif@80054000 {
-                               reg = <0x80054000 2000>;
+                               reg = <0x80054000 0x2000>;
                                interrupts = <45 66>;
                                status = "disabled";
                        };
 
                        rtc@80056000 {
                                compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc";
-                               reg = <0x80056000 2000>;
+                               reg = <0x80056000 0x2000>;
                                interrupts = <29>;
                        };
 
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx28-i2c";
-                               reg = <0x80058000 2000>;
+                               reg = <0x80058000 0x2000>;
                                interrupts = <111 68>;
                                clock-frequency = <100000>;
                                status = "disabled";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx28-i2c";
-                               reg = <0x8005a000 2000>;
+                               reg = <0x8005a000 0x2000>;
                                interrupts = <110 69>;
                                clock-frequency = <100000>;
                                status = "disabled";
 
                        pwm: pwm@80064000 {
                                compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
-                               reg = <0x80064000 2000>;
+                               reg = <0x80064000 0x2000>;
                                #pwm-cells = <2>;
                                fsl,pwm-number = <8>;
                                status = "disabled";
                        };
 
                        timrot@80068000 {
-                               reg = <0x80068000 2000>;
+                               reg = <0x80068000 0x2000>;
                                status = "disabled";
                        };
 
index de065b5976e6cf0ed025c7e550198f4b079b817c..cd86177a3ea21aa1dbe3d0dcea633b50661e5552 100644 (file)
@@ -53,7 +53,7 @@
                                                spi-max-frequency = <6000000>;
                                                reg = <0>;
                                                interrupt-parent = <&gpio1>;
-                                               interrupts = <8>;
+                                               interrupts = <8 0x4>;
 
                                                regulators {
                                                        sw1_reg: sw1 {
index 53cbaa3d4f904cbe464116640824fd24a4015d81..aba28dc87fc80b3d064b5acb0861ab80eec4eca1 100644 (file)
                serial0 = &uart1;
                serial1 = &uart2;
                serial2 = &uart3;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
        };
 
        tzic: tz-interrupt-controller@e0000000 {
index 5b8eafcdbeec638009a894365b577df17256b3c0..da895e93a999113e0585905126dd980f3029e80b 100644 (file)
                        reg = <0xf4000000 0x2000000>;
                        phy-mode = "mii";
                        interrupt-parent = <&gpio2>;
-                       interrupts = <31>;
+                       interrupts = <31 0x8>;
                        reg-io-width = <4>;
+                       /*
+                        * VDD33A and VDDVARIO of LAN9220 are supplied by
+                        * SW4_3V3 of LTC3589.  Before the regulator driver
+                        * for this PMIC is available, we use a fixed dummy
+                        * 3V3 regulator to get LAN9220 driver probing work.
+                        */
+                       vdd33a-supply = <&reg_3p3v>;
+                       vddvario-supply = <&reg_3p3v>;
                        smsc,irq-push-pull;
                };
        };
 
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+       };
+
        gpio-keys {
                compatible = "gpio-keys";
 
index fc79cdc4b4e6a18d96138025bad146caabb04004..cd37165edce5e5d2f06628813c01e17181aa8b8d 100644 (file)
                serial2 = &uart3;
                serial3 = &uart4;
                serial4 = &uart5;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+               gpio5 = &gpio6;
+               gpio6 = &gpio7;
        };
 
        tzic: tz-interrupt-controller@0fffc000 {
index d42e851ceb97e423fd785e3cd357ba6d70b23d8c..72f30f3e6171b4b737d122333c03a25a37189ddb 100644 (file)
@@ -53,6 +53,7 @@
                                                fsl,pins = <
                                                           144  0x80000000      /* MX6Q_PAD_EIM_D22__GPIO_3_22 */
                                                           121  0x80000000      /* MX6Q_PAD_EIM_D19__GPIO_3_19 */
+                                                          953  0x80000000      /* MX6Q_PAD_GPIO_0__CCM_CLKO */
                                                           >;
                                        };
                                };
index 3d3c64b014e61f9978072571343f6b84afb5f523..fd57079f71a95281d107da8df2328c37df8cc1d6 100644 (file)
                serial2 = &uart3;
                serial3 = &uart4;
                serial4 = &uart5;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+               gpio5 = &gpio6;
+               gpio6 = &gpio7;
        };
 
        cpus {
index f725b9637b3374a4079c17ca50823f064ea0bb6d..3c9f32f9b6b4dc6e5b77884deaa216c87684919c 100644 (file)
@@ -192,6 +192,7 @@ CONFIG_RTC_DRV_MC13XXX=y
 CONFIG_RTC_DRV_MXC=y
 CONFIG_DMADEVICES=y
 CONFIG_IMX_SDMA=y
+CONFIG_MXS_DMA=y
 CONFIG_COMMON_CLK_DEBUG=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT2_FS=y
index ccdb6357fb74065e017d44527a27e8c2c7a3f46d..4edcfb4e4deeea476d9b5007779153d2281643b8 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_AEABI=y
-CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
 CONFIG_AUTO_ZRELADDR=y
 CONFIG_FPE_NWFPE=y
 CONFIG_NET=y
index 1d24f8458befd49cd41b98e6fb1d6f22fcca8f94..71277a1591bad96d77036ad8eb2557af2a6d4c54 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_BUG is not set
+# CONFIG_BUGVERBOSE is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_SHMEM is not set
 CONFIG_SLOB=y
index f66626d71e7d1a304ad2c750fc4b00be9a436901..41dc31f834c3b68926a070036ac024b83f8e7b66 100644 (file)
@@ -195,6 +195,18 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 
 #define pte_clear(mm,addr,ptep)        set_pte_ext(ptep, __pte(0), 0)
 
+#define pte_none(pte)          (!pte_val(pte))
+#define pte_present(pte)       (pte_val(pte) & L_PTE_PRESENT)
+#define pte_write(pte)         (!(pte_val(pte) & L_PTE_RDONLY))
+#define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
+#define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)          (!(pte_val(pte) & L_PTE_XN))
+#define pte_special(pte)       (0)
+
+#define pte_present_user(pte) \
+       ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+        (L_PTE_PRESENT | L_PTE_USER))
+
 #if __LINUX_ARM_ARCH__ < 6
 static inline void __sync_icache_dcache(pte_t pteval)
 {
@@ -206,25 +218,15 @@ extern void __sync_icache_dcache(pte_t pteval);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
-       if (addr >= TASK_SIZE)
-               set_pte_ext(ptep, pteval, 0);
-       else {
+       unsigned long ext = 0;
+
+       if (addr < TASK_SIZE && pte_present_user(pteval)) {
                __sync_icache_dcache(pteval);
-               set_pte_ext(ptep, pteval, PTE_EXT_NG);
+               ext |= PTE_EXT_NG;
        }
-}
 
-#define pte_none(pte)          (!pte_val(pte))
-#define pte_present(pte)       (pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte)         (!(pte_val(pte) & L_PTE_RDONLY))
-#define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
-#define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
-#define pte_exec(pte)          (!(pte_val(pte) & L_PTE_XN))
-#define pte_special(pte)       (0)
-
-#define pte_present_user(pte) \
-       ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
-        (L_PTE_PRESENT | L_PTE_USER))
+       set_pte_ext(ptep, pteval, ext);
+}
 
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -251,13 +253,13 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  *
  *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   <--------------- offset --------------------> <- type --> 0 0 0
+ *   <--------------- offset ----------------------> < type -> 0 0 0
  *
- * This gives us up to 63 swap files and 32GB per swap file.  Note that
+ * This gives us up to 31 swap files and 64GB per swap file.  Note that
  * the offset field is always non-zero.
  */
 #define __SWP_TYPE_SHIFT       3
-#define __SWP_TYPE_BITS                6
+#define __SWP_TYPE_BITS                5
 #define __SWP_TYPE_MASK                ((1 << __SWP_TYPE_BITS) - 1)
 #define __SWP_OFFSET_SHIFT     (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
 
index e3f7572634381bd28fbf3225eb375788431ee3fc..05b8e82ec9f5b66744305de1094df1115fc92798 100644 (file)
@@ -10,5 +10,7 @@
 
 extern void sched_clock_postinit(void);
 extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
+extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
+               unsigned long rate);
 
 #endif
index 27d186abbc06f8aa3aa6310faa5b67039d447f03..f4515393248dab76b97700f55ef17bba68e6cd0a 100644 (file)
@@ -21,6 +21,8 @@ struct clock_data {
        u32 epoch_cyc_copy;
        u32 mult;
        u32 shift;
+       bool suspended;
+       bool needs_suspend;
 };
 
 static void sched_clock_poll(unsigned long wrap_ticks);
@@ -49,6 +51,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
        u64 epoch_ns;
        u32 epoch_cyc;
 
+       if (cd.suspended)
+               return cd.epoch_ns;
+
        /*
         * Load the epoch_cyc and epoch_ns atomically.  We do this by
         * ensuring that we always write epoch_cyc, epoch_ns and
@@ -98,6 +103,13 @@ static void sched_clock_poll(unsigned long wrap_ticks)
        update_sched_clock();
 }
 
+void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
+               unsigned long rate)
+{
+       setup_sched_clock(read, bits, rate);
+       cd.needs_suspend = true;
+}
+
 void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 {
        unsigned long r, w;
@@ -169,11 +181,23 @@ void __init sched_clock_postinit(void)
 static int sched_clock_suspend(void)
 {
        sched_clock_poll(sched_clock_timer.data);
+       if (cd.needs_suspend)
+               cd.suspended = true;
        return 0;
 }
 
+static void sched_clock_resume(void)
+{
+       if (cd.needs_suspend) {
+               cd.epoch_cyc = read_sched_clock();
+               cd.epoch_cyc_copy = cd.epoch_cyc;
+               cd.suspended = false;
+       }
+}
+
 static struct syscore_ops sched_clock_ops = {
        .suspend = sched_clock_suspend,
+       .resume = sched_clock_resume,
 };
 
 static int __init sched_clock_syscore_init(void)
index 198b08456e905e42d1c09819083c003d9a59e988..26c12c6440fcde02a3829f1ed3e1035f16ed6338 100644 (file)
@@ -321,7 +321,7 @@ void store_cpu_topology(unsigned int cpuid)
  * init_cpu_topology is called at boot when only one cpu is running
  * which prevent simultaneous write access to cpu_topology array
  */
-void init_cpu_topology(void)
+void __init init_cpu_topology(void)
 {
        unsigned int cpu;
 
index 2473fd1fd51cfa50ef02985e6e8d83c5f97119c8..af72969820b4951448c9d95135383ae9d8387cde 100644 (file)
@@ -16,13 +16,30 @@ lib-y               := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   call_with_stack.o
 
 mmu-y  := clear_user.o copy_page.o getuser.o putuser.o
-mmu-y  += copy_from_user.o copy_to_user.o
+
+# the code in uaccess.S is not preemption safe and
+# probably faster on ARMv3 only
+ifeq ($(CONFIG_PREEMPT),y)
+  mmu-y        += copy_from_user.o copy_to_user.o
+else
+ifneq ($(CONFIG_CPU_32v3),y)
+  mmu-y        += copy_from_user.o copy_to_user.o
+else
+  mmu-y        += uaccess.o
+endif
+endif
 
 # using lib_ here won't override already available weak symbols
 obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
 
-lib-$(CONFIG_MMU)              += $(mmu-y)
-lib-y                          += io-readsw-armv4.o io-writesw-armv4.o
+lib-$(CONFIG_MMU) += $(mmu-y)
+
+ifeq ($(CONFIG_CPU_32v3),y)
+  lib-y        += io-readsw-armv3.o io-writesw-armv3.o
+else
+  lib-y        += io-readsw-armv4.o io-writesw-armv4.o
+endif
+
 lib-$(CONFIG_ARCH_RPC)         += ecard.o io-acorn.o floppydma.o
 lib-$(CONFIG_ARCH_SHARK)       += io-shark.o
 
diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S
new file mode 100644 (file)
index 0000000..88487c8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  linux/arch/arm/lib/io-readsw-armv3.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * 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 <linux/linkage.h>
+#include <asm/assembler.h>
+
+.Linsw_bad_alignment:
+               adr     r0, .Linsw_bad_align_msg
+               mov     r2, lr
+               b       panic
+.Linsw_bad_align_msg:
+               .asciz  "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n"
+               .align
+
+.Linsw_align:  tst     r1, #1
+               bne     .Linsw_bad_alignment
+
+               ldr     r3, [r0]
+               strb    r3, [r1], #1
+               mov     r3, r3, lsr #8
+               strb    r3, [r1], #1
+
+               subs    r2, r2, #1
+               moveq   pc, lr
+
+ENTRY(__raw_readsw)
+               teq     r2, #0          @ do we have to check for the zero len?
+               moveq   pc, lr
+               tst     r1, #3
+               bne     .Linsw_align
+
+.Linsw_aligned:        mov     ip, #0xff
+               orr     ip, ip, ip, lsl #8
+               stmfd   sp!, {r4, r5, r6, lr}
+
+               subs    r2, r2, #8
+               bmi     .Lno_insw_8
+
+.Linsw_8_lp:   ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               ldr     r4, [r0]
+               and     r4, r4, ip
+               ldr     r5, [r0]
+               orr     r4, r4, r5, lsl #16
+
+               ldr     r5, [r0]
+               and     r5, r5, ip
+               ldr     r6, [r0]
+               orr     r5, r5, r6, lsl #16
+
+               ldr     r6, [r0]
+               and     r6, r6, ip
+               ldr     lr, [r0]
+               orr     r6, r6, lr, lsl #16
+
+               stmia   r1!, {r3 - r6}
+
+               subs    r2, r2, #8
+               bpl     .Linsw_8_lp
+
+               tst     r2, #7
+               ldmeqfd sp!, {r4, r5, r6, pc}
+
+.Lno_insw_8:   tst     r2, #4
+               beq     .Lno_insw_4
+
+               ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               ldr     r4, [r0]
+               and     r4, r4, ip
+               ldr     r5, [r0]
+               orr     r4, r4, r5, lsl #16
+
+               stmia   r1!, {r3, r4}
+
+.Lno_insw_4:   tst     r2, #2
+               beq     .Lno_insw_2
+
+               ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               str     r3, [r1], #4
+
+.Lno_insw_2:   tst     r2, #1
+               ldrne   r3, [r0]
+               strneb  r3, [r1], #1
+               movne   r3, r3, lsr #8
+               strneb  r3, [r1]
+
+               ldmfd   sp!, {r4, r5, r6, pc}
+
+
diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S
new file mode 100644 (file)
index 0000000..49b8004
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  linux/arch/arm/lib/io-writesw-armv3.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * 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 <linux/linkage.h>
+#include <asm/assembler.h>
+
+.Loutsw_bad_alignment:
+               adr     r0, .Loutsw_bad_align_msg
+               mov     r2, lr
+               b       panic
+.Loutsw_bad_align_msg:
+               .asciz  "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n"
+               .align
+
+.Loutsw_align: tst     r1, #1
+               bne     .Loutsw_bad_alignment
+
+               add     r1, r1, #2
+
+               ldr     r3, [r1, #-4]
+               mov     r3, r3, lsr #16
+               orr     r3, r3, r3, lsl #16
+               str     r3, [r0]
+               subs    r2, r2, #1
+               moveq   pc, lr
+
+ENTRY(__raw_writesw)
+               teq     r2, #0          @ do we have to check for the zero len?
+               moveq   pc, lr
+               tst     r1, #3
+               bne     .Loutsw_align
+
+               stmfd   sp!, {r4, r5, r6, lr}
+
+               subs    r2, r2, #8
+               bmi     .Lno_outsw_8
+
+.Loutsw_8_lp:  ldmia   r1!, {r3, r4, r5, r6}
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r5, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r5, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r6, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r6, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               subs    r2, r2, #8
+               bpl     .Loutsw_8_lp
+
+               tst     r2, #7
+               ldmeqfd sp!, {r4, r5, r6, pc}
+
+.Lno_outsw_8:  tst     r2, #4
+               beq     .Lno_outsw_4
+
+               ldmia   r1!, {r3, r4}
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+.Lno_outsw_4:  tst     r2, #2
+               beq     .Lno_outsw_2
+
+               ldr     r3, [r1], #4
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+.Lno_outsw_2:  tst     r2, #1
+
+               ldrne   r3, [r1]
+
+               movne   ip, r3, lsl #16
+               orrne   ip, ip, ip, lsr #16
+               strne   ip, [r0]
+
+               ldmfd   sp!, {r4, r5, r6, pc}
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S
new file mode 100644 (file)
index 0000000..5c908b1
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ *  linux/arch/arm/lib/uaccess.S
+ *
+ *  Copyright (C) 1995, 1996,1997,1998 Russell King
+ *
+ * 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.
+ *
+ *  Routines to block copy data to/from user memory
+ *   These are highly optimised both for the 4k page size
+ *   and for various alignments.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include <asm/domain.h>
+
+               .text
+
+#define PAGE_SHIFT 12
+
+/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
+ * Purpose  : copy a block to user memory from kernel memory
+ * Params   : to   - user memory
+ *          : from - kernel memory
+ *          : n    - number of bytes to copy
+ * Returns  : Number of bytes NOT copied.
+ */
+
+.Lc2u_dest_not_aligned:
+               rsb     ip, ip, #4
+               cmp     ip, #2
+               ldrb    r3, [r1], #1
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               ldrgeb  r3, [r1], #1
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #1
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               sub     r2, r2, ip
+               b       .Lc2u_dest_aligned
+
+ENTRY(__copy_to_user)
+               stmfd   sp!, {r2, r4 - r7, lr}
+               cmp     r2, #4
+               blt     .Lc2u_not_enough
+               ands    ip, r0, #3
+               bne     .Lc2u_dest_not_aligned
+.Lc2u_dest_aligned:
+
+               ands    ip, r1, #3
+               bne     .Lc2u_src_not_aligned
+/*
+ * Seeing as there has to be at least 8 bytes to copy, we can
+ * copy one word, and force a user-mode page fault...
+ */
+
+.Lc2u_0fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_0nowords
+               ldr     r3, [r1], #4
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT    @ On each page, use a ld/st??t instruction
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_0fupi
+/*
+ * ip = max no. of bytes to copy before needing another "strt" insn
+ */
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #32
+               blt     .Lc2u_0rem8lp
+
+.Lc2u_0cpy8lp: ldmia   r1!, {r3 - r6}
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               ldmia   r1!, {r3 - r6}
+               subs    ip, ip, #32
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_0cpy8lp
+
+.Lc2u_0rem8lp: cmn     ip, #16
+               ldmgeia r1!, {r3 - r6}
+               stmgeia r0!, {r3 - r6}                  @ Shouldnt fault
+               tst     ip, #8
+               ldmneia r1!, {r3 - r4}
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               ldrne   r3, [r1], #4
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_0fupi
+.Lc2u_0nowords:        teq     ip, #0
+               beq     .Lc2u_finished
+.Lc2u_nowords: cmp     ip, #2
+               ldrb    r3, [r1], #1
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               ldrgeb  r3, [r1], #1
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #1
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+
+.Lc2u_not_enough:
+               movs    ip, r2
+               bne     .Lc2u_nowords
+.Lc2u_finished:        mov     r0, #0
+               ldmfd   sp!, {r2, r4 - r7, pc}
+
+.Lc2u_src_not_aligned:
+               bic     r1, r1, #3
+               ldr     r7, [r1], #4
+               cmp     ip, #2
+               bgt     .Lc2u_3fupi
+               beq     .Lc2u_2fupi
+.Lc2u_1fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_1nowords
+               mov     r3, r7, pull #8
+               ldr     r7, [r1], #4
+               orr     r3, r3, r7, push #24
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_1fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lc2u_1rem8lp
+
+.Lc2u_1cpy8lp: mov     r3, r7, pull #8
+               ldmia   r1!, {r4 - r7}
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #24
+               mov     r4, r4, pull #8
+               orr     r4, r4, r5, push #24
+               mov     r5, r5, pull #8
+               orr     r5, r5, r6, push #24
+               mov     r6, r6, pull #8
+               orr     r6, r6, r7, push #24
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_1cpy8lp
+
+.Lc2u_1rem8lp: tst     ip, #8
+               movne   r3, r7, pull #8
+               ldmneia r1!, {r4, r7}
+               orrne   r3, r3, r4, push #24
+               movne   r4, r4, pull #8
+               orrne   r4, r4, r7, push #24
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               movne   r3, r7, pull #8
+               ldrne   r7, [r1], #4
+               orrne   r3, r3, r7, push #24
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_1fupi
+.Lc2u_1nowords:        mov     r3, r7, get_byte_1
+               teq     ip, #0
+               beq     .Lc2u_finished
+               cmp     ip, #2
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               movge   r3, r7, get_byte_2
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               movgt   r3, r7, get_byte_3
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+
+.Lc2u_2fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_2nowords
+               mov     r3, r7, pull #16
+               ldr     r7, [r1], #4
+               orr     r3, r3, r7, push #16
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_2fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lc2u_2rem8lp
+
+.Lc2u_2cpy8lp: mov     r3, r7, pull #16
+               ldmia   r1!, {r4 - r7}
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #16
+               mov     r4, r4, pull #16
+               orr     r4, r4, r5, push #16
+               mov     r5, r5, pull #16
+               orr     r5, r5, r6, push #16
+               mov     r6, r6, pull #16
+               orr     r6, r6, r7, push #16
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_2cpy8lp
+
+.Lc2u_2rem8lp: tst     ip, #8
+               movne   r3, r7, pull #16
+               ldmneia r1!, {r4, r7}
+               orrne   r3, r3, r4, push #16
+               movne   r4, r4, pull #16
+               orrne   r4, r4, r7, push #16
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               movne   r3, r7, pull #16
+               ldrne   r7, [r1], #4
+               orrne   r3, r3, r7, push #16
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_2fupi
+.Lc2u_2nowords:        mov     r3, r7, get_byte_2
+               teq     ip, #0
+               beq     .Lc2u_finished
+               cmp     ip, #2
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               movge   r3, r7, get_byte_3
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #0
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+
+.Lc2u_3fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_3nowords
+               mov     r3, r7, pull #24
+               ldr     r7, [r1], #4
+               orr     r3, r3, r7, push #8
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_3fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lc2u_3rem8lp
+
+.Lc2u_3cpy8lp: mov     r3, r7, pull #24
+               ldmia   r1!, {r4 - r7}
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #8
+               mov     r4, r4, pull #24
+               orr     r4, r4, r5, push #8
+               mov     r5, r5, pull #24
+               orr     r5, r5, r6, push #8
+               mov     r6, r6, pull #24
+               orr     r6, r6, r7, push #8
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_3cpy8lp
+
+.Lc2u_3rem8lp: tst     ip, #8
+               movne   r3, r7, pull #24
+               ldmneia r1!, {r4, r7}
+               orrne   r3, r3, r4, push #8
+               movne   r4, r4, pull #24
+               orrne   r4, r4, r7, push #8
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               movne   r3, r7, pull #24
+               ldrne   r7, [r1], #4
+               orrne   r3, r3, r7, push #8
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_3fupi
+.Lc2u_3nowords:        mov     r3, r7, get_byte_3
+               teq     ip, #0
+               beq     .Lc2u_finished
+               cmp     ip, #2
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               ldrgeb  r3, [r1], #1
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #0
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+ENDPROC(__copy_to_user)
+
+               .pushsection .fixup,"ax"
+               .align  0
+9001:          ldmfd   sp!, {r0, r4 - r7, pc}
+               .popsection
+
+/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
+ * Purpose  : copy a block from user memory to kernel memory
+ * Params   : to   - kernel memory
+ *          : from - user memory
+ *          : n    - number of bytes to copy
+ * Returns  : Number of bytes NOT copied.
+ */
+.Lcfu_dest_not_aligned:
+               rsb     ip, ip, #4
+               cmp     ip, #2
+USER(  TUSER(  ldrb)   r3, [r1], #1)                   @ May fault
+               strb    r3, [r0], #1
+USER(  TUSER(  ldrgeb) r3, [r1], #1)                   @ May fault
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #1)                   @ May fault
+               strgtb  r3, [r0], #1
+               sub     r2, r2, ip
+               b       .Lcfu_dest_aligned
+
+ENTRY(__copy_from_user)
+               stmfd   sp!, {r0, r2, r4 - r7, lr}
+               cmp     r2, #4
+               blt     .Lcfu_not_enough
+               ands    ip, r0, #3
+               bne     .Lcfu_dest_not_aligned
+.Lcfu_dest_aligned:
+               ands    ip, r1, #3
+               bne     .Lcfu_src_not_aligned
+
+/*
+ * Seeing as there has to be at least 8 bytes to copy, we can
+ * copy one word, and force a user-mode page fault...
+ */
+
+.Lcfu_0fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_0nowords
+USER(  TUSER(  ldr)    r3, [r1], #4)
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT    @ On each page, use a ld/st??t instruction
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_0fupi
+/*
+ * ip = max no. of bytes to copy before needing another "strt" insn
+ */
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #32
+               blt     .Lcfu_0rem8lp
+
+.Lcfu_0cpy8lp: ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
+               stmia   r0!, {r3 - r6}
+               ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
+               subs    ip, ip, #32
+               stmia   r0!, {r3 - r6}
+               bpl     .Lcfu_0cpy8lp
+
+.Lcfu_0rem8lp: cmn     ip, #16
+               ldmgeia r1!, {r3 - r6}                  @ Shouldnt fault
+               stmgeia r0!, {r3 - r6}
+               tst     ip, #8
+               ldmneia r1!, {r3 - r4}                  @ Shouldnt fault
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+       TUSER(  ldrne) r3, [r1], #4                     @ Shouldnt fault
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_0fupi
+.Lcfu_0nowords:        teq     ip, #0
+               beq     .Lcfu_finished
+.Lcfu_nowords: cmp     ip, #2
+USER(  TUSER(  ldrb)   r3, [r1], #1)                   @ May fault
+               strb    r3, [r0], #1
+USER(  TUSER(  ldrgeb) r3, [r1], #1)                   @ May fault
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #1)                   @ May fault
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+
+.Lcfu_not_enough:
+               movs    ip, r2
+               bne     .Lcfu_nowords
+.Lcfu_finished:        mov     r0, #0
+               add     sp, sp, #8
+               ldmfd   sp!, {r4 - r7, pc}
+
+.Lcfu_src_not_aligned:
+               bic     r1, r1, #3
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               cmp     ip, #2
+               bgt     .Lcfu_3fupi
+               beq     .Lcfu_2fupi
+.Lcfu_1fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_1nowords
+               mov     r3, r7, pull #8
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               orr     r3, r3, r7, push #24
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_1fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lcfu_1rem8lp
+
+.Lcfu_1cpy8lp: mov     r3, r7, pull #8
+               ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #24
+               mov     r4, r4, pull #8
+               orr     r4, r4, r5, push #24
+               mov     r5, r5, pull #8
+               orr     r5, r5, r6, push #24
+               mov     r6, r6, pull #8
+               orr     r6, r6, r7, push #24
+               stmia   r0!, {r3 - r6}
+               bpl     .Lcfu_1cpy8lp
+
+.Lcfu_1rem8lp: tst     ip, #8
+               movne   r3, r7, pull #8
+               ldmneia r1!, {r4, r7}                   @ Shouldnt fault
+               orrne   r3, r3, r4, push #24
+               movne   r4, r4, pull #8
+               orrne   r4, r4, r7, push #24
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+               movne   r3, r7, pull #8
+USER(  TUSER(  ldrne) r7, [r1], #4)                    @ May fault
+               orrne   r3, r3, r7, push #24
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_1fupi
+.Lcfu_1nowords:        mov     r3, r7, get_byte_1
+               teq     ip, #0
+               beq     .Lcfu_finished
+               cmp     ip, #2
+               strb    r3, [r0], #1
+               movge   r3, r7, get_byte_2
+               strgeb  r3, [r0], #1
+               movgt   r3, r7, get_byte_3
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+
+.Lcfu_2fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_2nowords
+               mov     r3, r7, pull #16
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               orr     r3, r3, r7, push #16
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_2fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lcfu_2rem8lp
+
+
+.Lcfu_2cpy8lp: mov     r3, r7, pull #16
+               ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #16
+               mov     r4, r4, pull #16
+               orr     r4, r4, r5, push #16
+               mov     r5, r5, pull #16
+               orr     r5, r5, r6, push #16
+               mov     r6, r6, pull #16
+               orr     r6, r6, r7, push #16
+               stmia   r0!, {r3 - r6}
+               bpl     .Lcfu_2cpy8lp
+
+.Lcfu_2rem8lp: tst     ip, #8
+               movne   r3, r7, pull #16
+               ldmneia r1!, {r4, r7}                   @ Shouldnt fault
+               orrne   r3, r3, r4, push #16
+               movne   r4, r4, pull #16
+               orrne   r4, r4, r7, push #16
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+               movne   r3, r7, pull #16
+USER(  TUSER(  ldrne) r7, [r1], #4)                    @ May fault
+               orrne   r3, r3, r7, push #16
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_2fupi
+.Lcfu_2nowords:        mov     r3, r7, get_byte_2
+               teq     ip, #0
+               beq     .Lcfu_finished
+               cmp     ip, #2
+               strb    r3, [r0], #1
+               movge   r3, r7, get_byte_3
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #0)                   @ May fault
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+
+.Lcfu_3fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_3nowords
+               mov     r3, r7, pull #24
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               orr     r3, r3, r7, push #8
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_3fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lcfu_3rem8lp
+
+.Lcfu_3cpy8lp: mov     r3, r7, pull #24
+               ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
+               orr     r3, r3, r4, push #8
+               mov     r4, r4, pull #24
+               orr     r4, r4, r5, push #8
+               mov     r5, r5, pull #24
+               orr     r5, r5, r6, push #8
+               mov     r6, r6, pull #24
+               orr     r6, r6, r7, push #8
+               stmia   r0!, {r3 - r6}
+               subs    ip, ip, #16
+               bpl     .Lcfu_3cpy8lp
+
+.Lcfu_3rem8lp: tst     ip, #8
+               movne   r3, r7, pull #24
+               ldmneia r1!, {r4, r7}                   @ Shouldnt fault
+               orrne   r3, r3, r4, push #8
+               movne   r4, r4, pull #24
+               orrne   r4, r4, r7, push #8
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+               movne   r3, r7, pull #24
+USER(  TUSER(  ldrne) r7, [r1], #4)                    @ May fault
+               orrne   r3, r3, r7, push #8
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_3fupi
+.Lcfu_3nowords:        mov     r3, r7, get_byte_3
+               teq     ip, #0
+               beq     .Lcfu_finished
+               cmp     ip, #2
+               strb    r3, [r0], #1
+USER(  TUSER(  ldrgeb) r3, [r1], #1)                   @ May fault
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #1)                   @ May fault
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+ENDPROC(__copy_from_user)
+
+               .pushsection .fixup,"ax"
+               .align  0
+               /*
+                * We took an exception.  r0 contains a pointer to
+                * the byte not copied.
+                */
+9001:          ldr     r2, [sp], #4                    @ void *to
+               sub     r2, r0, r2                      @ bytes copied
+               ldr     r1, [sp], #4                    @ unsigned long count
+               subs    r4, r1, r2                      @ bytes left to copy
+               movne   r1, r4
+               blne    __memzero
+               mov     r0, r4
+               ldmfd   sp!, {r4 - r7, pc}
+               .popsection
+
index 5de69f2fcca9fec965fc300b506056c4a1f29e01..f6b9fc70161b43338772a9f092b589aecfb021df 100644 (file)
@@ -162,38 +162,6 @@ static void __init davinci_ntosd2_map_io(void)
        dm644x_init();
 }
 
-/*
- I2C initialization
-*/
-static struct davinci_i2c_platform_data ntosd2_i2c_pdata = {
-       .bus_freq       = 20 /* kHz */,
-       .bus_delay      = 100 /* usec */,
-};
-
-static struct i2c_board_info __initdata ntosd2_i2c_info[] =  {
-};
-
-static int ntosd2_init_i2c(void)
-{
-       int     status;
-
-       davinci_init_i2c(&ntosd2_i2c_pdata);
-       status = gpio_request(NTOSD2_MSP430_IRQ, ntosd2_i2c_info[0].type);
-       if (status == 0) {
-               status = gpio_direction_input(NTOSD2_MSP430_IRQ);
-               if (status == 0) {
-                       status = gpio_to_irq(NTOSD2_MSP430_IRQ);
-                       if (status > 0) {
-                               ntosd2_i2c_info[0].irq = status;
-                               i2c_register_board_info(1,
-                                       ntosd2_i2c_info,
-                                       ARRAY_SIZE(ntosd2_i2c_info));
-                       }
-               }
-       }
-       return status;
-}
-
 static struct davinci_mmc_config davinci_ntosd2_mmc_config = {
        .wires          = 4,
        .version        = MMC_CTLR_VERSION_1
@@ -218,7 +186,6 @@ static __init void davinci_ntosd2_init(void)
 {
        struct clk *aemif_clk;
        struct davinci_soc_info *soc_info = &davinci_soc_info;
-       int     status;
 
        aemif_clk = clk_get(NULL, "aemif");
        clk_enable(aemif_clk);
@@ -242,12 +209,6 @@ static __init void davinci_ntosd2_init(void)
        platform_add_devices(davinci_ntosd2_devices,
                                ARRAY_SIZE(davinci_ntosd2_devices));
 
-       /* Initialize I2C interface specific for this board */
-       status = ntosd2_init_i2c();
-       if (status < 0)
-               pr_warning("davinci_ntosd2_init: msp430 irq setup failed:"
-                                               "        %d\n", status);
-
        davinci_serial_init(&uart_config);
        dm644x_init_asp(&dm644x_ntosd2_snd_data);
 
index 373c3c00d24cdbbe054a1aae60625d97188e6208..c0bc83a7663ee5877edfc0ff768b63a1ed1a2e30 100644 (file)
@@ -115,7 +115,7 @@ static __init int exynos_pm_dt_parse_domains(void)
 }
 #endif /* CONFIG_OF */
 
-static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
+static __init __maybe_unused void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
                                                struct exynos_pm_domain *pd)
 {
        if (pdev->dev.bus) {
index 7aa6313fb1671bbf975d6cf6407aad3ecee66498..f69ca4680049dd9f253e30eec5fc1690569f8d0d 100644 (file)
@@ -223,7 +223,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[per3_gate], "per", "imx-fb.0");
        clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0");
        clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx-fb.0");
-       clk_register_clkdev(clk[csi_ahb_gate], NULL, "mx2-camera.0");
+       clk_register_clkdev(clk[csi_ahb_gate], "ahb", "mx2-camera.0");
        clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc");
        clk_register_clkdev(clk[usb_ipg_gate], "ipg", "fsl-usb2-udc");
        clk_register_clkdev(clk[usb_ahb_gate], "ahb", "fsl-usb2-udc");
@@ -250,8 +250,10 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx-i2c.1");
        clk_register_clkdev(clk[owire_ipg_gate], NULL, "mxc_w1.0");
        clk_register_clkdev(clk[kpp_ipg_gate], NULL, "imx-keypad");
-       clk_register_clkdev(clk[emma_ahb_gate], "ahb", "imx-emma");
-       clk_register_clkdev(clk[emma_ipg_gate], "ipg", "imx-emma");
+       clk_register_clkdev(clk[emma_ahb_gate], "emma-ahb", "mx2-camera.0");
+       clk_register_clkdev(clk[emma_ipg_gate], "emma-ipg", "mx2-camera.0");
+       clk_register_clkdev(clk[emma_ahb_gate], "ahb", "m2m-emmaprp.0");
+       clk_register_clkdev(clk[emma_ipg_gate], "ipg", "m2m-emmaprp.0");
        clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL);
        clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL);
        clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL);
index 8e19e70f90f97f121b6379945ebeadc2ae2284ab..1253af2d99715a63f157a9f838230895006d9323 100644 (file)
@@ -130,7 +130,7 @@ int __init mx31_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[nfc], NULL, "mxc_nand.0");
        clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
        clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
-       clk_register_clkdev(clk[kpp_gate], "kpp", NULL);
+       clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
        clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0");
        clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0");
        clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
index f6086693ebd2aa665e29fc7a5d5623caeb0d3d53..4bdcaa97bd9803be209f5deed8b771a4b21094d6 100644 (file)
@@ -303,6 +303,7 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,
        clk_prepare_enable(clk[aips_tz2]); /* fec */
        clk_prepare_enable(clk[spba]);
        clk_prepare_enable(clk[emi_fast_gate]); /* fec */
+       clk_prepare_enable(clk[emi_slow_gate]); /* eim */
        clk_prepare_enable(clk[tmax1]);
        clk_prepare_enable(clk[tmax2]); /* esdhc2, fec */
        clk_prepare_enable(clk[tmax3]); /* esdhc1, esdhc4 */
index ebf680bebdf2ad95a1928f6895f2a77fa60e9236..3fa6c51390da0723ab904e17aed5a2dc7b869afe 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index 7b1055c8e0b98c6619473ca4bca9cd711ccc316c..3b2267529f5e308cc1c47c048375ffedd5a60f9a 100644 (file)
@@ -456,7 +456,7 @@ static void __init ap_init_timer(void)
 
        clk = clk_get_sys("ap_timer", NULL);
        BUG_ON(IS_ERR(clk));
-       clk_enable(clk);
+       clk_prepare_enable(clk);
        rate = clk_get_rate(clk);
 
        writel(0, TIMER0_VA_BASE + TIMER_CTRL);
index 2a576abf409bd0323c64e0cac807d0f609e2135a..a5717558ee892fd61aac83997bb3ccff5411a0df 100644 (file)
@@ -9,5 +9,5 @@ dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb
 dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb
 dtb-$(CONFIG_MACH_TS219_DT)    += kirkwood-qnap-ts219.dtb
 dtb-$(CONFIG_MACH_GOFLEXNET_DT) += kirkwood-goflexnet.dtb
-dbt-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb
-dbt-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb
+dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb
+dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb
index ccdf83b17cf16030612bdf62c43711f7f926baa6..9a8bbda195b28a2b64e19a01d052990a2d6f1156 100644 (file)
@@ -2,9 +2,6 @@ if ARCH_MXS
 
 source "arch/arm/mach-mxs/devices/Kconfig"
 
-config MXS_OCOTP
-       bool
-
 config SOC_IMX23
        bool
        select ARM_AMBA
@@ -66,7 +63,6 @@ config MACH_MX28EVK
        select MXS_HAVE_PLATFORM_MXS_SAIF
        select MXS_HAVE_PLATFORM_MXS_I2C
        select MXS_HAVE_PLATFORM_RTC_STMP3XXX
-       select MXS_OCOTP
        help
          Include support for MX28EVK platform. This includes specific
          configurations for the board and its peripherals.
@@ -94,7 +90,6 @@ config MODULE_M28
        select MXS_HAVE_PLATFORM_MXS_I2C
        select MXS_HAVE_PLATFORM_MXS_MMC
        select MXS_HAVE_PLATFORM_MXSFB
-       select MXS_OCOTP
 
 config MODULE_APX4
        bool
@@ -106,7 +101,6 @@ config MODULE_APX4
        select MXS_HAVE_PLATFORM_MXS_I2C
        select MXS_HAVE_PLATFORM_MXS_MMC
        select MXS_HAVE_PLATFORM_MXS_SAIF
-       select MXS_OCOTP
 
 config MACH_TX28
        bool "Ka-Ro TX28 module"
index e41590ccb437feb62a0a9154778d91a700185521..fed3695a1339d89c754edb10ae382730429625b8 100644 (file)
@@ -1,7 +1,6 @@
 # Common support
-obj-y := devices.o icoll.o iomux.o system.o timer.o mm.o
+obj-y := devices.o icoll.o iomux.o ocotp.o system.o timer.o mm.o
 
-obj-$(CONFIG_MXS_OCOTP) += ocotp.o
 obj-$(CONFIG_PM) += pm.o
 
 obj-$(CONFIG_MACH_MXS_DT) += mach-mxs.o
index ef230a0eb5eb13e5cedde6f0a6c540f6a348eae6..9894e3df49c20aa9091b582d9ca93b153b1e40fd 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/spi/ads7846.h>
 #include <linux/i2c/twl.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
 #include <linux/smsc911x.h>
 
 #include <linux/wl12xx.h>
index d52651a05daa6ce0686ec32a4915e17c8fdc9919..874aecc0facab5fe4e6384eeee30801e3a699967 100644 (file)
 #include <plat/usb.h>
 #include "control.h"
 
-/* OMAP control module register for UTMI PHY */
-#define CONTROL_DEV_CONF               0x300
-#define PHY_PD                         0x1
-
-#define USBOTGHS_CONTROL               0x33c
-#define        AVALID                          BIT(0)
-#define        BVALID                          BIT(1)
-#define        VBUSVALID                       BIT(2)
-#define        SESSEND                         BIT(3)
-#define        IDDIG                           BIT(4)
-
-static struct clk *phyclk, *clk48m, *clk32k;
-static void __iomem *ctrl_base;
-static int usbotghs_control;
-
-int omap4430_phy_init(struct device *dev)
-{
-       ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
-       if (!ctrl_base) {
-               pr_err("control module ioremap failed\n");
-               return -ENOMEM;
-       }
-       /* Power down the phy */
-       __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-
-       if (!dev) {
-               iounmap(ctrl_base);
-               return 0;
-       }
-
-       phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
-       if (IS_ERR(phyclk)) {
-               dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
-               iounmap(ctrl_base);
-               return PTR_ERR(phyclk);
-       }
-
-       clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m");
-       if (IS_ERR(clk48m)) {
-               dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n");
-               clk_put(phyclk);
-               iounmap(ctrl_base);
-               return PTR_ERR(clk48m);
-       }
-
-       clk32k = clk_get(dev, "usb_phy_cm_clk32k");
-       if (IS_ERR(clk32k)) {
-               dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n");
-               clk_put(phyclk);
-               clk_put(clk48m);
-               iounmap(ctrl_base);
-               return PTR_ERR(clk32k);
-       }
-       return 0;
-}
-
-int omap4430_phy_set_clk(struct device *dev, int on)
-{
-       static int state;
-
-       if (on && !state) {
-               /* Enable the phy clocks */
-               clk_enable(phyclk);
-               clk_enable(clk48m);
-               clk_enable(clk32k);
-               state = 1;
-       } else if (state) {
-               /* Disable the phy clocks */
-               clk_disable(phyclk);
-               clk_disable(clk48m);
-               clk_disable(clk32k);
-               state = 0;
-       }
-       return 0;
-}
-
-int omap4430_phy_power(struct device *dev, int ID, int on)
-{
-       if (on) {
-               if (ID)
-                       /* enable VBUS valid, IDDIG groung */
-                       __raw_writel(AVALID | VBUSVALID, ctrl_base +
-                                                       USBOTGHS_CONTROL);
-               else
-                       /*
-                        * Enable VBUS Valid, AValid and IDDIG
-                        * high impedance
-                        */
-                       __raw_writel(IDDIG | AVALID | VBUSVALID,
-                                               ctrl_base + USBOTGHS_CONTROL);
-       } else {
-               /* Enable session END and IDIG to high impedance. */
-               __raw_writel(SESSEND | IDDIG, ctrl_base +
-                                       USBOTGHS_CONTROL);
-       }
-       return 0;
-}
-
-int omap4430_phy_suspend(struct device *dev, int suspend)
-{
-       if (suspend) {
-               /* Disable the clocks */
-               omap4430_phy_set_clk(dev, 0);
-               /* Power down the phy */
-               __raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-
-               /* save the context */
-               usbotghs_control = __raw_readl(ctrl_base + USBOTGHS_CONTROL);
-       } else {
-               /* Enable the internel phy clcoks */
-               omap4430_phy_set_clk(dev, 1);
-               /* power on the phy */
-               if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) {
-                       __raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF);
-                       mdelay(200);
-               }
-
-               /* restore the context */
-               __raw_writel(usbotghs_control, ctrl_base + USBOTGHS_CONTROL);
-       }
-
-       return 0;
-}
-
-int omap4430_phy_exit(struct device *dev)
-{
-       if (ctrl_base)
-               iounmap(ctrl_base);
-       if (phyclk)
-               clk_put(phyclk);
-       if (clk48m)
-               clk_put(clk48m);
-       if (clk32k)
-               clk_put(clk32k);
-
-       return 0;
-}
-
 void am35x_musb_reset(void)
 {
        u32     regval;
index de47f170ba50abf2506c363838d7cd82c70109ee..e2cdf67f4b8fff761c8f6fe02e92732bb6e8b0ef 100644 (file)
@@ -250,11 +250,6 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
 
 #if defined(CONFIG_ARCH_OMAP4)
 static struct twl4030_usb_data omap4_usb_pdata = {
-       .phy_init       = omap4430_phy_init,
-       .phy_exit       = omap4430_phy_exit,
-       .phy_power      = omap4430_phy_power,
-       .phy_set_clock  = omap4430_phy_set_clk,
-       .phy_suspend    = omap4430_phy_suspend,
 };
 
 static struct regulator_init_data omap4_vdac_idata = {
index c4a576856661014ea3bec9acc70f80e32d62c33b..e9b4b234dc5ff483f434850013b690241f1681e9 100644 (file)
@@ -117,7 +117,4 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
        dev->dma_mask = &musb_dmamask;
        dev->coherent_dma_mask = musb_dmamask;
        put_device(dev);
-
-       if (cpu_is_omap44xx())
-               omap4430_phy_init(dev);
 }
index 5905ed130e94200abe59867d0b916e718cedae98..d89d87ae144cc77d2e71e1efe470761544573e3d 100644 (file)
@@ -953,12 +953,12 @@ static struct i2c_board_info raumfeld_connector_i2c_board_info __initdata = {
 
 static struct eeti_ts_platform_data eeti_ts_pdata = {
        .irq_active_high = 1,
+       .irq_gpio = GPIO_TOUCH_IRQ,
 };
 
 static struct i2c_board_info raumfeld_controller_i2c_board_info __initdata = {
        .type   = "eeti_ts",
        .addr   = 0x0a,
-       .irq    = PXA_GPIO_TO_IRQ(GPIO_TOUCH_IRQ),
        .platform_data = &eeti_ts_pdata,
 };
 
index e24961109b70286655c36c46a3083809511870c5..d56b0f7f2b202a0aaea0b36435328ff15b8c783f 100644 (file)
@@ -483,7 +483,7 @@ config MACH_NEO1973_GTA02
        select I2C
        select POWER_SUPPLY
        select MACH_NEO1973
-       select S3C2410_PWM
+       select S3C24XX_PWM
        select S3C_DEV_USB_HOST
        help
           Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
@@ -493,7 +493,7 @@ config MACH_RX1950
        select S3C24XX_DCLK
        select PM_H1940 if PM
        select I2C
-       select S3C2410_PWM
+       select S3C24XX_PWM
        select S3C_DEV_NAND
        select S3C2410_IOTIMING if S3C2440_CPUFREQ
        select S3C2440_XTAL_16934400
index 6a2352436e6268989700ab9d9b84761add3b9bc1..f8e47235babeab49c179328d9013d62503286eee 100644 (file)
@@ -10,6 +10,7 @@
  * as cpu led, the green one is used as timer led.
  */
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/leds.h>
index c3d7303b9ac8f07a662e25739c6362a8e7ee4fd8..0e82b7f34fc1464ab3951e6f1f8f8bf018ba5d1f 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
-obj-$(CONFIG_USB_SUPPORT)              += usb_phy.o
 
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += board-dt-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += board-dt-tegra30.o
index 8fd387bf31f0c66a27b313d3b5edc8bd976e3d0a..b7344beec102b109d4d013b4db47a1ab56d90e42 100644 (file)
@@ -51,7 +51,7 @@ static struct regulator_init_data ldo0_data = {
        .consumer_supplies = tps658621_ldo0_supply,
 };
 
-#define HARMONY_REGULATOR_INIT(_id, _name, _supply, _minmv, _maxmv)    \
+#define HARMONY_REGULATOR_INIT(_id, _name, _supply, _minmv, _maxmv, _on)\
        static struct regulator_init_data _id##_data = {                \
                .supply_regulator = _supply,                            \
                .constraints = {                                        \
@@ -63,21 +63,22 @@ static struct regulator_init_data ldo0_data = {
                        .valid_ops_mask = (REGULATOR_CHANGE_MODE |      \
                                           REGULATOR_CHANGE_STATUS |    \
                                           REGULATOR_CHANGE_VOLTAGE),   \
+                       .always_on = _on,                               \
                },                                                      \
        }
 
-HARMONY_REGULATOR_INIT(sm0,  "vdd_sm0",  "vdd_sys", 725, 1500);
-HARMONY_REGULATOR_INIT(sm1,  "vdd_sm1",  "vdd_sys", 725, 1500);
-HARMONY_REGULATOR_INIT(sm2,  "vdd_sm2",  "vdd_sys", 3000, 4550);
-HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500);
-HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500);
-HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475);
-HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL,     1250, 3300);
-HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300);
+HARMONY_REGULATOR_INIT(sm0,  "vdd_sm0",  "vdd_sys", 725, 1500, 1);
+HARMONY_REGULATOR_INIT(sm1,  "vdd_sm1",  "vdd_sys", 725, 1500, 1);
+HARMONY_REGULATOR_INIT(sm2,  "vdd_sm2",  "vdd_sys", 3000, 4550, 1);
+HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500, 1);
+HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500, 0);
+HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300, 1);
+HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475, 1);
+HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL,     1250, 3300, 1);
+HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300, 0);
+HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300, 0);
+HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300, 0);
+HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300, 1);
 
 #define TPS_REG(_id, _data)                    \
        {                                       \
@@ -119,9 +120,10 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
 
 int __init harmony_regulator_init(void)
 {
+       regulator_register_always_on(0, "vdd_sys",
+               NULL, 0, 5000000);
+
        if (machine_is_harmony()) {
-               regulator_register_always_on(0, "vdd_sys",
-                       NULL, 0, 5000000);
                i2c_register_board_info(3, harmony_regulators, 1);
        } else { /* Harmony, booted using device tree */
                struct device_node *np;
index c70e65ffa36ba8a91e16b372c8c616abd4414c20..d8ab7627639758fd6b80792bc22691c0eadefeef 100644 (file)
@@ -27,7 +27,7 @@
 #include <mach/irqs.h>
 #include <mach/iomap.h>
 #include <mach/dma.h>
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
 
 #include "gpio-names.h"
 #include "devices.h"
index 4f50527264956b0f28413e462b9afef024b00322..906a61f340c87e701bb68ad49d10b6eaab020367 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_data/tegra_usb.h>
 
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
 
 extern struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config;
 
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
deleted file mode 100644 (file)
index 935ce9f..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/usb_phy.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __MACH_USB_PHY_H
-#define __MACH_USB_PHY_H
-
-#include <linux/clk.h>
-#include <linux/usb/otg.h>
-
-struct tegra_utmip_config {
-       u8 hssync_start_delay;
-       u8 elastic_limit;
-       u8 idle_wait_delay;
-       u8 term_range_adj;
-       u8 xcvr_setup;
-       u8 xcvr_lsfslew;
-       u8 xcvr_lsrslew;
-};
-
-struct tegra_ulpi_config {
-       int reset_gpio;
-       const char *clk;
-};
-
-enum tegra_usb_phy_port_speed {
-       TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
-       TEGRA_USB_PHY_PORT_SPEED_LOW,
-       TEGRA_USB_PHY_PORT_SPEED_HIGH,
-};
-
-enum tegra_usb_phy_mode {
-       TEGRA_USB_PHY_MODE_DEVICE,
-       TEGRA_USB_PHY_MODE_HOST,
-};
-
-struct tegra_xtal_freq;
-
-struct tegra_usb_phy {
-       int instance;
-       const struct tegra_xtal_freq *freq;
-       void __iomem *regs;
-       void __iomem *pad_regs;
-       struct clk *clk;
-       struct clk *pll_u;
-       struct clk *pad_clk;
-       enum tegra_usb_phy_mode mode;
-       void *config;
-       struct usb_phy *ulpi;
-};
-
-struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
-       void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
-
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
-
-void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
-                                enum tegra_usb_phy_port_speed port_speed);
-
-void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
-
-void tegra_usb_phy_close(struct tegra_usb_phy *phy);
-
-#endif /* __MACH_USB_PHY_H */
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
deleted file mode 100644 (file)
index 022b33a..0000000
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * arch/arm/mach-tegra/usb_phy.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *     Erik Gilling <konkers@google.com>
- *     Benoit Goby <benoit@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#include <linux/resource.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/ulpi.h>
-#include <asm/mach-types.h>
-#include <mach/gpio-tegra.h>
-#include <mach/usb_phy.h>
-#include <mach/iomap.h>
-
-#define ULPI_VIEWPORT          0x170
-
-#define USB_PORTSC1            0x184
-#define   USB_PORTSC1_PTS(x)   (((x) & 0x3) << 30)
-#define   USB_PORTSC1_PSPD(x)  (((x) & 0x3) << 26)
-#define   USB_PORTSC1_PHCD     (1 << 23)
-#define   USB_PORTSC1_WKOC     (1 << 22)
-#define   USB_PORTSC1_WKDS     (1 << 21)
-#define   USB_PORTSC1_WKCN     (1 << 20)
-#define   USB_PORTSC1_PTC(x)   (((x) & 0xf) << 16)
-#define   USB_PORTSC1_PP       (1 << 12)
-#define   USB_PORTSC1_SUSP     (1 << 7)
-#define   USB_PORTSC1_PE       (1 << 2)
-#define   USB_PORTSC1_CCS      (1 << 0)
-
-#define USB_SUSP_CTRL          0x400
-#define   USB_WAKE_ON_CNNT_EN_DEV      (1 << 3)
-#define   USB_WAKE_ON_DISCON_EN_DEV    (1 << 4)
-#define   USB_SUSP_CLR         (1 << 5)
-#define   USB_PHY_CLK_VALID    (1 << 7)
-#define   UTMIP_RESET                  (1 << 11)
-#define   UHSIC_RESET                  (1 << 11)
-#define   UTMIP_PHY_ENABLE             (1 << 12)
-#define   ULPI_PHY_ENABLE      (1 << 13)
-#define   USB_SUSP_SET         (1 << 14)
-#define   USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
-
-#define USB1_LEGACY_CTRL       0x410
-#define   USB1_NO_LEGACY_MODE                  (1 << 0)
-#define   USB1_VBUS_SENSE_CTL_MASK             (3 << 1)
-#define   USB1_VBUS_SENSE_CTL_VBUS_WAKEUP      (0 << 1)
-#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
-                                               (1 << 1)
-#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD      (2 << 1)
-#define   USB1_VBUS_SENSE_CTL_A_SESS_VLD       (3 << 1)
-
-#define ULPI_TIMING_CTRL_0     0x424
-#define   ULPI_OUTPUT_PINMUX_BYP       (1 << 10)
-#define   ULPI_CLKOUT_PINMUX_BYP       (1 << 11)
-
-#define ULPI_TIMING_CTRL_1     0x428
-#define   ULPI_DATA_TRIMMER_LOAD       (1 << 0)
-#define   ULPI_DATA_TRIMMER_SEL(x)     (((x) & 0x7) << 1)
-#define   ULPI_STPDIRNXT_TRIMMER_LOAD  (1 << 16)
-#define   ULPI_STPDIRNXT_TRIMMER_SEL(x)        (((x) & 0x7) << 17)
-#define   ULPI_DIR_TRIMMER_LOAD                (1 << 24)
-#define   ULPI_DIR_TRIMMER_SEL(x)      (((x) & 0x7) << 25)
-
-#define UTMIP_PLL_CFG1         0x804
-#define   UTMIP_XTAL_FREQ_COUNT(x)             (((x) & 0xfff) << 0)
-#define   UTMIP_PLLU_ENABLE_DLY_COUNT(x)       (((x) & 0x1f) << 27)
-
-#define UTMIP_XCVR_CFG0                0x808
-#define   UTMIP_XCVR_SETUP(x)                  (((x) & 0xf) << 0)
-#define   UTMIP_XCVR_LSRSLEW(x)                        (((x) & 0x3) << 8)
-#define   UTMIP_XCVR_LSFSLEW(x)                        (((x) & 0x3) << 10)
-#define   UTMIP_FORCE_PD_POWERDOWN             (1 << 14)
-#define   UTMIP_FORCE_PD2_POWERDOWN            (1 << 16)
-#define   UTMIP_FORCE_PDZI_POWERDOWN           (1 << 18)
-#define   UTMIP_XCVR_HSSLEW_MSB(x)             (((x) & 0x7f) << 25)
-
-#define UTMIP_BIAS_CFG0                0x80c
-#define   UTMIP_OTGPD                  (1 << 11)
-#define   UTMIP_BIASPD                 (1 << 10)
-
-#define UTMIP_HSRX_CFG0                0x810
-#define   UTMIP_ELASTIC_LIMIT(x)       (((x) & 0x1f) << 10)
-#define   UTMIP_IDLE_WAIT(x)           (((x) & 0x1f) << 15)
-
-#define UTMIP_HSRX_CFG1                0x814
-#define   UTMIP_HS_SYNC_START_DLY(x)   (((x) & 0x1f) << 1)
-
-#define UTMIP_TX_CFG0          0x820
-#define   UTMIP_FS_PREABMLE_J          (1 << 19)
-#define   UTMIP_HS_DISCON_DISABLE      (1 << 8)
-
-#define UTMIP_MISC_CFG0                0x824
-#define   UTMIP_DPDM_OBSERVE           (1 << 26)
-#define   UTMIP_DPDM_OBSERVE_SEL(x)    (((x) & 0xf) << 27)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_J  UTMIP_DPDM_OBSERVE_SEL(0xf)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_K  UTMIP_DPDM_OBSERVE_SEL(0xe)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
-#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
-#define   UTMIP_SUSPEND_EXIT_ON_EDGE   (1 << 22)
-
-#define UTMIP_MISC_CFG1                0x828
-#define   UTMIP_PLL_ACTIVE_DLY_COUNT(x)        (((x) & 0x1f) << 18)
-#define   UTMIP_PLLU_STABLE_COUNT(x)   (((x) & 0xfff) << 6)
-
-#define UTMIP_DEBOUNCE_CFG0    0x82c
-#define   UTMIP_BIAS_DEBOUNCE_A(x)     (((x) & 0xffff) << 0)
-
-#define UTMIP_BAT_CHRG_CFG0    0x830
-#define   UTMIP_PD_CHRG                        (1 << 0)
-
-#define UTMIP_SPARE_CFG0       0x834
-#define   FUSE_SETUP_SEL               (1 << 3)
-
-#define UTMIP_XCVR_CFG1                0x838
-#define   UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
-#define   UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
-#define   UTMIP_FORCE_PDDR_POWERDOWN   (1 << 4)
-#define   UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
-
-#define UTMIP_BIAS_CFG1                0x83c
-#define   UTMIP_BIAS_PDTRK_COUNT(x)    (((x) & 0x1f) << 3)
-
-static DEFINE_SPINLOCK(utmip_pad_lock);
-static int utmip_pad_count;
-
-struct tegra_xtal_freq {
-       int freq;
-       u8 enable_delay;
-       u8 stable_count;
-       u8 active_delay;
-       u8 xtal_freq_count;
-       u16 debounce;
-};
-
-static const struct tegra_xtal_freq tegra_freq_table[] = {
-       {
-               .freq = 12000000,
-               .enable_delay = 0x02,
-               .stable_count = 0x2F,
-               .active_delay = 0x04,
-               .xtal_freq_count = 0x76,
-               .debounce = 0x7530,
-       },
-       {
-               .freq = 13000000,
-               .enable_delay = 0x02,
-               .stable_count = 0x33,
-               .active_delay = 0x05,
-               .xtal_freq_count = 0x7F,
-               .debounce = 0x7EF4,
-       },
-       {
-               .freq = 19200000,
-               .enable_delay = 0x03,
-               .stable_count = 0x4B,
-               .active_delay = 0x06,
-               .xtal_freq_count = 0xBB,
-               .debounce = 0xBB80,
-       },
-       {
-               .freq = 26000000,
-               .enable_delay = 0x04,
-               .stable_count = 0x66,
-               .active_delay = 0x09,
-               .xtal_freq_count = 0xFE,
-               .debounce = 0xFDE8,
-       },
-};
-
-static struct tegra_utmip_config utmip_default[] = {
-       [0] = {
-               .hssync_start_delay = 9,
-               .idle_wait_delay = 17,
-               .elastic_limit = 16,
-               .term_range_adj = 6,
-               .xcvr_setup = 9,
-               .xcvr_lsfslew = 1,
-               .xcvr_lsrslew = 1,
-       },
-       [2] = {
-               .hssync_start_delay = 9,
-               .idle_wait_delay = 17,
-               .elastic_limit = 16,
-               .term_range_adj = 6,
-               .xcvr_setup = 9,
-               .xcvr_lsfslew = 2,
-               .xcvr_lsrslew = 2,
-       },
-};
-
-static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
-{
-       return (phy->instance == 1);
-}
-
-static int utmip_pad_open(struct tegra_usb_phy *phy)
-{
-       phy->pad_clk = clk_get_sys("utmip-pad", NULL);
-       if (IS_ERR(phy->pad_clk)) {
-               pr_err("%s: can't get utmip pad clock\n", __func__);
-               return PTR_ERR(phy->pad_clk);
-       }
-
-       if (phy->instance == 0) {
-               phy->pad_regs = phy->regs;
-       } else {
-               phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
-               if (!phy->pad_regs) {
-                       pr_err("%s: can't remap usb registers\n", __func__);
-                       clk_put(phy->pad_clk);
-                       return -ENOMEM;
-               }
-       }
-       return 0;
-}
-
-static void utmip_pad_close(struct tegra_usb_phy *phy)
-{
-       if (phy->instance != 0)
-               iounmap(phy->pad_regs);
-       clk_put(phy->pad_clk);
-}
-
-static void utmip_pad_power_on(struct tegra_usb_phy *phy)
-{
-       unsigned long val, flags;
-       void __iomem *base = phy->pad_regs;
-
-       clk_prepare_enable(phy->pad_clk);
-
-       spin_lock_irqsave(&utmip_pad_lock, flags);
-
-       if (utmip_pad_count++ == 0) {
-               val = readl(base + UTMIP_BIAS_CFG0);
-               val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
-               writel(val, base + UTMIP_BIAS_CFG0);
-       }
-
-       spin_unlock_irqrestore(&utmip_pad_lock, flags);
-
-       clk_disable_unprepare(phy->pad_clk);
-}
-
-static int utmip_pad_power_off(struct tegra_usb_phy *phy)
-{
-       unsigned long val, flags;
-       void __iomem *base = phy->pad_regs;
-
-       if (!utmip_pad_count) {
-               pr_err("%s: utmip pad already powered off\n", __func__);
-               return -EINVAL;
-       }
-
-       clk_prepare_enable(phy->pad_clk);
-
-       spin_lock_irqsave(&utmip_pad_lock, flags);
-
-       if (--utmip_pad_count == 0) {
-               val = readl(base + UTMIP_BIAS_CFG0);
-               val |= UTMIP_OTGPD | UTMIP_BIASPD;
-               writel(val, base + UTMIP_BIAS_CFG0);
-       }
-
-       spin_unlock_irqrestore(&utmip_pad_lock, flags);
-
-       clk_disable_unprepare(phy->pad_clk);
-
-       return 0;
-}
-
-static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
-{
-       unsigned long timeout = 2000;
-       do {
-               if ((readl(reg) & mask) == result)
-                       return 0;
-               udelay(1);
-               timeout--;
-       } while (timeout);
-       return -1;
-}
-
-static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       if (phy->instance == 0) {
-               val = readl(base + USB_SUSP_CTRL);
-               val |= USB_SUSP_SET;
-               writel(val, base + USB_SUSP_CTRL);
-
-               udelay(10);
-
-               val = readl(base + USB_SUSP_CTRL);
-               val &= ~USB_SUSP_SET;
-               writel(val, base + USB_SUSP_CTRL);
-       }
-
-       if (phy->instance == 2) {
-               val = readl(base + USB_PORTSC1);
-               val |= USB_PORTSC1_PHCD;
-               writel(val, base + USB_PORTSC1);
-       }
-
-       if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
-               pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-}
-
-static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       if (phy->instance == 0) {
-               val = readl(base + USB_SUSP_CTRL);
-               val |= USB_SUSP_CLR;
-               writel(val, base + USB_SUSP_CTRL);
-
-               udelay(10);
-
-               val = readl(base + USB_SUSP_CTRL);
-               val &= ~USB_SUSP_CLR;
-               writel(val, base + USB_SUSP_CTRL);
-       }
-
-       if (phy->instance == 2) {
-               val = readl(base + USB_PORTSC1);
-               val &= ~USB_PORTSC1_PHCD;
-               writel(val, base + USB_PORTSC1);
-       }
-
-       if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
-                                                    USB_PHY_CLK_VALID))
-               pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
-}
-
-static int utmi_phy_power_on(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-       struct tegra_utmip_config *config = phy->config;
-
-       val = readl(base + USB_SUSP_CTRL);
-       val |= UTMIP_RESET;
-       writel(val, base + USB_SUSP_CTRL);
-
-       if (phy->instance == 0) {
-               val = readl(base + USB1_LEGACY_CTRL);
-               val |= USB1_NO_LEGACY_MODE;
-               writel(val, base + USB1_LEGACY_CTRL);
-       }
-
-       val = readl(base + UTMIP_TX_CFG0);
-       val &= ~UTMIP_FS_PREABMLE_J;
-       writel(val, base + UTMIP_TX_CFG0);
-
-       val = readl(base + UTMIP_HSRX_CFG0);
-       val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
-       val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
-       val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
-       writel(val, base + UTMIP_HSRX_CFG0);
-
-       val = readl(base + UTMIP_HSRX_CFG1);
-       val &= ~UTMIP_HS_SYNC_START_DLY(~0);
-       val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
-       writel(val, base + UTMIP_HSRX_CFG1);
-
-       val = readl(base + UTMIP_DEBOUNCE_CFG0);
-       val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
-       val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
-       writel(val, base + UTMIP_DEBOUNCE_CFG0);
-
-       val = readl(base + UTMIP_MISC_CFG0);
-       val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
-       writel(val, base + UTMIP_MISC_CFG0);
-
-       val = readl(base + UTMIP_MISC_CFG1);
-       val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
-       val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
-               UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
-       writel(val, base + UTMIP_MISC_CFG1);
-
-       val = readl(base + UTMIP_PLL_CFG1);
-       val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
-       val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
-               UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
-       writel(val, base + UTMIP_PLL_CFG1);
-
-       if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
-               val = readl(base + USB_SUSP_CTRL);
-               val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
-               writel(val, base + USB_SUSP_CTRL);
-       }
-
-       utmip_pad_power_on(phy);
-
-       val = readl(base + UTMIP_XCVR_CFG0);
-       val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
-                UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
-                UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
-                UTMIP_XCVR_HSSLEW_MSB(~0));
-       val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
-       val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
-       val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
-       writel(val, base + UTMIP_XCVR_CFG0);
-
-       val = readl(base + UTMIP_XCVR_CFG1);
-       val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
-                UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
-       val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
-       writel(val, base + UTMIP_XCVR_CFG1);
-
-       val = readl(base + UTMIP_BAT_CHRG_CFG0);
-       val &= ~UTMIP_PD_CHRG;
-       writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
-       val = readl(base + UTMIP_BIAS_CFG1);
-       val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
-       val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
-       writel(val, base + UTMIP_BIAS_CFG1);
-
-       if (phy->instance == 0) {
-               val = readl(base + UTMIP_SPARE_CFG0);
-               if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
-                       val &= ~FUSE_SETUP_SEL;
-               else
-                       val |= FUSE_SETUP_SEL;
-               writel(val, base + UTMIP_SPARE_CFG0);
-       }
-
-       if (phy->instance == 2) {
-               val = readl(base + USB_SUSP_CTRL);
-               val |= UTMIP_PHY_ENABLE;
-               writel(val, base + USB_SUSP_CTRL);
-       }
-
-       val = readl(base + USB_SUSP_CTRL);
-       val &= ~UTMIP_RESET;
-       writel(val, base + USB_SUSP_CTRL);
-
-       if (phy->instance == 0) {
-               val = readl(base + USB1_LEGACY_CTRL);
-               val &= ~USB1_VBUS_SENSE_CTL_MASK;
-               val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
-               writel(val, base + USB1_LEGACY_CTRL);
-
-               val = readl(base + USB_SUSP_CTRL);
-               val &= ~USB_SUSP_SET;
-               writel(val, base + USB_SUSP_CTRL);
-       }
-
-       utmi_phy_clk_enable(phy);
-
-       if (phy->instance == 2) {
-               val = readl(base + USB_PORTSC1);
-               val &= ~USB_PORTSC1_PTS(~0);
-               writel(val, base + USB_PORTSC1);
-       }
-
-       return 0;
-}
-
-static void utmi_phy_power_off(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       utmi_phy_clk_disable(phy);
-
-       if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
-               val = readl(base + USB_SUSP_CTRL);
-               val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
-               val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
-               writel(val, base + USB_SUSP_CTRL);
-       }
-
-       val = readl(base + USB_SUSP_CTRL);
-       val |= UTMIP_RESET;
-       writel(val, base + USB_SUSP_CTRL);
-
-       val = readl(base + UTMIP_BAT_CHRG_CFG0);
-       val |= UTMIP_PD_CHRG;
-       writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
-       val = readl(base + UTMIP_XCVR_CFG0);
-       val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
-              UTMIP_FORCE_PDZI_POWERDOWN;
-       writel(val, base + UTMIP_XCVR_CFG0);
-
-       val = readl(base + UTMIP_XCVR_CFG1);
-       val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
-              UTMIP_FORCE_PDDR_POWERDOWN;
-       writel(val, base + UTMIP_XCVR_CFG1);
-
-       utmip_pad_power_off(phy);
-}
-
-static void utmi_phy_preresume(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       val = readl(base + UTMIP_TX_CFG0);
-       val |= UTMIP_HS_DISCON_DISABLE;
-       writel(val, base + UTMIP_TX_CFG0);
-}
-
-static void utmi_phy_postresume(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       val = readl(base + UTMIP_TX_CFG0);
-       val &= ~UTMIP_HS_DISCON_DISABLE;
-       writel(val, base + UTMIP_TX_CFG0);
-}
-
-static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
-                                  enum tegra_usb_phy_port_speed port_speed)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       val = readl(base + UTMIP_MISC_CFG0);
-       val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
-       if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
-               val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
-       else
-               val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
-       writel(val, base + UTMIP_MISC_CFG0);
-       udelay(1);
-
-       val = readl(base + UTMIP_MISC_CFG0);
-       val |= UTMIP_DPDM_OBSERVE;
-       writel(val, base + UTMIP_MISC_CFG0);
-       udelay(10);
-}
-
-static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       val = readl(base + UTMIP_MISC_CFG0);
-       val &= ~UTMIP_DPDM_OBSERVE;
-       writel(val, base + UTMIP_MISC_CFG0);
-       udelay(10);
-}
-
-static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
-{
-       int ret;
-       unsigned long val;
-       void __iomem *base = phy->regs;
-       struct tegra_ulpi_config *config = phy->config;
-
-       gpio_direction_output(config->reset_gpio, 0);
-       msleep(5);
-       gpio_direction_output(config->reset_gpio, 1);
-
-       clk_prepare_enable(phy->clk);
-       msleep(1);
-
-       val = readl(base + USB_SUSP_CTRL);
-       val |= UHSIC_RESET;
-       writel(val, base + USB_SUSP_CTRL);
-
-       val = readl(base + ULPI_TIMING_CTRL_0);
-       val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
-       writel(val, base + ULPI_TIMING_CTRL_0);
-
-       val = readl(base + USB_SUSP_CTRL);
-       val |= ULPI_PHY_ENABLE;
-       writel(val, base + USB_SUSP_CTRL);
-
-       val = 0;
-       writel(val, base + ULPI_TIMING_CTRL_1);
-
-       val |= ULPI_DATA_TRIMMER_SEL(4);
-       val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
-       val |= ULPI_DIR_TRIMMER_SEL(4);
-       writel(val, base + ULPI_TIMING_CTRL_1);
-       udelay(10);
-
-       val |= ULPI_DATA_TRIMMER_LOAD;
-       val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
-       val |= ULPI_DIR_TRIMMER_LOAD;
-       writel(val, base + ULPI_TIMING_CTRL_1);
-
-       /* Fix VbusInvalid due to floating VBUS */
-       ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
-       if (ret) {
-               pr_err("%s: ulpi write failed\n", __func__);
-               return ret;
-       }
-
-       ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
-       if (ret) {
-               pr_err("%s: ulpi write failed\n", __func__);
-               return ret;
-       }
-
-       val = readl(base + USB_PORTSC1);
-       val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
-       writel(val, base + USB_PORTSC1);
-
-       val = readl(base + USB_SUSP_CTRL);
-       val |= USB_SUSP_CLR;
-       writel(val, base + USB_SUSP_CTRL);
-       udelay(100);
-
-       val = readl(base + USB_SUSP_CTRL);
-       val &= ~USB_SUSP_CLR;
-       writel(val, base + USB_SUSP_CTRL);
-
-       return 0;
-}
-
-static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-       struct tegra_ulpi_config *config = phy->config;
-
-       /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
-        * Controller to immediately bring the ULPI PHY out of low power
-        */
-       val = readl(base + USB_PORTSC1);
-       val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
-       writel(val, base + USB_PORTSC1);
-
-       gpio_direction_output(config->reset_gpio, 0);
-       clk_disable(phy->clk);
-}
-
-struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
-       void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode)
-{
-       struct tegra_usb_phy *phy;
-       struct tegra_ulpi_config *ulpi_config;
-       unsigned long parent_rate;
-       int i;
-       int err;
-
-       phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
-       if (!phy)
-               return ERR_PTR(-ENOMEM);
-
-       phy->instance = instance;
-       phy->regs = regs;
-       phy->config = config;
-       phy->mode = phy_mode;
-
-       if (!phy->config) {
-               if (phy_is_ulpi(phy)) {
-                       pr_err("%s: ulpi phy configuration missing", __func__);
-                       err = -EINVAL;
-                       goto err0;
-               } else {
-                       phy->config = &utmip_default[instance];
-               }
-       }
-
-       phy->pll_u = clk_get_sys(NULL, "pll_u");
-       if (IS_ERR(phy->pll_u)) {
-               pr_err("Can't get pll_u clock\n");
-               err = PTR_ERR(phy->pll_u);
-               goto err0;
-       }
-       clk_prepare_enable(phy->pll_u);
-
-       parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
-       for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
-               if (tegra_freq_table[i].freq == parent_rate) {
-                       phy->freq = &tegra_freq_table[i];
-                       break;
-               }
-       }
-       if (!phy->freq) {
-               pr_err("invalid pll_u parent rate %ld\n", parent_rate);
-               err = -EINVAL;
-               goto err1;
-       }
-
-       if (phy_is_ulpi(phy)) {
-               ulpi_config = config;
-               phy->clk = clk_get_sys(NULL, ulpi_config->clk);
-               if (IS_ERR(phy->clk)) {
-                       pr_err("%s: can't get ulpi clock\n", __func__);
-                       err = -ENXIO;
-                       goto err1;
-               }
-               if (!gpio_is_valid(ulpi_config->reset_gpio))
-                       ulpi_config->reset_gpio =
-                               of_get_named_gpio(dev->of_node,
-                                                 "nvidia,phy-reset-gpio", 0);
-               if (!gpio_is_valid(ulpi_config->reset_gpio)) {
-                       pr_err("%s: invalid reset gpio: %d\n", __func__,
-                              ulpi_config->reset_gpio);
-                       err = -EINVAL;
-                       goto err1;
-               }
-               gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
-               gpio_direction_output(ulpi_config->reset_gpio, 0);
-               phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
-               phy->ulpi->io_priv = regs + ULPI_VIEWPORT;
-       } else {
-               err = utmip_pad_open(phy);
-               if (err < 0)
-                       goto err1;
-       }
-
-       return phy;
-
-err1:
-       clk_disable_unprepare(phy->pll_u);
-       clk_put(phy->pll_u);
-err0:
-       kfree(phy);
-       return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
-
-int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
-{
-       if (phy_is_ulpi(phy))
-               return ulpi_phy_power_on(phy);
-       else
-               return utmi_phy_power_on(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
-
-void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
-{
-       if (phy_is_ulpi(phy))
-               ulpi_phy_power_off(phy);
-       else
-               utmi_phy_power_off(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
-
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
-{
-       if (!phy_is_ulpi(phy))
-               utmi_phy_preresume(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
-
-void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
-{
-       if (!phy_is_ulpi(phy))
-               utmi_phy_postresume(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
-
-void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
-                                enum tegra_usb_phy_port_speed port_speed)
-{
-       if (!phy_is_ulpi(phy))
-               utmi_phy_restore_start(phy, port_speed);
-}
-EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
-
-void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
-{
-       if (!phy_is_ulpi(phy))
-               utmi_phy_restore_end(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
-
-void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
-{
-       if (!phy_is_ulpi(phy))
-               utmi_phy_clk_disable(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
-
-void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
-{
-       if (!phy_is_ulpi(phy))
-               utmi_phy_clk_enable(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
-
-void tegra_usb_phy_close(struct tegra_usb_phy *phy)
-{
-       if (phy_is_ulpi(phy))
-               clk_put(phy->clk);
-       else
-               utmip_pad_close(phy);
-       clk_disable_unprepare(phy->pll_u);
-       clk_put(phy->pll_u);
-       kfree(phy);
-}
-EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
index f9fbeb2d10e988525c7c775d960f619ec643d6c4..6fd9d609ebaa59172c8683c8b4b9995862154eda 100644 (file)
@@ -33,6 +33,7 @@ static struct platform_device *devices[] __initdata = {
        &vt8500_device_uart0,
        &vt8500_device_lcdc,
        &vt8500_device_ehci,
+       &vt8500_device_uhci,
        &vt8500_device_ge_rops,
        &vt8500_device_pwm,
        &vt8500_device_pwmbl,
index 19519aeecf37abba6fe80c626f83383bd52f4492..def7fe393a2c9d2c7967ccae12ec31fc53af3ae4 100644 (file)
@@ -48,6 +48,11 @@ void __init vt8500_set_resources(void)
        tmp[1] = wmt_irq_res(IRQ_EHCI);
        wmt_res_add(&vt8500_device_ehci, tmp, 2);
 
+       /* vt8500 uses a single IRQ for both EHCI and UHCI controllers */
+       tmp[0] = wmt_mmio_res(VT8500_UHCI_BASE, SZ_512);
+       tmp[1] = wmt_irq_res(IRQ_EHCI);
+       wmt_res_add(&vt8500_device_uhci, tmp, 2);
+
        tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256);
        wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
 
index db4594e029f4785eaf0b0ba3abb8316edfc04b7c..c810454178dcf091b7091f547cccfb5e530c3444 100644 (file)
@@ -55,6 +55,10 @@ void __init wm8505_set_resources(void)
        tmp[1] = wmt_irq_res(IRQ_EHCI);
        wmt_res_add(&vt8500_device_ehci, tmp, 2);
 
+       tmp[0] = wmt_mmio_res(WM8505_UHCI_BASE, SZ_512);
+       tmp[1] = wmt_irq_res(IRQ_UHCI);
+       wmt_res_add(&vt8500_device_uhci, tmp, 2);
+
        tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256);
        wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
 
index 1fcdc36b358df112a536bdf835a542d8392d50f1..46ff82dad54409bd8f897feabbe4fab04d472612 100644 (file)
@@ -204,6 +204,17 @@ struct platform_device vt8500_device_ehci = {
        },
 };
 
+static u64 uhci_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device vt8500_device_uhci = {
+       .name           = "platform-uhci",
+       .id             = 0,
+       .dev            = {
+               .dma_mask       = &uhci_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
 struct platform_device vt8500_device_ge_rops = {
        .name           = "wmt_ge_rops",
        .id             = -1,
index 188d4e17f35c3d2dc8c7ffc63fcad750774a517a..0e6d9f904c773aa87d5d4963bce82700d027a9c0 100644 (file)
@@ -81,6 +81,7 @@ extern struct platform_device vt8500_device_uart5;
 extern struct platform_device vt8500_device_lcdc;
 extern struct platform_device vt8500_device_wm8505_fb;
 extern struct platform_device vt8500_device_ehci;
+extern struct platform_device vt8500_device_uhci;
 extern struct platform_device vt8500_device_ge_rops;
 extern struct platform_device vt8500_device_pwm;
 extern struct platform_device vt8500_device_pwmbl;
index db19886caf7ce679ff6ac2f98f0d5d70568e2eac..4804e2a4557463d422bfdaae9a47223fafc9bdc4 100644 (file)
@@ -32,6 +32,7 @@ static void __iomem *pmc_hiber;
 static struct platform_device *devices[] __initdata = {
        &vt8500_device_uart0,
        &vt8500_device_ehci,
+       &vt8500_device_uhci,
        &vt8500_device_wm8505_fb,
        &vt8500_device_ge_rops,
        &vt8500_device_pwm,
index c2cdf6500f75dc5a1ab5a688ea305099e8d30057..4e7d1182e8a3a59270073b5cb3b348e0bd690ef8 100644 (file)
@@ -358,7 +358,7 @@ void __init dma_contiguous_remap(void)
                if (end > arm_lowmem_limit)
                        end = arm_lowmem_limit;
                if (start >= end)
-                       return;
+                       continue;
 
                map.pfn = __phys_to_pfn(start);
                map.virtual = __phys_to_virt(start);
@@ -423,7 +423,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
        unsigned int pageno;
        unsigned long flags;
        void *ptr = NULL;
-       size_t align;
+       unsigned long align_mask;
 
        if (!pool->vaddr) {
                WARN(1, "coherent pool not initialised!\n");
@@ -435,11 +435,11 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
         * small, so align them to their order in pages, minimum is a page
         * size. This helps reduce fragmentation of the DMA space.
         */
-       align = PAGE_SIZE << get_order(size);
+       align_mask = (1 << get_order(size)) - 1;
 
        spin_lock_irqsave(&pool->lock, flags);
        pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages,
-                                           0, count, (1 << align) - 1);
+                                           0, count, align_mask);
        if (pageno < pool->nr_pages) {
                bitmap_set(pool->bitmap, pageno, count);
                ptr = pool->vaddr + PAGE_SIZE * pageno;
@@ -648,12 +648,12 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
 
        if (arch_is_coherent() || nommu()) {
                __dma_free_buffer(page, size);
+       } else if (__free_from_pool(cpu_addr, size)) {
+               return;
        } else if (!IS_ENABLED(CONFIG_CMA)) {
                __dma_free_remap(cpu_addr, size);
                __dma_free_buffer(page, size);
        } else {
-               if (__free_from_pool(cpu_addr, size))
-                       return;
                /*
                 * Non-atomic allocations cannot be freed with IRQs disabled
                 */
index 77458548e031fe73d75a5a79ea36f923c95cc88a..40ca11ed6e5fbae9c54914db0123bf136e788481 100644 (file)
@@ -231,8 +231,6 @@ void __sync_icache_dcache(pte_t pteval)
        struct page *page;
        struct address_space *mapping;
 
-       if (!pte_present_user(pteval))
-               return;
        if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
                /* only flush non-aliasing VIPT caches for exec mappings */
                return;
index c2021139cb563fd14a74c327d453f3cf0cee183d..ea94765acf9a3650f5cb850f6990893f3ccb459b 100644 (file)
@@ -38,10 +38,10 @@ ENTRY(v7wbi_flush_user_tlb_range)
        dsb
        mov     r0, r0, lsr #PAGE_SHIFT         @ align address
        mov     r1, r1, lsr #PAGE_SHIFT
-#ifdef CONFIG_ARM_ERRATA_720789
-       mov     r3, #0
-#else
        asid    r3, r3                          @ mask ASID
+#ifdef CONFIG_ARM_ERRATA_720789
+       ALT_SMP(W(mov)  r3, #0  )
+       ALT_UP(W(nop)           )
 #endif
        orr     r0, r3, r0, lsl #PAGE_SHIFT     @ Create initial MVA
        mov     r1, r1, lsl #PAGE_SHIFT
index 7aca31c1df1fe57ac91b4278b13ad8036a8dac93..9c3b90c3538e3b71bb1e71c8c8bf817ca5057a89 100644 (file)
@@ -403,7 +403,8 @@ config S5P_DEV_USB_EHCI
 
 config S3C24XX_PWM
        bool "PWM device support"
-       select HAVE_PWM
+       select PWM
+       select PWM_SAMSUNG
        help
          Support for exporting the PWM timer blocks via the pwm device
          system
index fb849d044bde9b231d481201c985f84cc37c0a3d..c834b32af275d73d4cd760efeb4a365e940f1df7 100644 (file)
@@ -719,8 +719,10 @@ static int __init vfp_init(void)
                        if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
                                elf_hwcap |= HWCAP_NEON;
 #endif
+#ifdef CONFIG_VFPv3
                        if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
                                elf_hwcap |= HWCAP_VFPv4;
+#endif
                }
        }
        return 0;
index ada8f0fc71e4731fc9bb619aacc7a77df50d7d54..fb96e607adcf815890de6ce475c55a3cfd76a42b 100644 (file)
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(reserved_mem_dcache_on);
 #ifdef CONFIG_MTD_UCLINUX
 extern struct map_info uclinux_ram_map;
 unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
-unsigned long _ebss;
 EXPORT_SYMBOL(memory_mtd_end);
 EXPORT_SYMBOL(memory_mtd_start);
 EXPORT_SYMBOL(mtd_size);
index 052f81a762398670188778a0645c8ed9ad1a4982..983c859e40b7b57e5eb1da68094524b7fe1c1301 100644 (file)
@@ -6,6 +6,7 @@
 config C6X
        def_bool y
        select CLKDEV_LOOKUP
+       select GENERIC_ATOMIC64
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
index 6d521d96d94136e25cd83158a5706a1c6681a84f..09c5a0f5f4d1778156a5ee83715e6a2aec7f0441 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Port on Texas Instruments TMS320C6x architecture
  *
- *  Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated
+ *  Copyright (C) 2005, 2006, 2009, 2010, 2012 Texas Instruments Incorporated
  *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
  *
  *  This program is free software; you can redistribute it and/or modify
 /*
  * Cache line size
  */
-#define L1D_CACHE_BYTES   64
-#define L1P_CACHE_BYTES   32
-#define L2_CACHE_BYTES   128
+#define L1D_CACHE_SHIFT   6
+#define L1D_CACHE_BYTES   (1 << L1D_CACHE_SHIFT)
+
+#define L1P_CACHE_SHIFT   5
+#define L1P_CACHE_BYTES   (1 << L1P_CACHE_SHIFT)
+
+#define L2_CACHE_SHIFT    7
+#define L2_CACHE_BYTES    (1 << L2_CACHE_SHIFT)
 
 /*
  * L2 used as cache
@@ -29,7 +34,8 @@
  * For practical reasons the L1_CACHE_BYTES defines should not be smaller than
  * the L2 line size
  */
-#define L1_CACHE_BYTES        L2_CACHE_BYTES
+#define L1_CACHE_SHIFT        L2_CACHE_SHIFT
+#define L1_CACHE_BYTES        (1 << L1_CACHE_SHIFT)
 
 #define L2_CACHE_ALIGN_LOW(x) \
        (((x) & ~(L2_CACHE_BYTES - 1)))
index 954d81e2e837648d80a67fb9648dad29dd6f39c4..7913695b2fcbe5605830b9e1da6441188a591b8b 100644 (file)
@@ -234,5 +234,4 @@ CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_T10DIF=y
-CONFIG_MISC_DEVICES=y
 CONFIG_INTEL_IOMMU=y
index 91c41ecfa6d9e0fad551ef268cab3f01200af2d8..f8e91336542392236c878276ad8abcef4d786166 100644 (file)
@@ -209,4 +209,3 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_CRYPTO_MD5=y
-CONFIG_MISC_DEVICES=y
index 6f38b6120d96bc841f4563c1fe3202ae7a78b7f3..440578850ae52bad9df8961aeec12d52f9a94ceb 100644 (file)
@@ -497,7 +497,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
        srat_num_cpus++;
 }
 
-void __init
+int __init
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
        unsigned long paddr, size;
@@ -512,7 +512,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 
        /* Ignore disabled entries */
        if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
-               return;
+               return -1;
 
        /* record this node in proximity bitmap */
        pxm_bit_set(pxm);
@@ -531,6 +531,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        p->size = size;
        p->nid = pxm;
        num_node_memblks++;
+       return 0;
 }
 
 void __init acpi_numa_arch_fixup(void)
index 0b0f8b8c4a266571d33fcd61900161d7961d8cea..b22df9410dceb75169f4127bb897befb6f4960ad 100644 (file)
@@ -5,6 +5,7 @@ config M68K
        select HAVE_AOUT if MMU
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_ATOMIC64
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select GENERIC_CPU_DEVICES
        select GENERIC_STRNCPY_FROM_USER if MMU
@@ -54,18 +55,6 @@ config ZONE_DMA
        bool
        default y
 
-config CPU_HAS_NO_BITFIELDS
-       bool
-
-config CPU_HAS_NO_MULDIV64
-       bool
-
-config CPU_HAS_ADDRESS_SPACES
-       bool
-
-config FPU
-       bool
-
 config HZ
        int
        default 1000 if CLEOPATRA
index 43a9f8f1b8eb43d41049051358b08667684cc6f0..c4eb79edecec04d58d5ad681c389118a3472cec5 100644 (file)
@@ -28,6 +28,7 @@ config COLDFIRE
        select CPU_HAS_NO_BITFIELDS
        select CPU_HAS_NO_MULDIV64
        select GENERIC_CSUM
+       select HAVE_CLK
 
 endchoice
 
@@ -37,6 +38,7 @@ config M68000
        bool
        select CPU_HAS_NO_BITFIELDS
        select CPU_HAS_NO_MULDIV64
+       select CPU_HAS_NO_UNALIGNED
        select GENERIC_CSUM
        help
          The Freescale (was Motorola) 68000 CPU is the first generation of
@@ -48,6 +50,7 @@ config M68000
 config MCPU32
        bool
        select CPU_HAS_NO_BITFIELDS
+       select CPU_HAS_NO_UNALIGNED
        help
          The Freescale (was then Motorola) CPU32 is a CPU core that is
          based on the 68020 processor. For the most part it is used in
@@ -56,7 +59,6 @@ config MCPU32
 config M68020
        bool "68020 support"
        depends on MMU
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68020
@@ -67,7 +69,6 @@ config M68020
 config M68030
        bool "68030 support"
        depends on MMU && !MMU_SUN3
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68030
@@ -77,7 +78,6 @@ config M68030
 config M68040
        bool "68040 support"
        depends on MMU && !MMU_SUN3
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68LC040
@@ -88,7 +88,6 @@ config M68040
 config M68060
        bool "68060 support"
        depends on MMU && !MMU_SUN3
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68060
@@ -376,6 +375,18 @@ config NODES_SHIFT
        default "3"
        depends on !SINGLE_MEMORY_CHUNK
 
+config CPU_HAS_NO_BITFIELDS
+       bool
+
+config CPU_HAS_NO_MULDIV64
+       bool
+
+config CPU_HAS_NO_UNALIGNED
+       bool
+
+config CPU_HAS_ADDRESS_SPACES
+       bool
+
 config FPU
        bool
 
index 0a30406b9442a4961b8f40fbc2832e0cc2079889..f5565d6eeb8e9bbe24b9ef1df22dea0310f9c4ee 100644 (file)
@@ -177,8 +177,8 @@ irqreturn_t dn_timer_int(int irq, void *dev_id)
 
        timer_handler(irq, dev_id);
 
-       x=*(volatile unsigned char *)(timer+3);
-       x=*(volatile unsigned char *)(timer+5);
+       x = *(volatile unsigned char *)(apollo_timer + 3);
+       x = *(volatile unsigned char *)(apollo_timer + 5);
 
        return IRQ_HANDLED;
 }
@@ -186,17 +186,17 @@ irqreturn_t dn_timer_int(int irq, void *dev_id)
 void dn_sched_init(irq_handler_t timer_routine)
 {
        /* program timer 1 */
-       *(volatile unsigned char *)(timer+3)=0x01;
-       *(volatile unsigned char *)(timer+1)=0x40;
-       *(volatile unsigned char *)(timer+5)=0x09;
-       *(volatile unsigned char *)(timer+7)=0xc4;
+       *(volatile unsigned char *)(apollo_timer + 3) = 0x01;
+       *(volatile unsigned char *)(apollo_timer + 1) = 0x40;
+       *(volatile unsigned char *)(apollo_timer + 5) = 0x09;
+       *(volatile unsigned char *)(apollo_timer + 7) = 0xc4;
 
        /* enable IRQ of PIC B */
        *(volatile unsigned char *)(pica+1)&=(~8);
 
 #if 0
-       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
-       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
+       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(apollo_timer + 0x3));
+       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(apollo_timer + 0x3));
 #endif
 
        if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine))
index eafa2539a8ee79dbcc65ea929ab082c767d93029..a74e5d95c384941583d99096bae1175634c9b4cb 100644 (file)
@@ -1,4 +1,29 @@
 include include/asm-generic/Kbuild.asm
 header-y += cachectl.h
 
+generic-y += bitsperlong.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += futex.h
+generic-y += ioctl.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += kvm_para.h
+generic-y += local64.h
+generic-y += local.h
+generic-y += mman.h
+generic-y += mutex.h
+generic-y += percpu.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += siginfo.h
+generic-y += statfs.h
+generic-y += topology.h
+generic-y += types.h
 generic-y += word-at-a-time.h
+generic-y += xor.h
diff --git a/arch/m68k/include/asm/MC68332.h b/arch/m68k/include/asm/MC68332.h
deleted file mode 100644 (file)
index 6bb8f02..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-
-/* include/asm-m68knommu/MC68332.h: '332 control registers
- *
- * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
- *
- */
-
-#ifndef _MC68332_H_
-#define _MC68332_H_
-
-#define BYTE_REF(addr) (*((volatile unsigned char*)addr))
-#define WORD_REF(addr) (*((volatile unsigned short*)addr))
-
-#define PORTE_ADDR     0xfffa11
-#define PORTE  BYTE_REF(PORTE_ADDR)
-#define DDRE_ADDR      0xfffa15
-#define DDRE   BYTE_REF(DDRE_ADDR)
-#define PEPAR_ADDR     0xfffa17
-#define PEPAR  BYTE_REF(PEPAR_ADDR)
-
-#define PORTF_ADDR     0xfffa19
-#define PORTF  BYTE_REF(PORTF_ADDR)
-#define DDRF_ADDR      0xfffa1d
-#define DDRF   BYTE_REF(DDRF_ADDR)
-#define PFPAR_ADDR     0xfffa1f
-#define PFPAR  BYTE_REF(PFPAR_ADDR)
-
-#define PORTQS_ADDR    0xfffc15
-#define PORTQS BYTE_REF(PORTQS_ADDR)
-#define DDRQS_ADDR     0xfffc17
-#define DDRQS  BYTE_REF(DDRQS_ADDR)
-#define PQSPAR_ADDR    0xfffc16
-#define PQSPAR BYTE_REF(PQSPAR_ADDR)
-
-#define CSPAR0_ADDR 0xFFFA44
-#define CSPAR0 WORD_REF(CSPAR0_ADDR)
-#define CSPAR1_ADDR 0xFFFA46
-#define CSPAR1 WORD_REF(CSPAR1_ADDR)
-#define CSARBT_ADDR 0xFFFA48
-#define CSARBT WORD_REF(CSARBT_ADDR)
-#define CSOPBT_ADDR 0xFFFA4A
-#define CSOPBT WORD_REF(CSOPBT_ADDR)
-#define CSBAR0_ADDR 0xFFFA4C
-#define CSBAR0 WORD_REF(CSBAR0_ADDR)
-#define CSOR0_ADDR 0xFFFA4E
-#define CSOR0 WORD_REF(CSOR0_ADDR)
-#define CSBAR1_ADDR 0xFFFA50
-#define CSBAR1 WORD_REF(CSBAR1_ADDR)
-#define CSOR1_ADDR 0xFFFA52
-#define CSOR1 WORD_REF(CSOR1_ADDR)
-#define CSBAR2_ADDR 0xFFFA54
-#define CSBAR2 WORD_REF(CSBAR2_ADDR)
-#define CSOR2_ADDR 0xFFFA56
-#define CSOR2 WORD_REF(CSOR2_ADDR)
-#define CSBAR3_ADDR 0xFFFA58
-#define CSBAR3 WORD_REF(CSBAR3_ADDR)
-#define CSOR3_ADDR 0xFFFA5A
-#define CSOR3 WORD_REF(CSOR3_ADDR)
-#define CSBAR4_ADDR 0xFFFA5C
-#define CSBAR4 WORD_REF(CSBAR4_ADDR)
-#define CSOR4_ADDR 0xFFFA5E
-#define CSOR4 WORD_REF(CSOR4_ADDR)
-#define CSBAR5_ADDR 0xFFFA60
-#define CSBAR5 WORD_REF(CSBAR5_ADDR)
-#define CSOR5_ADDR 0xFFFA62
-#define CSOR5 WORD_REF(CSOR5_ADDR)
-#define CSBAR6_ADDR 0xFFFA64
-#define CSBAR6 WORD_REF(CSBAR6_ADDR)
-#define CSOR6_ADDR 0xFFFA66
-#define CSOR6 WORD_REF(CSOR6_ADDR)
-#define CSBAR7_ADDR 0xFFFA68
-#define CSBAR7 WORD_REF(CSBAR7_ADDR)
-#define CSOR7_ADDR 0xFFFA6A
-#define CSOR7 WORD_REF(CSOR7_ADDR)
-#define CSBAR8_ADDR 0xFFFA6C
-#define CSBAR8 WORD_REF(CSBAR8_ADDR)
-#define CSOR8_ADDR 0xFFFA6E
-#define CSOR8 WORD_REF(CSOR8_ADDR)
-#define CSBAR9_ADDR 0xFFFA70
-#define CSBAR9 WORD_REF(CSBAR9_ADDR)
-#define CSOR9_ADDR 0xFFFA72
-#define CSOR9 WORD_REF(CSOR9_ADDR)
-#define CSBAR10_ADDR 0xFFFA74
-#define CSBAR10 WORD_REF(CSBAR10_ADDR)
-#define CSOR10_ADDR 0xFFFA76
-#define CSOR10 WORD_REF(CSOR10_ADDR)
-
-#define CSOR_MODE_ASYNC        0x0000
-#define CSOR_MODE_SYNC 0x8000
-#define CSOR_MODE_MASK 0x8000
-#define CSOR_BYTE_DISABLE      0x0000
-#define CSOR_BYTE_UPPER                0x4000
-#define CSOR_BYTE_LOWER                0x2000
-#define CSOR_BYTE_BOTH         0x6000
-#define CSOR_BYTE_MASK         0x6000
-#define CSOR_RW_RSVD           0x0000
-#define CSOR_RW_READ           0x0800
-#define CSOR_RW_WRITE          0x1000
-#define CSOR_RW_BOTH           0x1800
-#define CSOR_RW_MASK           0x1800
-#define CSOR_STROBE_DS         0x0400
-#define CSOR_STROBE_AS         0x0000
-#define CSOR_STROBE_MASK       0x0400
-#define CSOR_DSACK_WAIT(x)     (wait << 6)
-#define CSOR_DSACK_FTERM       (14 << 6)
-#define CSOR_DSACK_EXTERNAL    (15 << 6)
-#define CSOR_DSACK_MASK                0x03c0
-#define CSOR_SPACE_CPU         0x0000
-#define CSOR_SPACE_USER                0x0010
-#define CSOR_SPACE_SU          0x0020
-#define CSOR_SPACE_BOTH                0x0030
-#define CSOR_SPACE_MASK                0x0030
-#define CSOR_IPL_ALL           0x0000
-#define CSOR_IPL_PRIORITY(x)   (x << 1)
-#define CSOR_IPL_MASK          0x000e
-#define CSOR_AVEC_ON           0x0001
-#define CSOR_AVEC_OFF          0x0000
-#define CSOR_AVEC_MASK         0x0001
-
-#define CSBAR_ADDR(x)          ((addr >> 11) << 3) 
-#define CSBAR_ADDR_MASK                0xfff8
-#define CSBAR_BLKSIZE_2K       0x0000
-#define CSBAR_BLKSIZE_8K       0x0001
-#define CSBAR_BLKSIZE_16K      0x0002
-#define CSBAR_BLKSIZE_64K      0x0003
-#define CSBAR_BLKSIZE_128K     0x0004
-#define CSBAR_BLKSIZE_256K     0x0005
-#define CSBAR_BLKSIZE_512K     0x0006
-#define CSBAR_BLKSIZE_1M       0x0007
-#define CSBAR_BLKSIZE_MASK     0x0007
-
-#define CSPAR_DISC     0
-#define CSPAR_ALT      1
-#define CSPAR_CS8      2
-#define CSPAR_CS16     3
-#define CSPAR_MASK     3
-
-#define CSPAR0_CSBOOT(x) (x << 0)
-#define CSPAR0_CS0(x)  (x << 2)
-#define CSPAR0_CS1(x)  (x << 4)
-#define CSPAR0_CS2(x)  (x << 6)
-#define CSPAR0_CS3(x)  (x << 8)
-#define CSPAR0_CS4(x)  (x << 10)
-#define CSPAR0_CS5(x)  (x << 12)
-
-#define CSPAR1_CS6(x)  (x << 0)
-#define CSPAR1_CS7(x)  (x << 2)
-#define CSPAR1_CS8(x)  (x << 4)
-#define CSPAR1_CS9(x)  (x << 6)
-#define CSPAR1_CS10(x) (x << 8)
-
-#endif
diff --git a/arch/m68k/include/asm/apollodma.h b/arch/m68k/include/asm/apollodma.h
deleted file mode 100644 (file)
index 954adc8..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * linux/include/asm/dma.h: Defines for using and allocating dma channels.
- * Written by Hennus Bergman, 1992.
- * High DMA channel support & info by Hannu Savolainen
- * and John Boyd, Nov. 1992.
- */
-
-#ifndef _ASM_APOLLO_DMA_H
-#define _ASM_APOLLO_DMA_H
-
-#include <asm/apollohw.h>              /* need byte IO */
-#include <linux/spinlock.h>            /* And spinlocks */
-#include <linux/delay.h>
-
-
-#define dma_outb(val,addr) (*((volatile unsigned char *)(addr+IO_BASE)) = (val))
-#define dma_inb(addr)     (*((volatile unsigned char *)(addr+IO_BASE)))
-
-/*
- * NOTES about DMA transfers:
- *
- *  controller 1: channels 0-3, byte operations, ports 00-1F
- *  controller 2: channels 4-7, word operations, ports C0-DF
- *
- *  - ALL registers are 8 bits only, regardless of transfer size
- *  - channel 4 is not used - cascades 1 into 2.
- *  - channels 0-3 are byte - addresses/counts are for physical bytes
- *  - channels 5-7 are word - addresses/counts are for physical words
- *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
- *  - transfer count loaded to registers is 1 less than actual count
- *  - controller 2 offsets are all even (2x offsets for controller 1)
- *  - page registers for 5-7 don't use data bit 0, represent 128K pages
- *  - page registers for 0-3 use bit 0, represent 64K pages
- *
- * DMA transfers are limited to the lower 16MB of _physical_ memory.
- * Note that addresses loaded into registers must be _physical_ addresses,
- * not logical addresses (which may differ if paging is active).
- *
- *  Address mapping for channels 0-3:
- *
- *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
- *    |  ...  |   |  ... |   |  ... |
- *    |  ...  |   |  ... |   |  ... |
- *    |  ...  |   |  ... |   |  ... |
- *   P7  ...  P0  A7 ... A0  A7 ... A0
- * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
- *
- *  Address mapping for channels 5-7:
- *
- *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
- *    |  ...  |   \   \   ... \  \  \  ... \  \
- *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
- *    |  ...  |     \   \   ... \  \  \  ... \
- *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0
- * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
- *
- * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
- * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
- * the hardware level, so odd-byte transfers aren't possible).
- *
- * Transfer count (_not # bytes_) is limited to 64K, represented as actual
- * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
- * and up to 128K bytes may be transferred on channels 5-7 in one operation.
- *
- */
-
-#define MAX_DMA_CHANNELS       8
-
-/* The maximum address that we can perform a DMA transfer to on this platform */#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x1000000)
-
-/* 8237 DMA controllers */
-#define IO_DMA1_BASE   0x10C00 /* 8 bit slave DMA, channels 0..3 */
-#define IO_DMA2_BASE   0x10D00 /* 16 bit master DMA, ch 4(=slave input)..7 */
-
-/* DMA controller registers */
-#define DMA1_CMD_REG           (IO_DMA1_BASE+0x08) /* command register (w) */
-#define DMA1_STAT_REG          (IO_DMA1_BASE+0x08) /* status register (r) */
-#define DMA1_REQ_REG            (IO_DMA1_BASE+0x09) /* request register (w) */
-#define DMA1_MASK_REG          (IO_DMA1_BASE+0x0A) /* single-channel mask (w) */
-#define DMA1_MODE_REG          (IO_DMA1_BASE+0x0B) /* mode register (w) */
-#define DMA1_CLEAR_FF_REG      (IO_DMA1_BASE+0x0C) /* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG           (IO_DMA1_BASE+0x0D) /* Temporary Register (r) */
-#define DMA1_RESET_REG         (IO_DMA1_BASE+0x0D) /* Master Clear (w) */
-#define DMA1_CLR_MASK_REG       (IO_DMA1_BASE+0x0E) /* Clear Mask */
-#define DMA1_MASK_ALL_REG       (IO_DMA1_BASE+0x0F) /* all-channels mask (w) */
-
-#define DMA2_CMD_REG           (IO_DMA2_BASE+0x10) /* command register (w) */
-#define DMA2_STAT_REG          (IO_DMA2_BASE+0x10) /* status register (r) */
-#define DMA2_REQ_REG            (IO_DMA2_BASE+0x12) /* request register (w) */
-#define DMA2_MASK_REG          (IO_DMA2_BASE+0x14) /* single-channel mask (w) */
-#define DMA2_MODE_REG          (IO_DMA2_BASE+0x16) /* mode register (w) */
-#define DMA2_CLEAR_FF_REG      (IO_DMA2_BASE+0x18) /* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG           (IO_DMA2_BASE+0x1A) /* Temporary Register (r) */
-#define DMA2_RESET_REG         (IO_DMA2_BASE+0x1A) /* Master Clear (w) */
-#define DMA2_CLR_MASK_REG       (IO_DMA2_BASE+0x1C) /* Clear Mask */
-#define DMA2_MASK_ALL_REG       (IO_DMA2_BASE+0x1E) /* all-channels mask (w) */
-
-#define DMA_ADDR_0              (IO_DMA1_BASE+0x00) /* DMA address registers */
-#define DMA_ADDR_1              (IO_DMA1_BASE+0x02)
-#define DMA_ADDR_2              (IO_DMA1_BASE+0x04)
-#define DMA_ADDR_3              (IO_DMA1_BASE+0x06)
-#define DMA_ADDR_4              (IO_DMA2_BASE+0x00)
-#define DMA_ADDR_5              (IO_DMA2_BASE+0x04)
-#define DMA_ADDR_6              (IO_DMA2_BASE+0x08)
-#define DMA_ADDR_7              (IO_DMA2_BASE+0x0C)
-
-#define DMA_CNT_0               (IO_DMA1_BASE+0x01)   /* DMA count registers */
-#define DMA_CNT_1               (IO_DMA1_BASE+0x03)
-#define DMA_CNT_2               (IO_DMA1_BASE+0x05)
-#define DMA_CNT_3               (IO_DMA1_BASE+0x07)
-#define DMA_CNT_4               (IO_DMA2_BASE+0x02)
-#define DMA_CNT_5               (IO_DMA2_BASE+0x06)
-#define DMA_CNT_6               (IO_DMA2_BASE+0x0A)
-#define DMA_CNT_7               (IO_DMA2_BASE+0x0E)
-
-#define DMA_MODE_READ  0x44    /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE 0x48    /* memory to I/O, no autoinit, increment, single mode */
-#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
-
-#define DMA_AUTOINIT   0x10
-
-#define DMA_8BIT 0
-#define DMA_16BIT 1
-#define DMA_BUSMASTER 2
-
-extern spinlock_t  dma_spin_lock;
-
-static __inline__ unsigned long claim_dma_lock(void)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dma_spin_lock, flags);
-       return flags;
-}
-
-static __inline__ void release_dma_lock(unsigned long flags)
-{
-       spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* enable/disable a specific DMA channel */
-static __inline__ void enable_dma(unsigned int dmanr)
-{
-       if (dmanr<=3)
-               dma_outb(dmanr,  DMA1_MASK_REG);
-       else
-               dma_outb(dmanr & 3,  DMA2_MASK_REG);
-}
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-       if (dmanr<=3)
-               dma_outb(dmanr | 4,  DMA1_MASK_REG);
-       else
-               dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while holding the DMA lock ! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-       if (dmanr<=3)
-               dma_outb(0,  DMA1_CLEAR_FF_REG);
-       else
-               dma_outb(0,  DMA2_CLEAR_FF_REG);
-}
-
-/* set mode (above) for a specific DMA channel */
-static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
-{
-       if (dmanr<=3)
-               dma_outb(mode | dmanr,  DMA1_MODE_REG);
-       else
-               dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
-}
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
-{
-       if (dmanr <= 3)  {
-           dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-            dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-       }  else  {
-           dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-           dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-       }
-}
-
-
-/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
- * a specific DMA channel.
- * You must ensure the parameters are valid.
- * NOTE: from a manual: "the number of transfers is one more
- * than the initial word count"! This is taken into account.
- * Assumes dma flip-flop is clear.
- * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
- */
-static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
-{
-        count--;
-       if (dmanr <= 3)  {
-           dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-           dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-        } else {
-           dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-           dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-        }
-}
-
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-static __inline__ int get_dma_residue(unsigned int dmanr)
-{
-       unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
-                                        : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
-
-       /* using short to get 16-bit wrap around */
-       unsigned short count;
-
-       count = 1 + dma_inb(io_port);
-       count += dma_inb(io_port) << 8;
-
-       return (dmanr<=3)? count : (count<<1);
-}
-
-
-/* These are in kernel/dma.c: */
-extern int request_dma(unsigned int dmanr, const char * device_id);    /* reserve a DMA channel */
-extern void free_dma(unsigned int dmanr);      /* release it again */
-
-/* These are in arch/m68k/apollo/dma.c: */
-extern unsigned short dma_map_page(unsigned long phys_addr,int count,int type);
-extern void dma_unmap_page(unsigned short dma_addr);
-
-#endif /* _ASM_APOLLO_DMA_H */
index a1373b9aa2811535728a5e95c07fdd827b6099b1..635ef4f890102b187ef86710ceb341c5af91bdb5 100644 (file)
@@ -98,7 +98,7 @@ extern u_long timer_physaddr;
 #define cpuctrl (*(volatile unsigned int *)(IO_BASE + cpuctrl_physaddr))
 #define pica (IO_BASE + pica_physaddr)
 #define picb (IO_BASE + picb_physaddr)
-#define timer (IO_BASE + timer_physaddr)
+#define apollo_timer (IO_BASE + timer_physaddr)
 #define addr_xlat_map ((unsigned short *)(IO_BASE + 0x17000))
 
 #define isaIO2mem(x) (((((x) & 0x3f8)  << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
diff --git a/arch/m68k/include/asm/bitsperlong.h b/arch/m68k/include/asm/bitsperlong.h
deleted file mode 100644 (file)
index 6dc0bb0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/bitsperlong.h>
diff --git a/arch/m68k/include/asm/cputime.h b/arch/m68k/include/asm/cputime.h
deleted file mode 100644 (file)
index c79c5e8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __M68K_CPUTIME_H
-#define __M68K_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __M68K_CPUTIME_H */
index 9c09becfd4c97fa96c249288f8ef3056832e8f4e..12d8fe4f1d30b5e6fe0f86b191b05bd2b0307251 100644 (file)
@@ -43,7 +43,7 @@ static inline void __delay(unsigned long loops)
 extern void __bad_udelay(void);
 
 
-#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+#ifdef CONFIG_CPU_HAS_NO_MULDIV64
 /*
  * The simpler m68k and ColdFire processors do not have a 32*32->64
  * multiply instruction. So we need to handle them a little differently.
diff --git a/arch/m68k/include/asm/device.h b/arch/m68k/include/asm/device.h
deleted file mode 100644 (file)
index d8f9872..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Arch specific extensions to struct device
- *
- * This file is released under the GPLv2
- */
-#include <asm-generic/device.h>
-
diff --git a/arch/m68k/include/asm/emergency-restart.h b/arch/m68k/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/m68k/include/asm/errno.h b/arch/m68k/include/asm/errno.h
deleted file mode 100644 (file)
index 0d4e188..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_ERRNO_H
-#define _M68K_ERRNO_H
-
-#include <asm-generic/errno.h>
-
-#endif /* _M68K_ERRNO_H */
diff --git a/arch/m68k/include/asm/futex.h b/arch/m68k/include/asm/futex.h
deleted file mode 100644 (file)
index 6a332a9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
-
-#include <asm-generic/futex.h>
-
-#endif
diff --git a/arch/m68k/include/asm/ioctl.h b/arch/m68k/include/asm/ioctl.h
deleted file mode 100644 (file)
index b279fe0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ioctl.h>
diff --git a/arch/m68k/include/asm/ipcbuf.h b/arch/m68k/include/asm/ipcbuf.h
deleted file mode 100644 (file)
index 84c7e51..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipcbuf.h>
diff --git a/arch/m68k/include/asm/irq_regs.h b/arch/m68k/include/asm/irq_regs.h
deleted file mode 100644 (file)
index 3dd9c0b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/m68k/include/asm/kdebug.h b/arch/m68k/include/asm/kdebug.h
deleted file mode 100644 (file)
index 6ece1b0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kdebug.h>
diff --git a/arch/m68k/include/asm/kmap_types.h b/arch/m68k/include/asm/kmap_types.h
deleted file mode 100644 (file)
index 3413cc1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_KMAP_TYPES_H
-#define __ASM_M68K_KMAP_TYPES_H
-
-#include <asm-generic/kmap_types.h>
-
-#endif /* __ASM_M68K_KMAP_TYPES_H */
diff --git a/arch/m68k/include/asm/kvm_para.h b/arch/m68k/include/asm/kvm_para.h
deleted file mode 100644 (file)
index 14fab8f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
diff --git a/arch/m68k/include/asm/local.h b/arch/m68k/include/asm/local.h
deleted file mode 100644 (file)
index 6c25926..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_LOCAL_H
-#define _ASM_M68K_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif /* _ASM_M68K_LOCAL_H */
diff --git a/arch/m68k/include/asm/local64.h b/arch/m68k/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
diff --git a/arch/m68k/include/asm/mac_mouse.h b/arch/m68k/include/asm/mac_mouse.h
deleted file mode 100644 (file)
index 39a5c29..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _ASM_MAC_MOUSE_H
-#define _ASM_MAC_MOUSE_H
-
-/*
- * linux/include/asm-m68k/mac_mouse.h
- * header file for Macintosh ADB mouse driver
- * 27-10-97 Michael Schmitz
- * copied from:
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
-       char            buttons;
-       short           dx;
-       short           dy;
-       int             ready;
-       int             active;
-       wait_queue_head_t wait;
-       struct fasync_struct *fasyncptr;
-};
-
-#endif
diff --git a/arch/m68k/include/asm/mcfmbus.h b/arch/m68k/include/asm/mcfmbus.h
deleted file mode 100644 (file)
index 319899c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************/
-
-/*
- *      mcfmbus.h -- Coldfire MBUS support defines.
- *
- *      (C) Copyright 1999, Martin Floeer (mfloeer@axcent.de) 
- */
-
-/****************************************************************************/
-
-
-#ifndef mcfmbus_h
-#define mcfmbus_h
-
-
-#define MCFMBUS_BASE           0x280
-#define MCFMBUS_IRQ_VECTOR     0x19
-#define MCFMBUS_IRQ            0x1
-#define MCFMBUS_CLK            0x3f
-#define MCFMBUS_IRQ_LEVEL      0x07    /*IRQ Level 1*/
-#define MCFMBUS_ADDRESS                0x01
-
-
-/*
-*      Define the 5307 MBUS register set addresses
-*/
-
-#define MCFMBUS_MADR   0x00
-#define MCFMBUS_MFDR   0x04
-#define MCFMBUS_MBCR   0x08
-#define MCFMBUS_MBSR   0x0C
-#define MCFMBUS_MBDR   0x10
-
-
-#define MCFMBUS_MADR_ADDR(a)   (((a)&0x7F)<<0x01) /*Slave Address*/
-
-#define MCFMBUS_MFDR_MBC(a)    ((a)&0x3F)         /*M-Bus Clock*/
-
-/*
-*      Define bit flags in Control Register
-*/
-
-#define MCFMBUS_MBCR_MEN           (0x80)  /* M-Bus Enable                 */
-#define MCFMBUS_MBCR_MIEN          (0x40)  /* M-Bus Interrupt Enable       */
-#define MCFMBUS_MBCR_MSTA          (0x20)  /* Master/Slave Mode Select Bit */
-#define MCFMBUS_MBCR_MTX           (0x10)  /* Transmit/Rcv Mode Select Bit */
-#define MCFMBUS_MBCR_TXAK          (0x08)  /* Transmit Acknowledge Enable  */
-#define MCFMBUS_MBCR_RSTA          (0x04)  /* Repeat Start                 */
-
-/*
-*      Define bit flags in Status Register
-*/
-
-#define MCFMBUS_MBSR_MCF           (0x80)  /* Data Transfer Complete       */
-#define MCFMBUS_MBSR_MAAS          (0x40)  /* Addressed as a Slave         */
-#define MCFMBUS_MBSR_MBB           (0x20)  /* Bus Busy                     */
-#define MCFMBUS_MBSR_MAL           (0x10)  /* Arbitration Lost             */
-#define MCFMBUS_MBSR_SRW           (0x04)  /* Slave Transmit               */
-#define MCFMBUS_MBSR_MIF           (0x02)  /* M-Bus Interrupt              */
-#define MCFMBUS_MBSR_RXAK          (0x01)  /* No Acknowledge Received      */
-
-/*
-*      Define bit flags in DATA I/O Register
-*/
-
-#define MCFMBUS_MBDR_READ          (0x01)  /* 1=read 0=write MBUS */
-
-#define MBUSIOCSCLOCK          1
-#define MBUSIOCGCLOCK          2
-#define MBUSIOCSADDR                   3
-#define MBUSIOCGADDR                   4
-#define MBUSIOCSSLADDR                 5
-#define MBUSIOCGSLADDR                 6
-#define MBUSIOCSSUBADDR                        7
-#define MBUSIOCGSUBADDR                        8
-
-#endif
diff --git a/arch/m68k/include/asm/mman.h b/arch/m68k/include/asm/mman.h
deleted file mode 100644 (file)
index 8eebf89..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/mman.h>
diff --git a/arch/m68k/include/asm/mutex.h b/arch/m68k/include/asm/mutex.h
deleted file mode 100644 (file)
index 458c1f7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/m68k/include/asm/percpu.h b/arch/m68k/include/asm/percpu.h
deleted file mode 100644 (file)
index 0859d04..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_PERCPU_H
-#define __ASM_M68K_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ASM_M68K_PERCPU_H */
diff --git a/arch/m68k/include/asm/resource.h b/arch/m68k/include/asm/resource.h
deleted file mode 100644 (file)
index e7d3501..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_RESOURCE_H
-#define _M68K_RESOURCE_H
-
-#include <asm-generic/resource.h>
-
-#endif /* _M68K_RESOURCE_H */
diff --git a/arch/m68k/include/asm/sbus.h b/arch/m68k/include/asm/sbus.h
deleted file mode 100644 (file)
index bfe3ba1..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * some sbus structures and macros to make usage of sbus drivers possible
- */
-
-#ifndef __M68K_SBUS_H
-#define __M68K_SBUS_H
-
-struct sbus_dev {
-       struct {
-               unsigned int which_io;
-               unsigned int phys_addr;
-       } reg_addrs[1];
-};
-
-/* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */
-/* No SBUS on the Sun3, kludge -- sam */
-
-static inline void _sbus_writeb(unsigned char val, unsigned long addr)
-{
-       *(volatile unsigned char *)addr = val;
-}
-
-static inline unsigned char _sbus_readb(unsigned long addr)
-{
-       return *(volatile unsigned char *)addr;
-}
-
-static inline void _sbus_writel(unsigned long val, unsigned long addr)
-{
-       *(volatile unsigned long *)addr = val;
-
-}
-
-extern inline unsigned long _sbus_readl(unsigned long addr)
-{
-       return *(volatile unsigned long *)addr;
-}
-
-
-#define sbus_readb(a) _sbus_readb((unsigned long)a)
-#define sbus_writeb(v, a) _sbus_writeb(v, (unsigned long)a)
-#define sbus_readl(a) _sbus_readl((unsigned long)a)
-#define sbus_writel(v, a) _sbus_writel(v, (unsigned long)a)
-
-#endif
diff --git a/arch/m68k/include/asm/scatterlist.h b/arch/m68k/include/asm/scatterlist.h
deleted file mode 100644 (file)
index 3125054..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SCATTERLIST_H
-#define _M68K_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/arch/m68k/include/asm/sections.h b/arch/m68k/include/asm/sections.h
deleted file mode 100644 (file)
index 5277e52..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _ASM_M68K_SECTIONS_H
-#define _ASM_M68K_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-extern char _sbss[], _ebss[];
-
-#endif /* _ASM_M68K_SECTIONS_H */
diff --git a/arch/m68k/include/asm/shm.h b/arch/m68k/include/asm/shm.h
deleted file mode 100644 (file)
index fa56ec8..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _M68K_SHM_H
-#define _M68K_SHM_H
-
-
-/* format of page table entries that correspond to shared memory pages
-   currently out in swap space (see also mm/swap.c):
-   bits 0-1 (PAGE_PRESENT) is  = 0
-   bits 8..2 (SWP_TYPE) are = SHM_SWP_TYPE
-   bits 31..9 are used like this:
-   bits 15..9 (SHM_ID) the id of the shared memory segment
-   bits 30..16 (SHM_IDX) the index of the page within the shared memory segment
-                    (actually only bits 25..16 get used since SHMMAX is so low)
-   bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
-*/
-/* on the m68k both bits 0 and 1 must be zero */
-/* format on the sun3 is similar, but bits 30, 31 are set to zero and all
-   others are reduced by 2. --m */
-
-#ifndef CONFIG_SUN3
-#define SHM_ID_SHIFT   9
-#else
-#define SHM_ID_SHIFT   7
-#endif
-#define _SHM_ID_BITS   7
-#define SHM_ID_MASK    ((1<<_SHM_ID_BITS)-1)
-
-#define SHM_IDX_SHIFT  (SHM_ID_SHIFT+_SHM_ID_BITS)
-#define _SHM_IDX_BITS  15
-#define SHM_IDX_MASK   ((1<<_SHM_IDX_BITS)-1)
-
-#endif /* _M68K_SHM_H */
diff --git a/arch/m68k/include/asm/siginfo.h b/arch/m68k/include/asm/siginfo.h
deleted file mode 100644 (file)
index 851d3d7..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SIGINFO_H
-#define _M68K_SIGINFO_H
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/m68k/include/asm/statfs.h b/arch/m68k/include/asm/statfs.h
deleted file mode 100644 (file)
index 08d93f1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_STATFS_H
-#define _M68K_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif /* _M68K_STATFS_H */
diff --git a/arch/m68k/include/asm/topology.h b/arch/m68k/include/asm/topology.h
deleted file mode 100644 (file)
index ca173e9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_TOPOLOGY_H
-#define _ASM_M68K_TOPOLOGY_H
-
-#include <asm-generic/topology.h>
-
-#endif /* _ASM_M68K_TOPOLOGY_H */
diff --git a/arch/m68k/include/asm/types.h b/arch/m68k/include/asm/types.h
deleted file mode 100644 (file)
index 89705ad..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _M68K_TYPES_H
-#define _M68K_TYPES_H
-
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue.  However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-#include <asm-generic/int-ll64.h>
-
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __KERNEL__
-
-#define BITS_PER_LONG 32
-
-#endif /* __KERNEL__ */
-
-#endif /* _M68K_TYPES_H */
index f4043ae63db1292889957f28cee8d4375d5719e3..2b3ca0bf7a0df900b6442a9611e9da857020c0dc 100644 (file)
@@ -2,7 +2,7 @@
 #define _ASM_M68K_UNALIGNED_H
 
 
-#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68000)
+#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
 #include <linux/unaligned/be_struct.h>
 #include <linux/unaligned/le_byteshift.h>
 #include <linux/unaligned/generic.h>
@@ -12,7 +12,7 @@
 
 #else
 /*
- * The m68k can do unaligned accesses itself. 
+ * The m68k can do unaligned accesses itself.
  */
 #include <linux/unaligned/access_ok.h>
 #include <linux/unaligned/generic.h>
diff --git a/arch/m68k/include/asm/xor.h b/arch/m68k/include/asm/xor.h
deleted file mode 100644 (file)
index c82eb12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
index 7dc186b7a85fb27a098858a4106ac64d95abc1b4..71fb29938dba260b6e5895c3d7eb5f10f2afbb16 100644 (file)
@@ -218,13 +218,10 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
 #endif
 
-       pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
-                "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
-                (int) &_sdata, (int) &_edata,
-                (int) &_sbss, (int) &_ebss);
-       pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
-                (int) &_ebss, (int) memory_start,
-                (int) memory_start, (int) memory_end);
+       pr_debug("KERNEL -> TEXT=0x%p-0x%p DATA=0x%p-0x%p BSS=0x%p-0x%p\n",
+                _stext, _etext, _sdata, _edata, __bss_start, __bss_stop);
+       pr_debug("MEMORY -> ROMFS=0x%p-0x%06lx MEM=0x%06lx-0x%06lx\n ",
+                __bss_stop, memory_start, memory_start, memory_end);
 
        /* Keep a copy of command line */
        *cmdline_p = &command_line[0];
index 8623f8dc16f8a03c9da88910537ae93fc47bc510..9a5932ec368946bf808c5faf527cbf39731b5540 100644 (file)
@@ -479,9 +479,13 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
                        goto bad_access;
                }
 
-               mem_value = *mem;
+               /*
+                * No need to check for EFAULT; we know that the page is
+                * present and writable.
+                */
+               __get_user(mem_value, mem);
                if (mem_value == oldval)
-                       *mem = newval;
+                       __put_user(newval, mem);
 
                pte_unmap_unlock(pte, ptl);
                up_read(&mm->mmap_sem);
index 40e02d9c38b4df4bac25bf659d44885dd99f9fa8..06a763f49fd34643d5330221a48011be00889b0e 100644 (file)
@@ -78,9 +78,7 @@ SECTIONS {
                __init_end = .;
        }
 
-       _sbss = .;
        BSS_SECTION(0, 0, 0)
-       _ebss = .;
 
        _end = .;
 
index 63407c836826842a9dc2648c84fb3c50ba5c4f79..d0993594f558b3408317aede57c634c407ea580f 100644 (file)
@@ -31,9 +31,7 @@ SECTIONS
 
   RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
 
-  _sbss = .;
   BSS_SECTION(0, 0, 0)
-  _ebss = .;
 
   _edata = .;                  /* End of data section */
 
index ad0f46d64c0b66a8d6b6cf4f82ffeaeeabbda084..8080469ee6c11c3e86ab59febaa4773790a2ffc7 100644 (file)
@@ -44,9 +44,7 @@ __init_begin = .;
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
 
-  _sbss = .;
   BSS_SECTION(0, 0, 0)
-  _ebss = .;
 
   _end = . ;
 
index 79e928a525d078169e0617270e1fcea9da08b5f2..ee5f0b1b5c5dd9b86c78552f42e4e7e9210a74cb 100644 (file)
@@ -19,7 +19,7 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+#ifdef CONFIG_CPU_HAS_NO_MULDIV64
 
 #define SI_TYPE_SIZE 32
 #define __BITS4 (SI_TYPE_SIZE / 4)
index f77f258dce3aca67fbfbc2e02ba33718c918903f..282f9de68966ee20409af3e4d2244af716323ca8 100644 (file)
@@ -104,7 +104,7 @@ void __init print_memmap(void)
                MLK_ROUNDUP(__init_begin, __init_end),
                MLK_ROUNDUP(_stext, _etext),
                MLK_ROUNDUP(_sdata, _edata),
-               MLK_ROUNDUP(_sbss, _ebss));
+               MLK_ROUNDUP(__bss_start, __bss_stop));
 }
 
 void __init mem_init(void)
index 345ec0d83e3d4ab825ff89afd0f4b022f0c67246..688e3664aea072ef2e2ee951b9991db2ab7abb78 100644 (file)
@@ -91,7 +91,7 @@ void __init mem_init(void)
        totalram_pages = free_all_bootmem();
 
        codek = (_etext - _stext) >> 10;
-       datak = (_ebss - _sdata) >> 10;
+       datak = (__bss_stop - _sdata) >> 10;
        initk = (__init_begin - __init_end) >> 10;
 
        tmp = nr_free_pages() << PAGE_SHIFT;
index f632fdcb93e913b218b7e5a7743d089ac0f8172f..537d3245b539a9c7006dfc7abc03b1f9f4f5ff04 100644 (file)
@@ -60,8 +60,8 @@ _start:
  *     Move ROM filesystem above bss :-)
  */
 
-       moveal  #_sbss, %a0                     /* romfs at the start of bss */
-       moveal  #_ebss, %a1                     /* Set up destination  */
+       moveal  #__bss_start, %a0               /* romfs at the start of bss */
+       moveal  #__bss_stop, %a1                /* Set up destination  */
        movel   %a0, %a2                        /* Copy of bss start */
 
        movel   8(%a0), %d1                     /* Get size of ROMFS */
@@ -84,8 +84,8 @@ _start:
  * Initialize BSS segment to 0
  */
 
-       lea     _sbss, %a0
-       lea     _ebss, %a1
+       lea     __bss_start, %a0
+       lea     __bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 2:     cmpal   %a0, %a1
index 2ebfd642081855acb3af3e35dac9066ed886038c..45a9dad29e3d3948ba0f52dadd2d54cae7b4a31a 100644 (file)
@@ -110,7 +110,7 @@ L0:
        movel   #CONFIG_VECTORBASE, %d7
        addl    #16, %d7
        moveal  %d7, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_stop, %a1
        lea     %a1@(512), %a2
 
        DBG_PUTC('C')
@@ -138,8 +138,8 @@ LD1:
 
        DBG_PUTC('E')
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 L1:
@@ -150,7 +150,7 @@ L1:
        DBG_PUTC('F')
 
        /* Copy command line from end of bss to command line */
-       moveal  #_ebss, %a0
+       moveal  #__bss_stop, %a0
        moveal  #command_line, %a1
        lea     %a1@(512), %a2
 
@@ -165,7 +165,7 @@ L3:
 
        movel   #_sdata, %d0    
        movel   %d0, _rambase   
-       movel   #_ebss, %d0
+       movel   #__bss_stop, %d0
        movel   %d0, _ramstart
 
        movel   %a4, %d0
index 7f1aeeacb219a7525f3b142f4e27fefa5cb99ba5..5189ef9260986c31e0baaafec7ba770846ae118f 100644 (file)
@@ -76,8 +76,8 @@ pclp3:
        beq     pclp3
 #endif /* DEBUG */
        moveal  #0x007ffff0, %ssp
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 >= %a1 */
 L1:
index a5ff96d0295f069e28ded27ace22a5d1296e6cff..3dff98ba2e97df254743af9eebb5b297d539e548 100644 (file)
@@ -59,8 +59,8 @@ _stext:       movew   #0x2700,%sr
        cmpal   %a1, %a2
        bhi     1b
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
        /* Copy 0 to %a0 until %a0 == %a1 */
        
 1:
@@ -70,7 +70,7 @@ _stext:       movew   #0x2700,%sr
 
         movel   #_sdata, %d0    
         movel   %d0, _rambase        
-        movel   #_ebss, %d0
+        movel   #__bss_stop, %d0
         movel   %d0, _ramstart
        movel   #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0
        movel   %d0, _ramend
index 8eb94fb6b971a3c35867f558096af9a6f7cd6b0e..acd213170d80fe6ae1e74cddd2fcbd90c7b65115 100644 (file)
@@ -219,8 +219,8 @@ LD1:
        cmp.l   #_edata, %a1
        blt     LD1
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 L1:
@@ -234,7 +234,7 @@ load_quicc:
 store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
-       move.l  #_ebss, _ramstart
+       move.l  #__bss_stop, _ramstart
        move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
        move.l  %d0, _ramend                    /* Different from RAMEND.*/
index 97510e55b802a587ad547c9f36005540ae2c8fc5..dfc756d998861823e48ac2b87a291ea7d04cbbb2 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 .global _stext
-.global _sbss
+.global __bss_start
 .global _start
 
 .global _rambase
@@ -229,8 +229,8 @@ LD1:
        cmp.l   #_edata, %a1
        blt     LD1
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 L1:
@@ -244,7 +244,7 @@ load_quicc:
 store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
-       move.l  #_ebss, _ramstart
+       move.l  #__bss_stop, _ramstart
        move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
        move.l  %d0, _ramend                    /* Different from RAMEND.*/
index 4e0c9eb3bd1f437df4d8c469f58070b3558e8f5a..b88f5716f357b7acecc2e38a2f1bed8676ced43e 100644 (file)
@@ -230,8 +230,8 @@ _vstart:
        /*
         *      Move ROM filesystem above bss :-)
         */
-       lea     _sbss,%a0                       /* get start of bss */
-       lea     _ebss,%a1                       /* set up destination  */
+       lea     __bss_start,%a0                 /* get start of bss */
+       lea     __bss_stop,%a1                  /* set up destination  */
        movel   %a0,%a2                         /* copy of bss start */
 
        movel   8(%a0),%d0                      /* get size of ROMFS */
@@ -249,7 +249,7 @@ _copy_romfs:
        bne     _copy_romfs
 
 #else /* CONFIG_ROMFS_FS */
-       lea     _ebss,%a1
+       lea     __bss_stop,%a1
        movel   %a1,_ramstart
 #endif /* CONFIG_ROMFS_FS */
 
@@ -257,8 +257,8 @@ _copy_romfs:
        /*
         *      Zero out the bss region.
         */
-       lea     _sbss,%a0                       /* get start of bss */
-       lea     _ebss,%a1                       /* get end of bss */
+       lea     __bss_start,%a0                 /* get start of bss */
+       lea     __bss_stop,%a1                  /* get end of bss */
        clrl    %d0                             /* set value */
 _clear_bss:
        movel   %d0,(%a0)+                      /* clear each word */
index d8e6349336b4f54e9f03d26ebfc095821f1da30a..eeba067d565f4470937da6a40a61dcaf8caaae18 100644 (file)
@@ -22,57 +22,13 @@ int prom_root_node;
 struct linux_nodeops *prom_nodeops;
 
 /* You must call prom_init() before you attempt to use any of the
- * routines in the prom library.  It returns 0 on success, 1 on
- * failure.  It gets passed the pointer to the PROM vector.
+ * routines in the prom library.
+ * It gets passed the pointer to the PROM vector.
  */
 
-extern void prom_meminit(void);
-extern void prom_ranges_init(void);
-
 void __init prom_init(struct linux_romvec *rp)
 {
        romvec = rp;
-#ifndef CONFIG_SUN3
-       switch(romvec->pv_romvers) {
-       case 0:
-               prom_vers = PROM_V0;
-               break;
-       case 2:
-               prom_vers = PROM_V2;
-               break;
-       case 3:
-               prom_vers = PROM_V3;
-               break;
-       case 4:
-               prom_vers = PROM_P1275;
-               prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
-               prom_halt();
-               break;
-       default:
-               prom_printf("PROMLIB: Bad PROM version %d\n",
-                           romvec->pv_romvers);
-               prom_halt();
-               break;
-       };
-
-       prom_rev = romvec->pv_plugin_revision;
-       prom_prev = romvec->pv_printrev;
-       prom_nodeops = romvec->pv_nodeops;
-
-       prom_root_node = prom_getsibling(0);
-       if((prom_root_node == 0) || (prom_root_node == -1))
-               prom_halt();
-
-       if((((unsigned long) prom_nodeops) == 0) ||
-          (((unsigned long) prom_nodeops) == -1))
-               prom_halt();
-
-       prom_meminit();
-
-       prom_ranges_init();
-#endif
-//     printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
-//            romvec->pv_romvers, prom_rev);
 
        /* Initialization successful. */
        return;
index 4487e150b4555d2815417551cbdafc200234bb5a..c07ed5d2a82034f11cbadc6e836d4e31761d380f 100644 (file)
@@ -18,10 +18,6 @@ extern char _ssbss[], _esbss[];
 extern unsigned long __ivt_start[], __ivt_end[];
 extern char _etext[], _stext[];
 
-#  ifdef CONFIG_MTD_UCLINUX
-extern char *_ebss;
-#  endif
-
 extern u32 _fdt_start[], _fdt_end[];
 
 # endif /* !__ASSEMBLY__ */
index bb4907c828dcb4c64ba4f3f291af06046c86c8a7..2b25bcf05c0022e44bdd46eff061f0782b309c7d 100644 (file)
@@ -21,9 +21,6 @@
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
-extern char *_ebss;
-EXPORT_SYMBOL_GPL(_ebss);
-
 #ifdef CONFIG_FUNCTION_TRACER
 extern void _mcount(void);
 EXPORT_SYMBOL(_mcount);
index 16d8dfd9094b1a0df25eaa48799576449a8b234b..4da971d4392f6fc79c4fa2040c87cd0c224c46fc 100644 (file)
@@ -121,7 +121,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 
        /* Move ROMFS out of BSS before clearing it */
        if (romfs_size > 0) {
-               memmove(&_ebss, (int *)romfs_base, romfs_size);
+               memmove(&__bss_stop, (int *)romfs_base, romfs_size);
                klimit += romfs_size;
        }
 #endif
@@ -165,7 +165,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        BUG_ON(romfs_size < 0); /* What else can we do? */
 
        printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
-                       romfs_size, romfs_base, (unsigned)&_ebss);
+                       romfs_size, romfs_base, (unsigned)&__bss_stop);
 
        printk("New klimit: 0x%08x\n", (unsigned)klimit);
 #endif
index 109e9d86ade4e46051f25c1d375eac1cd9f83224..936d01a689d74157f3a63e53eff1de725fa67f9d 100644 (file)
@@ -131,7 +131,6 @@ SECTIONS {
                        *(COMMON)
                . = ALIGN (4) ;
                __bss_stop = . ;
-               _ebss = . ;
        }
        . = ALIGN(PAGE_SIZE);
        _end = .;
index 76de6b68487c8a44aa4eabecc1dddc7d916546e2..107610e01a295e27a7fdb1d82fbf8ad0270a4bfc 100644 (file)
@@ -124,6 +124,7 @@ config S390
        select GENERIC_TIME_VSYSCALL
        select GENERIC_CLOCKEVENTS
        select KTIME_SCALAR if 32BIT
+       select HAVE_ARCH_SECCOMP_FILTER
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
index 0fb34027d3f6fbdc5a851f796a0e23d368bea071..a60d085ddb4d90089d7e73850955432ca2372eb6 100644 (file)
@@ -4,13 +4,11 @@
 #ifdef CONFIG_64BIT
 
 #define SECTION_SIZE_BITS      28
-#define MAX_PHYSADDR_BITS      46
 #define MAX_PHYSMEM_BITS       46
 
 #else
 
 #define SECTION_SIZE_BITS      25
-#define MAX_PHYSADDR_BITS      31
 #define MAX_PHYSMEM_BITS       31
 
 #endif /* CONFIG_64BIT */
index fb214dd9b7e0631606072a00a6b3994de4e8a97b..fe7b99759e12ffcdf5f2df9880f86f91df3c9800 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _ASM_SYSCALL_H
 #define _ASM_SYSCALL_H 1
 
+#include <linux/audit.h>
 #include <linux/sched.h>
 #include <linux/err.h>
 #include <asm/ptrace.h>
@@ -87,4 +88,13 @@ static inline void syscall_set_arguments(struct task_struct *task,
                regs->orig_gpr2 = args[0];
 }
 
+static inline int syscall_get_arch(struct task_struct *task,
+                                  struct pt_regs *regs)
+{
+#ifdef CONFIG_COMPAT
+       if (test_tsk_thread_flag(task, TIF_31BIT))
+               return AUDIT_ARCH_S390;
+#endif
+       return sizeof(long) == 8 ? AUDIT_ARCH_S390X : AUDIT_ARCH_S390;
+}
 #endif /* _ASM_SYSCALL_H */
index d1225089a4bbe09519555c4f5336e283394ff03e..f606d935f4950dcbec6fca5f67b88ac70760dcda 100644 (file)
@@ -620,7 +620,6 @@ asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
                return -EFAULT;
        if (a.offset & ~PAGE_MASK)
                return -EINVAL;
-       a.addr = (unsigned long) compat_ptr(a.addr);
        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
                              a.offset >> PAGE_SHIFT);
 }
@@ -631,7 +630,6 @@ asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
 
        if (copy_from_user(&a, arg, sizeof(a)))
                return -EFAULT;
-       a.addr = (unsigned long) compat_ptr(a.addr);
        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 }
 
index e835d6d5b7fdc94ee90e5293087328d638c2f74f..2d82cfcbce5b8cae9127aa115902fa6a2f3b5123 100644 (file)
@@ -1635,7 +1635,7 @@ ENTRY(compat_sys_process_vm_readv_wrapper)
        llgfr   %r6,%r6                 # unsigned long
        llgf    %r0,164(%r15)           # unsigned long
        stg     %r0,160(%r15)
-       jg      sys_process_vm_readv
+       jg      compat_sys_process_vm_readv
 
 ENTRY(compat_sys_process_vm_writev_wrapper)
        lgfr    %r2,%r2                 # compat_pid_t
@@ -1645,4 +1645,4 @@ ENTRY(compat_sys_process_vm_writev_wrapper)
        llgfr   %r6,%r6                 # unsigned long
        llgf    %r0,164(%r15)           # unsigned long
        stg     %r0,160(%r15)
-       jg      sys_process_vm_writev
+       jg      compat_sys_process_vm_writev
index f4eb37680b9152b458938ff37b875754823be695..e4be113fbac62de564bc8566263ae40bd6b4771b 100644 (file)
@@ -719,7 +719,11 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
        long ret = 0;
 
        /* Do the secure computing check first. */
-       secure_computing_strict(regs->gprs[2]);
+       if (secure_computing(regs->gprs[2])) {
+               /* seccomp failures shouldn't expose any additional code. */
+               ret = -1;
+               goto out;
+       }
 
        /*
         * The sysc_tracesys code in entry.S stored the system
@@ -745,6 +749,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                            regs->gprs[2], regs->orig_gpr2,
                            regs->gprs[3], regs->gprs[4],
                            regs->gprs[5]);
+out:
        return ret ?: regs->gprs[2];
 }
 
index b4a29eee41b8d59a7542ce040019a62b0e5f4be8..d0964d22adb5aecb66d94005483e04c7c282b657 100644 (file)
@@ -81,11 +81,12 @@ SYSCALL_DEFINE1(s390_personality, unsigned int, personality)
 {
        unsigned int ret;
 
-       if (current->personality == PER_LINUX32 && personality == PER_LINUX)
-               personality = PER_LINUX32;
+       if (personality(current->personality) == PER_LINUX32 &&
+           personality(personality) == PER_LINUX)
+               personality |= PER_LINUX32;
        ret = sys_personality(personality);
-       if (ret == PER_LINUX32)
-               ret = PER_LINUX;
+       if (personality(ret) == PER_LINUX32)
+               ret &= ~PER_LINUX32;
 
        return ret;
 }
index 4c171f13b0e8792b5f88a564c1fef52e15218c22..b2256562314298e0e63918b7f60323691e08d5b3 100644 (file)
@@ -335,7 +335,7 @@ static int dmae_irq_init(void)
 
        for (n = 0; n < NR_DMAE; n++) {
                int i = request_irq(get_dma_error_irq(n), dma_err,
-                                   IRQF_SHARED, dmae_name[n], NULL);
+                                   IRQF_SHARED, dmae_name[n], (void *)dmae_name[n]);
                if (unlikely(i < 0)) {
                        printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
                        return i;
index 4a5350037c8f59217a06e6e6ea1c429594d51073..1b6199740e98ab7e554f1676d615983f451e56a7 100644 (file)
@@ -6,7 +6,6 @@
 extern long __nosave_begin, __nosave_end;
 extern long __machvec_start, __machvec_end;
 extern char __uncached_start, __uncached_end;
-extern char _ebss[];
 extern char __start_eh_frame[], __stop_eh_frame[];
 
 #endif /* __ASM_SH_SECTIONS_H */
index 48d14498e7740aaf76fcdafa0bae17a3ec7b6ec6..2a0ca8780f0d8c343fb87e434cf6acec73acaddb 100644 (file)
@@ -183,18 +183,30 @@ enum {
        GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
        GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
        GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
-       GPIO_FN_LCD_DATA23, GPIO_FN_LCD_DATA22,
-       GPIO_FN_LCD_DATA21, GPIO_FN_LCD_DATA20,
-       GPIO_FN_LCD_DATA19, GPIO_FN_LCD_DATA18,
-       GPIO_FN_LCD_DATA17, GPIO_FN_LCD_DATA16,
-       GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
-       GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
-       GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
-       GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
-       GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
-       GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
-       GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
-       GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+       GPIO_FN_LCD_DATA23_PG23, GPIO_FN_LCD_DATA22_PG22,
+       GPIO_FN_LCD_DATA21_PG21, GPIO_FN_LCD_DATA20_PG20,
+       GPIO_FN_LCD_DATA19_PG19, GPIO_FN_LCD_DATA18_PG18,
+       GPIO_FN_LCD_DATA17_PG17, GPIO_FN_LCD_DATA16_PG16,
+       GPIO_FN_LCD_DATA15_PG15, GPIO_FN_LCD_DATA14_PG14,
+       GPIO_FN_LCD_DATA13_PG13, GPIO_FN_LCD_DATA12_PG12,
+       GPIO_FN_LCD_DATA11_PG11, GPIO_FN_LCD_DATA10_PG10,
+       GPIO_FN_LCD_DATA9_PG9, GPIO_FN_LCD_DATA8_PG8,
+       GPIO_FN_LCD_DATA7_PG7, GPIO_FN_LCD_DATA6_PG6,
+       GPIO_FN_LCD_DATA5_PG5, GPIO_FN_LCD_DATA4_PG4,
+       GPIO_FN_LCD_DATA3_PG3, GPIO_FN_LCD_DATA2_PG2,
+       GPIO_FN_LCD_DATA1_PG1, GPIO_FN_LCD_DATA0_PG0,
+       GPIO_FN_LCD_DATA23_PJ23, GPIO_FN_LCD_DATA22_PJ22,
+       GPIO_FN_LCD_DATA21_PJ21, GPIO_FN_LCD_DATA20_PJ20,
+       GPIO_FN_LCD_DATA19_PJ19, GPIO_FN_LCD_DATA18_PJ18,
+       GPIO_FN_LCD_DATA17_PJ17, GPIO_FN_LCD_DATA16_PJ16,
+       GPIO_FN_LCD_DATA15_PJ15, GPIO_FN_LCD_DATA14_PJ14,
+       GPIO_FN_LCD_DATA13_PJ13, GPIO_FN_LCD_DATA12_PJ12,
+       GPIO_FN_LCD_DATA11_PJ11, GPIO_FN_LCD_DATA10_PJ10,
+       GPIO_FN_LCD_DATA9_PJ9, GPIO_FN_LCD_DATA8_PJ8,
+       GPIO_FN_LCD_DATA7_PJ7, GPIO_FN_LCD_DATA6_PJ6,
+       GPIO_FN_LCD_DATA5_PJ5, GPIO_FN_LCD_DATA4_PJ4,
+       GPIO_FN_LCD_DATA3_PJ3, GPIO_FN_LCD_DATA2_PJ2,
+       GPIO_FN_LCD_DATA1_PJ1, GPIO_FN_LCD_DATA0_PJ0,
        GPIO_FN_LCD_M_DISP,
 };
 
index f25127c46ecaff2df0e7bb7b38eca237903c7838..039e4587dd9b8cf2959e2d19159098f02136f7fd 100644 (file)
@@ -758,12 +758,22 @@ enum {
        DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
        LCD_CLK_MARK, LCD_EXTCLK_MARK,
        LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
-       LCD_DATA23_MARK, LCD_DATA22_MARK, LCD_DATA21_MARK, LCD_DATA20_MARK,
-       LCD_DATA19_MARK, LCD_DATA18_MARK, LCD_DATA17_MARK, LCD_DATA16_MARK,
-       LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
-       LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
-       LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
-       LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+       LCD_DATA23_PG23_MARK, LCD_DATA22_PG22_MARK, LCD_DATA21_PG21_MARK,
+       LCD_DATA20_PG20_MARK, LCD_DATA19_PG19_MARK, LCD_DATA18_PG18_MARK,
+       LCD_DATA17_PG17_MARK, LCD_DATA16_PG16_MARK, LCD_DATA15_PG15_MARK,
+       LCD_DATA14_PG14_MARK, LCD_DATA13_PG13_MARK, LCD_DATA12_PG12_MARK,
+       LCD_DATA11_PG11_MARK, LCD_DATA10_PG10_MARK, LCD_DATA9_PG9_MARK,
+       LCD_DATA8_PG8_MARK, LCD_DATA7_PG7_MARK, LCD_DATA6_PG6_MARK,
+       LCD_DATA5_PG5_MARK, LCD_DATA4_PG4_MARK, LCD_DATA3_PG3_MARK,
+       LCD_DATA2_PG2_MARK, LCD_DATA1_PG1_MARK, LCD_DATA0_PG0_MARK,
+       LCD_DATA23_PJ23_MARK, LCD_DATA22_PJ22_MARK, LCD_DATA21_PJ21_MARK,
+       LCD_DATA20_PJ20_MARK, LCD_DATA19_PJ19_MARK, LCD_DATA18_PJ18_MARK,
+       LCD_DATA17_PJ17_MARK, LCD_DATA16_PJ16_MARK, LCD_DATA15_PJ15_MARK,
+       LCD_DATA14_PJ14_MARK, LCD_DATA13_PJ13_MARK, LCD_DATA12_PJ12_MARK,
+       LCD_DATA11_PJ11_MARK, LCD_DATA10_PJ10_MARK, LCD_DATA9_PJ9_MARK,
+       LCD_DATA8_PJ8_MARK, LCD_DATA7_PJ7_MARK, LCD_DATA6_PJ6_MARK,
+       LCD_DATA5_PJ5_MARK, LCD_DATA4_PJ4_MARK, LCD_DATA3_PJ3_MARK,
+       LCD_DATA2_PJ2_MARK, LCD_DATA1_PJ1_MARK, LCD_DATA0_PJ0_MARK,
        LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
        LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
        LCD_M_DISP_MARK,
@@ -1036,6 +1046,7 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PF1_DATA, PF1MD_000),
        PINMUX_DATA(BACK_MARK, PF1MD_001),
+       PINMUX_DATA(SSL10_MARK, PF1MD_011),
        PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
        PINMUX_DATA(DACK0_MARK, PF1MD_101),
 
@@ -1049,47 +1060,50 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PG27_DATA, PG27MD_00),
        PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
        PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
+       PINMUX_DATA(LCD_DE_MARK, PG27MD_11),
 
        PINMUX_DATA(PG26_DATA, PG26MD_00),
        PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
+       PINMUX_DATA(LCD_HSYNC_MARK, PG26MD_10),
 
        PINMUX_DATA(PG25_DATA, PG25MD_00),
        PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
+       PINMUX_DATA(LCD_VSYNC_MARK, PG25MD_10),
 
        PINMUX_DATA(PG24_DATA, PG24MD_00),
        PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
 
        PINMUX_DATA(PG23_DATA, PG23MD_000),
-       PINMUX_DATA(LCD_DATA23_MARK, PG23MD_010),
+       PINMUX_DATA(LCD_DATA23_PG23_MARK, PG23MD_010),
        PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
        PINMUX_DATA(TXD5_MARK, PG23MD_100),
 
        PINMUX_DATA(PG22_DATA, PG22MD_000),
-       PINMUX_DATA(LCD_DATA22_MARK, PG22MD_010),
+       PINMUX_DATA(LCD_DATA22_PG22_MARK, PG22MD_010),
        PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
        PINMUX_DATA(RXD5_MARK, PG22MD_100),
 
        PINMUX_DATA(PG21_DATA, PG21MD_000),
        PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
-       PINMUX_DATA(LCD_DATA21_MARK, PG21MD_010),
+       PINMUX_DATA(LCD_DATA21_PG21_MARK, PG21MD_010),
        PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
        PINMUX_DATA(TXD4_MARK, PG21MD_100),
 
        PINMUX_DATA(PG20_DATA, PG20MD_000),
        PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
-       PINMUX_DATA(LCD_DATA20_MARK, PG21MD_010),
+       PINMUX_DATA(LCD_DATA20_PG20_MARK, PG21MD_010),
        PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
        PINMUX_DATA(RXD4_MARK, PG20MD_100),
 
        PINMUX_DATA(PG19_DATA, PG19MD_000),
        PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
-       PINMUX_DATA(LCD_DATA19_MARK, PG19MD_010),
+       PINMUX_DATA(LCD_DATA19_PG19_MARK, PG19MD_010),
        PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
        PINMUX_DATA(SCK5_MARK, PG19MD_100),
 
        PINMUX_DATA(PG18_DATA, PG18MD_000),
        PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
-       PINMUX_DATA(LCD_DATA18_MARK, PG18MD_010),
+       PINMUX_DATA(LCD_DATA18_PG18_MARK, PG18MD_010),
        PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
        PINMUX_DATA(SCK4_MARK, PG18MD_100),
 
@@ -1097,103 +1111,103 @@ static pinmux_enum_t pinmux_data[] = {
 // we're going with 2 bits
        PINMUX_DATA(PG17_DATA, PG17MD_00),
        PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
-       PINMUX_DATA(LCD_DATA17_MARK, PG17MD_10),
+       PINMUX_DATA(LCD_DATA17_PG17_MARK, PG17MD_10),
 
 // TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
 // we're going with 2 bits
        PINMUX_DATA(PG16_DATA, PG16MD_00),
        PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
-       PINMUX_DATA(LCD_DATA16_MARK, PG16MD_10),
+       PINMUX_DATA(LCD_DATA16_PG16_MARK, PG16MD_10),
 
        PINMUX_DATA(PG15_DATA, PG15MD_00),
        PINMUX_DATA(D31_MARK, PG15MD_01),
-       PINMUX_DATA(LCD_DATA15_MARK, PG15MD_10),
+       PINMUX_DATA(LCD_DATA15_PG15_MARK, PG15MD_10),
        PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
 
        PINMUX_DATA(PG14_DATA, PG14MD_00),
        PINMUX_DATA(D30_MARK, PG14MD_01),
-       PINMUX_DATA(LCD_DATA14_MARK, PG14MD_10),
+       PINMUX_DATA(LCD_DATA14_PG14_MARK, PG14MD_10),
        PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
 
        PINMUX_DATA(PG13_DATA, PG13MD_00),
        PINMUX_DATA(D29_MARK, PG13MD_01),
-       PINMUX_DATA(LCD_DATA13_MARK, PG13MD_10),
+       PINMUX_DATA(LCD_DATA13_PG13_MARK, PG13MD_10),
        PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
 
        PINMUX_DATA(PG12_DATA, PG12MD_00),
        PINMUX_DATA(D28_MARK, PG12MD_01),
-       PINMUX_DATA(LCD_DATA12_MARK, PG12MD_10),
+       PINMUX_DATA(LCD_DATA12_PG12_MARK, PG12MD_10),
        PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
 
        PINMUX_DATA(PG11_DATA, PG11MD_000),
        PINMUX_DATA(D27_MARK, PG11MD_001),
-       PINMUX_DATA(LCD_DATA11_MARK, PG11MD_010),
+       PINMUX_DATA(LCD_DATA11_PG11_MARK, PG11MD_010),
        PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
        PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
 
        PINMUX_DATA(PG10_DATA, PG10MD_000),
        PINMUX_DATA(D26_MARK, PG10MD_001),
-       PINMUX_DATA(LCD_DATA10_MARK, PG10MD_010),
+       PINMUX_DATA(LCD_DATA10_PG10_MARK, PG10MD_010),
        PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
        PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
 
        PINMUX_DATA(PG9_DATA, PG9MD_000),
        PINMUX_DATA(D25_MARK, PG9MD_001),
-       PINMUX_DATA(LCD_DATA9_MARK, PG9MD_010),
+       PINMUX_DATA(LCD_DATA9_PG9_MARK, PG9MD_010),
        PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
        PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
 
        PINMUX_DATA(PG8_DATA, PG8MD_000),
        PINMUX_DATA(D24_MARK, PG8MD_001),
-       PINMUX_DATA(LCD_DATA8_MARK, PG8MD_010),
+       PINMUX_DATA(LCD_DATA8_PG8_MARK, PG8MD_010),
        PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
        PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
 
        PINMUX_DATA(PG7_DATA, PG7MD_000),
        PINMUX_DATA(D23_MARK, PG7MD_001),
-       PINMUX_DATA(LCD_DATA7_MARK, PG7MD_010),
+       PINMUX_DATA(LCD_DATA7_PG7_MARK, PG7MD_010),
        PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
        PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
 
        PINMUX_DATA(PG6_DATA, PG6MD_000),
        PINMUX_DATA(D22_MARK, PG6MD_001),
-       PINMUX_DATA(LCD_DATA6_MARK, PG6MD_010),
+       PINMUX_DATA(LCD_DATA6_PG6_MARK, PG6MD_010),
        PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
        PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
 
        PINMUX_DATA(PG5_DATA, PG5MD_000),
        PINMUX_DATA(D21_MARK, PG5MD_001),
-       PINMUX_DATA(LCD_DATA5_MARK, PG5MD_010),
+       PINMUX_DATA(LCD_DATA5_PG5_MARK, PG5MD_010),
        PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
        PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
 
        PINMUX_DATA(PG4_DATA, PG4MD_000),
        PINMUX_DATA(D20_MARK, PG4MD_001),
-       PINMUX_DATA(LCD_DATA4_MARK, PG4MD_010),
+       PINMUX_DATA(LCD_DATA4_PG4_MARK, PG4MD_010),
        PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
        PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
 
        PINMUX_DATA(PG3_DATA, PG3MD_000),
        PINMUX_DATA(D19_MARK, PG3MD_001),
-       PINMUX_DATA(LCD_DATA3_MARK, PG3MD_010),
+       PINMUX_DATA(LCD_DATA3_PG3_MARK, PG3MD_010),
        PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
        PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
 
        PINMUX_DATA(PG2_DATA, PG2MD_000),
        PINMUX_DATA(D18_MARK, PG2MD_001),
-       PINMUX_DATA(LCD_DATA2_MARK, PG2MD_010),
+       PINMUX_DATA(LCD_DATA2_PG2_MARK, PG2MD_010),
        PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
        PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
 
        PINMUX_DATA(PG1_DATA, PG1MD_000),
        PINMUX_DATA(D17_MARK, PG1MD_001),
-       PINMUX_DATA(LCD_DATA1_MARK, PG1MD_010),
+       PINMUX_DATA(LCD_DATA1_PG1_MARK, PG1MD_010),
        PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
        PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
 
        PINMUX_DATA(PG0_DATA, PG0MD_000),
        PINMUX_DATA(D16_MARK, PG0MD_001),
-       PINMUX_DATA(LCD_DATA0_MARK, PG0MD_010),
+       PINMUX_DATA(LCD_DATA0_PG0_MARK, PG0MD_010),
        PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
        PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
 
@@ -1275,14 +1289,14 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ23_DATA, PJ23MD_000),
        PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
-       PINMUX_DATA(LCD_DATA23_MARK, PJ23MD_010),
+       PINMUX_DATA(LCD_DATA23_PJ23_MARK, PJ23MD_010),
        PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
        PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
        PINMUX_DATA(CTX1_MARK, PJ23MD_101),
 
        PINMUX_DATA(PJ22_DATA, PJ22MD_000),
        PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
-       PINMUX_DATA(LCD_DATA22_MARK, PJ22MD_010),
+       PINMUX_DATA(LCD_DATA22_PJ22_MARK, PJ22MD_010),
        PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
        PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
        PINMUX_DATA(CRX1_MARK, PJ22MD_101),
@@ -1290,14 +1304,14 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ21_DATA, PJ21MD_000),
        PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
-       PINMUX_DATA(LCD_DATA21_MARK, PJ21MD_010),
+       PINMUX_DATA(LCD_DATA21_PJ21_MARK, PJ21MD_010),
        PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
        PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
        PINMUX_DATA(CTX2_MARK, PJ21MD_101),
 
        PINMUX_DATA(PJ20_DATA, PJ20MD_000),
        PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
-       PINMUX_DATA(LCD_DATA20_MARK, PJ20MD_010),
+       PINMUX_DATA(LCD_DATA20_PJ20_MARK, PJ20MD_010),
        PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
        PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
        PINMUX_DATA(CRX2_MARK, PJ20MD_101),
@@ -1305,7 +1319,7 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ19_DATA, PJ19MD_000),
        PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
-       PINMUX_DATA(LCD_DATA19_MARK, PJ19MD_010),
+       PINMUX_DATA(LCD_DATA19_PJ19_MARK, PJ19MD_010),
        PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
        PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
        PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
@@ -1313,126 +1327,126 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ18_DATA, PJ18MD_000),
        PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
-       PINMUX_DATA(LCD_DATA18_MARK, PJ18MD_010),
+       PINMUX_DATA(LCD_DATA18_PJ18_MARK, PJ18MD_010),
        PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
        PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
        PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
 
        PINMUX_DATA(PJ17_DATA, PJ17MD_000),
        PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
-       PINMUX_DATA(LCD_DATA17_MARK, PJ17MD_010),
+       PINMUX_DATA(LCD_DATA17_PJ17_MARK, PJ17MD_010),
        PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
        PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
        PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
 
        PINMUX_DATA(PJ16_DATA, PJ16MD_000),
        PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
-       PINMUX_DATA(LCD_DATA16_MARK, PJ16MD_010),
+       PINMUX_DATA(LCD_DATA16_PJ16_MARK, PJ16MD_010),
        PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
        PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
        PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
 
        PINMUX_DATA(PJ15_DATA, PJ15MD_000),
        PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
-       PINMUX_DATA(LCD_DATA15_MARK, PJ15MD_010),
+       PINMUX_DATA(LCD_DATA15_PJ15_MARK, PJ15MD_010),
        PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
        PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
        PINMUX_DATA(TXD7_MARK, PJ15MD_101),
 
        PINMUX_DATA(PJ14_DATA, PJ14MD_000),
        PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
-       PINMUX_DATA(LCD_DATA14_MARK, PJ14MD_010),
+       PINMUX_DATA(LCD_DATA14_PJ14_MARK, PJ14MD_010),
        PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
        PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
        PINMUX_DATA(TXD6_MARK, PJ14MD_101),
 
        PINMUX_DATA(PJ13_DATA, PJ13MD_000),
        PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
-       PINMUX_DATA(LCD_DATA13_MARK, PJ13MD_010),
+       PINMUX_DATA(LCD_DATA13_PJ13_MARK, PJ13MD_010),
        PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
        PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
        PINMUX_DATA(TXD5_MARK, PJ13MD_101),
 
        PINMUX_DATA(PJ12_DATA, PJ12MD_000),
        PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
-       PINMUX_DATA(LCD_DATA12_MARK, PJ12MD_010),
+       PINMUX_DATA(LCD_DATA12_PJ12_MARK, PJ12MD_010),
        PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
        PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
        PINMUX_DATA(SCK7_MARK, PJ12MD_101),
 
        PINMUX_DATA(PJ11_DATA, PJ11MD_000),
        PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
-       PINMUX_DATA(LCD_DATA11_MARK, PJ11MD_010),
+       PINMUX_DATA(LCD_DATA11_PJ11_MARK, PJ11MD_010),
        PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
        PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
        PINMUX_DATA(SCK6_MARK, PJ11MD_101),
 
        PINMUX_DATA(PJ10_DATA, PJ10MD_000),
        PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
-       PINMUX_DATA(LCD_DATA10_MARK, PJ10MD_010),
+       PINMUX_DATA(LCD_DATA10_PJ10_MARK, PJ10MD_010),
        PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
        PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
        PINMUX_DATA(SCK5_MARK, PJ10MD_101),
 
        PINMUX_DATA(PJ9_DATA, PJ9MD_000),
        PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
-       PINMUX_DATA(LCD_DATA9_MARK, PJ9MD_010),
+       PINMUX_DATA(LCD_DATA9_PJ9_MARK, PJ9MD_010),
        PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
        PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
        PINMUX_DATA(RTS5_MARK, PJ9MD_101),
 
        PINMUX_DATA(PJ8_DATA, PJ8MD_000),
        PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
-       PINMUX_DATA(LCD_DATA8_MARK, PJ8MD_010),
+       PINMUX_DATA(LCD_DATA8_PJ8_MARK, PJ8MD_010),
        PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
        PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
        PINMUX_DATA(CTS5_MARK, PJ8MD_101),
 
        PINMUX_DATA(PJ7_DATA, PJ7MD_000),
        PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
-       PINMUX_DATA(LCD_DATA7_MARK, PJ7MD_010),
+       PINMUX_DATA(LCD_DATA7_PJ7_MARK, PJ7MD_010),
        PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
        PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
 
        PINMUX_DATA(PJ6_DATA, PJ6MD_000),
        PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
-       PINMUX_DATA(LCD_DATA6_MARK, PJ6MD_010),
+       PINMUX_DATA(LCD_DATA6_PJ6_MARK, PJ6MD_010),
        PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
        PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
 
        PINMUX_DATA(PJ5_DATA, PJ5MD_000),
        PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
-       PINMUX_DATA(LCD_DATA5_MARK, PJ5MD_010),
+       PINMUX_DATA(LCD_DATA5_PJ5_MARK, PJ5MD_010),
        PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
        PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
 
        PINMUX_DATA(PJ4_DATA, PJ4MD_000),
        PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
-       PINMUX_DATA(LCD_DATA4_MARK, PJ4MD_010),
+       PINMUX_DATA(LCD_DATA4_PJ4_MARK, PJ4MD_010),
        PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
        PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
 
        PINMUX_DATA(PJ3_DATA, PJ3MD_000),
        PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
-       PINMUX_DATA(LCD_DATA3_MARK, PJ3MD_010),
+       PINMUX_DATA(LCD_DATA3_PJ3_MARK, PJ3MD_010),
        PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
        PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
 
        PINMUX_DATA(PJ2_DATA, PJ2MD_000),
        PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
-       PINMUX_DATA(LCD_DATA2_MARK, PJ2MD_010),
+       PINMUX_DATA(LCD_DATA2_PJ2_MARK, PJ2MD_010),
        PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
        PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
 
        PINMUX_DATA(PJ1_DATA, PJ1MD_000),
        PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
-       PINMUX_DATA(LCD_DATA1_MARK, PJ1MD_010),
+       PINMUX_DATA(LCD_DATA1_PJ1_MARK, PJ1MD_010),
        PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
        PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
 
        PINMUX_DATA(PJ0_DATA, PJ0MD_000),
        PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
-       PINMUX_DATA(LCD_DATA0_MARK, PJ0MD_010),
+       PINMUX_DATA(LCD_DATA0_PJ0_MARK, PJ0MD_010),
        PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
        PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
 };
@@ -1877,30 +1891,55 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
        PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
 
-       PINMUX_GPIO(GPIO_FN_LCD_DATA23, LCD_DATA23_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA22, LCD_DATA22_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA21, LCD_DATA21_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA20, LCD_DATA20_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA19, LCD_DATA19_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA18, LCD_DATA18_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA17, LCD_DATA17_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA16, LCD_DATA16_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA23_PG23, LCD_DATA23_PG23_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA22_PG22, LCD_DATA22_PG22_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA21_PG21, LCD_DATA21_PG21_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA20_PG20, LCD_DATA20_PG20_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA19_PG19, LCD_DATA19_PG19_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA18_PG18, LCD_DATA18_PG18_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA17_PG17, LCD_DATA17_PG17_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA16_PG16, LCD_DATA16_PG16_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA15_PG15, LCD_DATA15_PG15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA14_PG14, LCD_DATA14_PG14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA13_PG13, LCD_DATA13_PG13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA12_PG12, LCD_DATA12_PG12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA11_PG11, LCD_DATA11_PG11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA10_PG10, LCD_DATA10_PG10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA9_PG9, LCD_DATA9_PG9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA8_PG8, LCD_DATA8_PG8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA7_PG7, LCD_DATA7_PG7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA6_PG6, LCD_DATA6_PG6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA5_PG5, LCD_DATA5_PG5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA4_PG4, LCD_DATA4_PG4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA3_PG3, LCD_DATA3_PG3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA2_PG2, LCD_DATA2_PG2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA1_PG1, LCD_DATA1_PG1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA0_PG0, LCD_DATA0_PG0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_DATA23_PJ23, LCD_DATA23_PJ23_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA22_PJ22, LCD_DATA22_PJ22_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA21_PJ21, LCD_DATA21_PJ21_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA20_PJ20, LCD_DATA20_PJ20_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA19_PJ19, LCD_DATA19_PJ19_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA18_PJ18, LCD_DATA18_PJ18_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA17_PJ17, LCD_DATA17_PJ17_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA16_PJ16, LCD_DATA16_PJ16_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA15_PJ15, LCD_DATA15_PJ15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA14_PJ14, LCD_DATA14_PJ14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA13_PJ13, LCD_DATA13_PJ13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA12_PJ12, LCD_DATA12_PJ12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA11_PJ11, LCD_DATA11_PJ11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA10_PJ10, LCD_DATA10_PJ10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA9_PJ9, LCD_DATA9_PJ9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA8_PJ8, LCD_DATA8_PJ8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA7_PJ7, LCD_DATA7_PJ7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA6_PJ6, LCD_DATA6_PJ6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA5_PJ5, LCD_DATA5_PJ5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA4_PJ4, LCD_DATA4_PJ4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA3_PJ3, LCD_DATA3_PJ3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA2_PJ2, LCD_DATA2_PJ2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA1_PJ1, LCD_DATA1_PJ1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA0_PJ0, LCD_DATA0_PJ0_MARK),
 
        PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
 };
index 7b57bf1dc85510c08b40a9f88892ffacbf78c379..ebe7a7d97215e4978252af8a3512821e64148064 100644 (file)
@@ -273,7 +273,7 @@ void __init setup_arch(char **cmdline_p)
        data_resource.start = virt_to_phys(_etext);
        data_resource.end = virt_to_phys(_edata)-1;
        bss_resource.start = virt_to_phys(__bss_start);
-       bss_resource.end = virt_to_phys(_ebss)-1;
+       bss_resource.end = virt_to_phys(__bss_stop)-1;
 
 #ifdef CONFIG_CMDLINE_OVERWRITE
        strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line));
index 3896f26efa4a5c9466943dbe10bcfd87028c0011..2a0a596ebf67d948663df3009d1ca14c8b09dabc 100644 (file)
@@ -19,7 +19,6 @@ EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(_ebss);
 EXPORT_SYMBOL(empty_zero_page);
 
 #define DECLARE_EXPORT(name)           \
index c98905f71e28ce78a1ab06e7b310653efa2156a9..db88cbf9eafdc815d76d72784c18e4df42b361e5 100644 (file)
@@ -78,7 +78,6 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        BSS_SECTION(0, PAGE_SIZE, 4)
-       _ebss = .;                      /* uClinux MTD sucks */
        _end = . ;
 
        STABS_DEBUG
index 84a57761f17e90ee8cfdfd71dfce2b02480002a4..60164e65d66551c4375121e984fd0ea28a9525fa 100644 (file)
@@ -39,7 +39,7 @@
  *
  * Make sure the stack pointer contains a valid address. Valid
  * addresses for kernel stacks are anywhere after the bss
- * (after _ebss) and anywhere in init_thread_union (init_stack).
+ * (after __bss_stop) and anywhere in init_thread_union (init_stack).
  */
 #define STACK_CHECK()                                  \
        mov     #(THREAD_SIZE >> 10), r0;               \
@@ -60,7 +60,7 @@
        cmp/hi  r2, r1;                                 \
        bf      stack_panic;                            \
                                                        \
-       /* If sp > _ebss then we're OK. */              \
+       /* If sp > __bss_stop then we're OK. */         \
        mov.l   .L_ebss, r1;                            \
        cmp/hi  r1, r15;                                \
        bt      1f;                                     \
@@ -70,7 +70,7 @@
        cmp/hs  r1, r15;                                \
        bf      stack_panic;                            \
                                                        \
-       /* If sp > init_stack && sp < _ebss, not OK. */ \
+       /* If sp > init_stack && sp < __bss_stop, not OK. */    \
        add     r0, r1;                                 \
        cmp/hs  r1, r15;                                \
        bt      stack_panic;                            \
@@ -292,8 +292,6 @@ stack_panic:
         nop
 
        .align 2
-.L_ebss:
-       .long   _ebss
 .L_init_thread_union:
        .long   init_thread_union
 .Lpanic:
index 0dc1f578608131002da0b869dcfa7c56b4b149e3..11c6c9603e71f03995a3c17fcdf2f28957d7fa43 100644 (file)
@@ -502,12 +502,12 @@ SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality)
 {
        int ret;
 
-       if (current->personality == PER_LINUX32 &&
-           personality == PER_LINUX)
-               personality = PER_LINUX32;
+       if (personality(current->personality) == PER_LINUX32 &&
+           personality(personality) == PER_LINUX)
+               personality |= PER_LINUX32;
        ret = sys_personality(personality);
-       if (ret == PER_LINUX32)
-               ret = PER_LINUX;
+       if (personality(ret) == PER_LINUX32)
+               ret &= ~PER_LINUX32;
 
        return ret;
 }
index 6026fdd1b2eddedbf9dcff60e1079c176eb0d3d6..d58edf5fefdb6a4a3fdf484f46588cc411727c38 100644 (file)
@@ -2020,6 +2020,9 @@ EXPORT_SYMBOL(_PAGE_CACHE);
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 unsigned long vmemmap_table[VMEMMAP_SIZE];
 
+static long __meminitdata addr_start, addr_end;
+static int __meminitdata node_start;
+
 int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
 {
        unsigned long vstart = (unsigned long) start;
@@ -2050,15 +2053,30 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
 
                        *vmem_pp = pte_base | __pa(block);
 
-                       printk(KERN_INFO "[%p-%p] page_structs=%lu "
-                              "node=%d entry=%lu/%lu\n", start, block, nr,
-                              node,
-                              addr >> VMEMMAP_CHUNK_SHIFT,
-                              VMEMMAP_SIZE);
+                       /* check to see if we have contiguous blocks */
+                       if (addr_end != addr || node_start != node) {
+                               if (addr_start)
+                                       printk(KERN_DEBUG " [%lx-%lx] on node %d\n",
+                                              addr_start, addr_end-1, node_start);
+                               addr_start = addr;
+                               node_start = node;
+                       }
+                       addr_end = addr + VMEMMAP_CHUNK;
                }
        }
        return 0;
 }
+
+void __meminit vmemmap_populate_print_last(void)
+{
+       if (addr_start) {
+               printk(KERN_DEBUG " [%lx-%lx] on node %d\n",
+                      addr_start, addr_end-1, node_start);
+               addr_start = 0;
+               addr_end = 0;
+               node_start = 0;
+       }
+}
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
 static void prot_init_common(unsigned long page_none,
index ba2657c492171c5ce5c295d1e1d4ef85391608d8..8ec3a1aa4abd3f612df4a5da31f30c67554d5182 100644 (file)
@@ -1527,7 +1527,7 @@ config SECCOMP
          If unsure, say Y. Only embedded should say N here.
 
 config CC_STACKPROTECTOR
-       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+       bool "Enable -fstack-protector buffer overflow detection"
        ---help---
          This option turns on the -fstack-protector GCC feature. This
          feature puts, at the beginning of functions, a canary value on
index b0c5276861ec8cc3b5713b6f83335746f812edde..682e9c210baacb99b86817adbd45ebbd17a30955 100644 (file)
@@ -27,6 +27,10 @@ ifeq ($(CONFIG_X86_32),y)
 
         KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return
 
+        # Never want PIC in a 32-bit kernel, prevent breakage with GCC built
+        # with nonstandard options
+        KBUILD_CFLAGS += -fno-pic
+
         # prevent gcc from keeping the stack 16 byte aligned
         KBUILD_CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
 
index 5a747dd884dbf1097916f46aaf195eb93ebe7b6c..f7535bedc33f3b73ee6c0d0b276435ae4b9fb8be 100644 (file)
@@ -57,7 +57,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
                   -Wall -Wstrict-prototypes \
                   -march=i386 -mregparm=3 \
                   -include $(srctree)/$(src)/code16gcc.h \
-                  -fno-strict-aliasing -fomit-frame-pointer \
+                  -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
                   $(call cc-option, -ffreestanding) \
                   $(call cc-option, -fno-toplevel-reorder,\
                        $(call cc-option, -fno-unit-at-a-time)) \
index 441520e4174f9f08736af4368f0c74e1f1ec5b0b..a3ac52b29cbfc5abd3c178fcfbfe7d7586d6e7f2 100644 (file)
 #define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
 #define MCI_STATUS_S    (1ULL<<56)  /* Signaled machine check */
 #define MCI_STATUS_AR   (1ULL<<55)  /* Action required */
+#define MCACOD           0xffff     /* MCA Error Code */
+
+/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
+#define MCACOD_SCRUB   0x00C0  /* 0xC0-0xCF Memory Scrubbing */
+#define MCACOD_SCRUBMSK        0xfff0
+#define MCACOD_L3WB    0x017A  /* L3 Explicit Writeback */
+#define MCACOD_DATA    0x0134  /* Data Load */
+#define MCACOD_INSTR   0x0150  /* Instruction Fetch */
 
 /* MCi_MISC register defines */
 #define MCI_MISC_ADDR_LSB(m)   ((m) & 0x3f)
index dab39350e51e446917d5b5e302fe1ac2214b10d0..cb4e43bce98ab46e262f3b235765e5ebd6270ddd 100644 (file)
@@ -196,11 +196,16 @@ static inline u32 get_ibs_caps(void) { return 0; }
 extern void perf_events_lapic_init(void);
 
 /*
- * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups.
- * This flag is otherwise unused and ABI specified to be 0, so nobody should
- * care what we do with it.
+ * Abuse bits {3,5} of the cpu eflags register. These flags are otherwise
+ * unused and ABI specified to be 0, so nobody should care what we do with
+ * them.
+ *
+ * EXACT - the IP points to the exact instruction that triggered the
+ *         event (HW bugs exempt).
+ * VM    - original X86_VM_MASK; see set_linear_ip().
  */
 #define PERF_EFLAGS_EXACT      (1UL << 3)
+#define PERF_EFLAGS_VM         (1UL << 5)
 
 struct pt_regs;
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
index 95bf99de9058128f320356caa6cad1ce9b2727da..1b8e5a03d942439c4b58a7470f181dcb99b29e85 100644 (file)
@@ -25,10 +25,6 @@ unsigned long acpi_realmode_flags;
 static char temp_stack[4096];
 #endif
 
-asmlinkage void acpi_enter_s3(void)
-{
-       acpi_enter_sleep_state(3, wake_sleep_flags);
-}
 /**
  * acpi_suspend_lowlevel - save kernel state
  *
index 5653a5791ec92291844a55665cc50a0cb402095b..67f59f8c695651977e45d88e15bc66781777f31c 100644 (file)
@@ -2,7 +2,6 @@
  *     Variables and functions used by the code in sleep.c
  */
 
-#include <linux/linkage.h>
 #include <asm/realmode.h>
 
 extern unsigned long saved_video_mode;
@@ -11,7 +10,6 @@ extern long saved_magic;
 extern int wakeup_pmode_return;
 
 extern u8 wake_sleep_flags;
-extern asmlinkage void acpi_enter_s3(void);
 
 extern unsigned long acpi_copy_wakeup_routine(unsigned long);
 extern void wakeup_long64(void);
index 72610839f03b3d45e8fa6adb49a13fe933b477b2..13ab720573e3e31e317ac52f977e168401552f17 100644 (file)
@@ -74,7 +74,9 @@ restore_registers:
 ENTRY(do_suspend_lowlevel)
        call    save_processor_state
        call    save_registers
-       call    acpi_enter_s3
+       pushl   $3
+       call    acpi_enter_sleep_state
+       addl    $4, %esp
 
 #      In case of S3 failure, we'll emerge here.  Jump
 #      to ret_point to recover
index 014d1d28c397076606be9d50f04af06892bf2f03..8ea5164cbd0451a27b9048699f60c2420057edb3 100644 (file)
@@ -71,7 +71,9 @@ ENTRY(do_suspend_lowlevel)
        movq    %rsi, saved_rsi
 
        addq    $8, %rsp
-       call    acpi_enter_s3
+       movl    $3, %edi
+       xorl    %eax, %eax
+       call    acpi_enter_sleep_state
        /* in case something went wrong, restore the machine status and go on */
        jmp     resume_point
 
index 931280ff8299471df09b60033cdb06b46a361677..afb7ff79a29fbb33c6578c9240c7e5b550417b88 100644 (file)
@@ -224,7 +224,7 @@ void __init arch_init_ideal_nops(void)
                        ideal_nops = intel_nops;
 #endif
                }
-
+               break;
        default:
 #ifdef CONFIG_X86_64
                ideal_nops = k8_nops;
index 406eee7846849990d8f87d53243e6cd171944e17..c265593ec2cdc3df35fda1586aaf91514fab62fa 100644 (file)
@@ -1204,7 +1204,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
        BUG_ON(!cfg->vector);
 
        vector = cfg->vector;
-       for_each_cpu(cpu, cfg->domain)
+       for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
                per_cpu(vector_irq, cpu)[vector] = -1;
 
        cfg->vector = 0;
@@ -1212,7 +1212,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
 
        if (likely(!cfg->move_in_progress))
                return;
-       for_each_cpu(cpu, cfg->old_domain) {
+       for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
                for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
                                                                vector++) {
                        if (per_cpu(vector_irq, cpu)[vector] != irq)
@@ -1356,6 +1356,16 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
        if (!IO_APIC_IRQ(irq))
                return;
 
+       /*
+        * For legacy irqs, cfg->domain starts with cpu 0. Now that IO-APIC
+        * can handle this irq and the apic driver is finialized at this point,
+        * update the cfg->domain.
+        */
+       if (irq < legacy_pic->nr_legacy_irqs &&
+           cpumask_equal(cfg->domain, cpumask_of(0)))
+               apic->vector_allocation_domain(0, cfg->domain,
+                                              apic->target_cpus());
+
        if (assign_irq_vector(irq, cfg, apic->target_cpus()))
                return;
 
index 46d8786d655e402b702cc2f19ba4eab9cb5a62cd..a5fbc3c5fccc5e60d61d9ec8f1d3f9f60a2a0467 100644 (file)
@@ -144,6 +144,8 @@ static int __init x86_xsave_setup(char *s)
 {
        setup_clear_cpu_cap(X86_FEATURE_XSAVE);
        setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+       setup_clear_cpu_cap(X86_FEATURE_AVX);
+       setup_clear_cpu_cap(X86_FEATURE_AVX2);
        return 1;
 }
 __setup("noxsave", x86_xsave_setup);
index 413c2ced887c66c89b1f49fb18a3bac29604ccb2..13017626f9a85c0948fe99cafa1102c0c9d010da 100644 (file)
@@ -55,13 +55,6 @@ static struct severity {
 #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
 #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
 #define        MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV)
-#define MCACOD 0xffff
-/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
-#define MCACOD_SCRUB   0x00C0  /* 0xC0-0xCF Memory Scrubbing */
-#define MCACOD_SCRUBMSK        0xfff0
-#define MCACOD_L3WB    0x017A  /* L3 Explicit Writeback */
-#define MCACOD_DATA    0x0134  /* Data Load */
-#define MCACOD_INSTR   0x0150  /* Instruction Fetch */
 
        MCESEV(
                NO, "Invalid",
index 5e095f873e3eb731a42012c5e10310fc238ed9c7..292d0258311c82d04c5ec0aeab43924d00c669b4 100644 (file)
@@ -103,6 +103,8 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
 
 static DEFINE_PER_CPU(struct work_struct, mce_work);
 
+static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
+
 /*
  * CPU/chipset specific EDAC code can register a notifier call here to print
  * MCE errors in a human-readable form.
@@ -650,14 +652,18 @@ EXPORT_SYMBOL_GPL(machine_check_poll);
  * Do a quick check if any of the events requires a panic.
  * This decides if we keep the events around or clear them.
  */
-static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp)
+static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
+                         struct pt_regs *regs)
 {
        int i, ret = 0;
 
        for (i = 0; i < banks; i++) {
                m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i));
-               if (m->status & MCI_STATUS_VAL)
+               if (m->status & MCI_STATUS_VAL) {
                        __set_bit(i, validp);
+                       if (quirk_no_way_out)
+                               quirk_no_way_out(i, m, regs);
+               }
                if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY)
                        ret = 1;
        }
@@ -1040,7 +1046,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
        *final = m;
 
        memset(valid_banks, 0, sizeof(valid_banks));
-       no_way_out = mce_no_way_out(&m, &msg, valid_banks);
+       no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs);
 
        barrier();
 
@@ -1418,6 +1424,34 @@ static void __mcheck_cpu_init_generic(void)
        }
 }
 
+/*
+ * During IFU recovery Sandy Bridge -EP4S processors set the RIPV and
+ * EIPV bits in MCG_STATUS to zero on the affected logical processor (SDM
+ * Vol 3B Table 15-20). But this confuses both the code that determines
+ * whether the machine check occurred in kernel or user mode, and also
+ * the severity assessment code. Pretend that EIPV was set, and take the
+ * ip/cs values from the pt_regs that mce_gather_info() ignored earlier.
+ */
+static void quirk_sandybridge_ifu(int bank, struct mce *m, struct pt_regs *regs)
+{
+       if (bank != 0)
+               return;
+       if ((m->mcgstatus & (MCG_STATUS_EIPV|MCG_STATUS_RIPV)) != 0)
+               return;
+       if ((m->status & (MCI_STATUS_OVER|MCI_STATUS_UC|
+                         MCI_STATUS_EN|MCI_STATUS_MISCV|MCI_STATUS_ADDRV|
+                         MCI_STATUS_PCC|MCI_STATUS_S|MCI_STATUS_AR|
+                         MCACOD)) !=
+                        (MCI_STATUS_UC|MCI_STATUS_EN|
+                         MCI_STATUS_MISCV|MCI_STATUS_ADDRV|MCI_STATUS_S|
+                         MCI_STATUS_AR|MCACOD_INSTR))
+               return;
+
+       m->mcgstatus |= MCG_STATUS_EIPV;
+       m->ip = regs->ip;
+       m->cs = regs->cs;
+}
+
 /* Add per CPU specific workarounds here */
 static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
 {
@@ -1515,6 +1549,9 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
                 */
                if (c->x86 == 6 && c->x86_model <= 13 && mce_bootlog < 0)
                        mce_bootlog = 0;
+
+               if (c->x86 == 6 && c->x86_model == 45)
+                       quirk_no_way_out = quirk_sandybridge_ifu;
        }
        if (monarch_timeout < 0)
                monarch_timeout = 0;
index 29557aa06dda6a724add1d6be6f7744f2d801d34..915b876edd1e2b8a509786446642302648989a73 100644 (file)
@@ -32,6 +32,8 @@
 #include <asm/smp.h>
 #include <asm/alternative.h>
 #include <asm/timer.h>
+#include <asm/desc.h>
+#include <asm/ldt.h>
 
 #include "perf_event.h"
 
@@ -1738,6 +1740,29 @@ valid_user_frame(const void __user *fp, unsigned long size)
        return (__range_not_ok(fp, size, TASK_SIZE) == 0);
 }
 
+static unsigned long get_segment_base(unsigned int segment)
+{
+       struct desc_struct *desc;
+       int idx = segment >> 3;
+
+       if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+               if (idx > LDT_ENTRIES)
+                       return 0;
+
+               if (idx > current->active_mm->context.size)
+                       return 0;
+
+               desc = current->active_mm->context.ldt;
+       } else {
+               if (idx > GDT_ENTRIES)
+                       return 0;
+
+               desc = __this_cpu_ptr(&gdt_page.gdt[0]);
+       }
+
+       return get_desc_base(desc + idx);
+}
+
 #ifdef CONFIG_COMPAT
 
 #include <asm/compat.h>
@@ -1746,13 +1771,17 @@ static inline int
 perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
 {
        /* 32-bit process in 64-bit kernel. */
+       unsigned long ss_base, cs_base;
        struct stack_frame_ia32 frame;
        const void __user *fp;
 
        if (!test_thread_flag(TIF_IA32))
                return 0;
 
-       fp = compat_ptr(regs->bp);
+       cs_base = get_segment_base(regs->cs);
+       ss_base = get_segment_base(regs->ss);
+
+       fp = compat_ptr(ss_base + regs->bp);
        while (entry->nr < PERF_MAX_STACK_DEPTH) {
                unsigned long bytes;
                frame.next_frame     = 0;
@@ -1765,8 +1794,8 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
                if (!valid_user_frame(fp, sizeof(frame)))
                        break;
 
-               perf_callchain_store(entry, frame.return_address);
-               fp = compat_ptr(frame.next_frame);
+               perf_callchain_store(entry, cs_base + frame.return_address);
+               fp = compat_ptr(ss_base + frame.next_frame);
        }
        return 1;
 }
@@ -1789,6 +1818,12 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
                return;
        }
 
+       /*
+        * We don't know what to do with VM86 stacks.. ignore them for now.
+        */
+       if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
+               return;
+
        fp = (void __user *)regs->bp;
 
        perf_callchain_store(entry, regs->ip);
@@ -1816,16 +1851,50 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
        }
 }
 
-unsigned long perf_instruction_pointer(struct pt_regs *regs)
+/*
+ * Deal with code segment offsets for the various execution modes:
+ *
+ *   VM86 - the good olde 16 bit days, where the linear address is
+ *          20 bits and we use regs->ip + 0x10 * regs->cs.
+ *
+ *   IA32 - Where we need to look at GDT/LDT segment descriptor tables
+ *          to figure out what the 32bit base address is.
+ *
+ *    X32 - has TIF_X32 set, but is running in x86_64
+ *
+ * X86_64 - CS,DS,SS,ES are all zero based.
+ */
+static unsigned long code_segment_base(struct pt_regs *regs)
 {
-       unsigned long ip;
+       /*
+        * If we are in VM86 mode, add the segment offset to convert to a
+        * linear address.
+        */
+       if (regs->flags & X86_VM_MASK)
+               return 0x10 * regs->cs;
+
+       /*
+        * For IA32 we look at the GDT/LDT segment base to convert the
+        * effective IP to a linear address.
+        */
+#ifdef CONFIG_X86_32
+       if (user_mode(regs) && regs->cs != __USER_CS)
+               return get_segment_base(regs->cs);
+#else
+       if (test_thread_flag(TIF_IA32)) {
+               if (user_mode(regs) && regs->cs != __USER32_CS)
+                       return get_segment_base(regs->cs);
+       }
+#endif
+       return 0;
+}
 
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
        if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
-               ip = perf_guest_cbs->get_guest_ip();
-       else
-               ip = instruction_pointer(regs);
+               return perf_guest_cbs->get_guest_ip();
 
-       return ip;
+       return regs->ip + code_segment_base(regs);
 }
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
@@ -1838,7 +1907,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
                else
                        misc |= PERF_RECORD_MISC_GUEST_KERNEL;
        } else {
-               if (!kernel_ip(regs->ip))
+               if (user_mode(regs))
                        misc |= PERF_RECORD_MISC_USER;
                else
                        misc |= PERF_RECORD_MISC_KERNEL;
index 821d53b696d1408fb1b71faffda28283052d9733..6605a81ba3399fb8c1c9044b0e7aa8c2e22ff882 100644 (file)
@@ -516,6 +516,26 @@ static inline bool kernel_ip(unsigned long ip)
 #endif
 }
 
+/*
+ * Not all PMUs provide the right context information to place the reported IP
+ * into full context. Specifically segment registers are typically not
+ * supplied.
+ *
+ * Assuming the address is a linear address (it is for IBS), we fake the CS and
+ * vm86 mode using the known zero-based code segment and 'fix up' the registers
+ * to reflect this.
+ *
+ * Intel PEBS/LBR appear to typically provide the effective address, nothing
+ * much we can do about that but pray and treat it like a linear address.
+ */
+static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip)
+{
+       regs->cs = kernel_ip(ip) ? __KERNEL_CS : __USER_CS;
+       if (regs->flags & X86_VM_MASK)
+               regs->flags ^= (PERF_EFLAGS_VM | X86_VM_MASK);
+       regs->ip = ip;
+}
+
 #ifdef CONFIG_CPU_SUP_AMD
 
 int amd_pmu_init(void);
index da9bcdcd9856666daf006c06ae6e14af4c77bca9..7bfb5bec8630ada6580dd446e8a62de847d12288 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <asm/apic.h>
 
+#include "perf_event.h"
+
 static u32 ibs_caps;
 
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
@@ -536,7 +538,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
        if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
                regs.flags &= ~PERF_EFLAGS_EXACT;
        } else {
-               instruction_pointer_set(&regs, ibs_data.regs[1]);
+               set_linear_ip(&regs, ibs_data.regs[1]);
                regs.flags |= PERF_EFLAGS_EXACT;
        }
 
index 382366977d4c7856d2cd354ebccc908da65e1a4b..7f2739e03e79a80fc1baaf203cf3a22eccec54dc 100644 (file)
@@ -1522,8 +1522,16 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr)
        arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL;
        arr[0].host = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask;
        arr[0].guest = x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_host_mask;
+       /*
+        * If PMU counter has PEBS enabled it is not enough to disable counter
+        * on a guest entry since PEBS memory write can overshoot guest entry
+        * and corrupt guest memory. Disabling PEBS solves the problem.
+        */
+       arr[1].msr = MSR_IA32_PEBS_ENABLE;
+       arr[1].host = cpuc->pebs_enabled;
+       arr[1].guest = 0;
 
-       *nr = 1;
+       *nr = 2;
        return arr;
 }
 
index 629ae0b7ad901c88706716966b1fd71415debe19..e38d97bf4259fc579f2b070fef85980ae7aaab7a 100644 (file)
@@ -499,7 +499,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
         * We sampled a branch insn, rewind using the LBR stack
         */
        if (ip == to) {
-               regs->ip = from;
+               set_linear_ip(regs, from);
                return 1;
        }
 
@@ -529,7 +529,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
        } while (to < ip);
 
        if (to == ip) {
-               regs->ip = old_to;
+               set_linear_ip(regs, old_to);
                return 1;
        }
 
@@ -569,7 +569,8 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
         * A possible PERF_SAMPLE_REGS will have to transfer all regs.
         */
        regs = *iregs;
-       regs.ip = pebs->ip;
+       regs.flags = pebs->flags;
+       set_linear_ip(&regs, pebs->ip);
        regs.bp = pebs->bp;
        regs.sp = pebs->sp;
 
index 7563fda9f0339b935c7b40a347409b966f7ffbdc..0a5571080e7453bc9d602061ffbe2c6ad81647a2 100644 (file)
@@ -796,7 +796,6 @@ static struct intel_uncore_type *nhm_msr_uncores[] = {
 
 DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
 DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
-DEFINE_UNCORE_FORMAT_ATTR(mm_cfg, mm_cfg, "config:63");
 DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
 DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
 
@@ -902,16 +901,21 @@ static struct attribute_group nhmex_uncore_cbox_format_group = {
        .attrs = nhmex_uncore_cbox_formats_attr,
 };
 
+/* msr offset for each instance of cbox */
+static unsigned nhmex_cbox_msr_offsets[] = {
+       0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
+};
+
 static struct intel_uncore_type nhmex_uncore_cbox = {
        .name                   = "cbox",
        .num_counters           = 6,
-       .num_boxes              = 8,
+       .num_boxes              = 10,
        .perf_ctr_bits          = 48,
        .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
        .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
        .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
        .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
-       .msr_offset             = NHMEX_C_MSR_OFFSET,
+       .msr_offsets            = nhmex_cbox_msr_offsets,
        .pair_ctr_ctl           = 1,
        .ops                    = &nhmex_uncore_ops,
        .format_group           = &nhmex_uncore_cbox_format_group
@@ -1032,24 +1036,22 @@ static struct intel_uncore_type nhmex_uncore_bbox = {
 
 static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
 {
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 
-       if (event->attr.config & NHMEX_S_PMON_MM_CFG_EN) {
-               reg1->config = event->attr.config1;
-               reg2->config = event->attr.config2;
-       } else {
-               reg1->config = ~0ULL;
-               reg2->config = ~0ULL;
-       }
+       /* only TO_R_PROG_EV event uses the match/mask register */
+       if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
+           NHMEX_S_EVENT_TO_R_PROG_EV)
+               return 0;
 
        if (box->pmu->pmu_idx == 0)
                reg1->reg = NHMEX_S0_MSR_MM_CFG;
        else
                reg1->reg = NHMEX_S1_MSR_MM_CFG;
-
        reg1->idx = 0;
-
+       reg1->config = event->attr.config1;
+       reg2->config = event->attr.config2;
        return 0;
 }
 
@@ -1059,8 +1061,8 @@ static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct per
        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
 
-       wrmsrl(reg1->reg, 0);
-       if (reg1->config != ~0ULL || reg2->config != ~0ULL) {
+       if (reg1->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg1->reg, 0);
                wrmsrl(reg1->reg + 1, reg1->config);
                wrmsrl(reg1->reg + 2, reg2->config);
                wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
@@ -1074,7 +1076,6 @@ static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
        &format_attr_edge.attr,
        &format_attr_inv.attr,
        &format_attr_thresh8.attr,
-       &format_attr_mm_cfg.attr,
        &format_attr_match.attr,
        &format_attr_mask.attr,
        NULL,
@@ -1142,6 +1143,9 @@ static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
        EVENT_EXTRA_END
 };
 
+/* Nehalem-EX or Westmere-EX ? */
+bool uncore_nhmex;
+
 static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
 {
        struct intel_uncore_extra_reg *er;
@@ -1171,18 +1175,29 @@ static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64
                return false;
 
        /* mask of the shared fields */
-       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       if (uncore_nhmex)
+               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       else
+               mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
        er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
 
        raw_spin_lock_irqsave(&er->lock, flags);
        /* add mask of the non-shared field if it's in use */
-       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8))
-               mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
+               if (uncore_nhmex)
+                       mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               else
+                       mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       }
 
        if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
                atomic_add(1 << (idx * 8), &er->ref);
-               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
-                       NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               if (uncore_nhmex)
+                       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                               NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               else
+                       mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                               WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
                er->config &= ~mask;
                er->config |= (config & mask);
                ret = true;
@@ -1216,7 +1231,10 @@ u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
 
        /* get the non-shared control bits and shift them */
        idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       if (uncore_nhmex)
+               config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       else
+               config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
        if (new_idx > orig_idx) {
                idx = new_idx - orig_idx;
                config <<= 3 * idx;
@@ -1226,6 +1244,10 @@ u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
        }
 
        /* add the shared control bits back */
+       if (uncore_nhmex)
+               config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       else
+               config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
        config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
        if (modify) {
                /* adjust the main event selector */
@@ -1264,7 +1286,8 @@ again:
        }
 
        /* for the match/mask registers */
-       if ((uncore_box_is_fake(box) || !reg2->alloc) &&
+       if (reg2->idx != EXTRA_REG_NONE &&
+           (uncore_box_is_fake(box) || !reg2->alloc) &&
            !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
                goto fail;
 
@@ -1278,7 +1301,8 @@ again:
                if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
                        nhmex_mbox_alter_er(event, idx[0], true);
                reg1->alloc |= alloc;
-               reg2->alloc = 1;
+               if (reg2->idx != EXTRA_REG_NONE)
+                       reg2->alloc = 1;
        }
        return NULL;
 fail:
@@ -1342,9 +1366,6 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
        struct extra_reg *er;
        unsigned msr;
        int reg_idx = 0;
-
-       if (WARN_ON_ONCE(reg1->idx != -1))
-               return -EINVAL;
        /*
         * The mbox events may require 2 extra MSRs at the most. But only
         * the lower 32 bits in these MSRs are significant, so we can use
@@ -1355,11 +1376,6 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
                        continue;
                if (event->attr.config1 & ~er->valid_mask)
                        return -EINVAL;
-               if (er->idx == __BITS_VALUE(reg1->idx, 0, 8) ||
-                   er->idx == __BITS_VALUE(reg1->idx, 1, 8))
-                       continue;
-               if (WARN_ON_ONCE(reg_idx >= 2))
-                       return -EINVAL;
 
                msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
                if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
@@ -1368,6 +1384,8 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
                /* always use the 32~63 bits to pass the PLD config */
                if (er->idx == EXTRA_REG_NHMEX_M_PLD)
                        reg_idx = 1;
+               else if (WARN_ON_ONCE(reg_idx > 0))
+                       return -EINVAL;
 
                reg1->idx &= ~(0xff << (reg_idx * 8));
                reg1->reg &= ~(0xffff << (reg_idx * 16));
@@ -1376,17 +1394,21 @@ static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event
                reg1->config = event->attr.config1;
                reg_idx++;
        }
-       /* use config2 to pass the filter config */
-       reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
-       if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
-               reg2->config = event->attr.config2;
-       else
-               reg2->config = ~0ULL;
-       if (box->pmu->pmu_idx == 0)
-               reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
-       else
-               reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
-
+       /*
+        * The mbox only provides ability to perform address matching
+        * for the PLD events.
+        */
+       if (reg_idx == 2) {
+               reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
+               if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
+                       reg2->config = event->attr.config2;
+               else
+                       reg2->config = ~0ULL;
+               if (box->pmu->pmu_idx == 0)
+                       reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
+               else
+                       reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
+       }
        return 0;
 }
 
@@ -1422,34 +1444,36 @@ static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct per
                wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
                        nhmex_mbox_shared_reg_config(box, idx));
 
-       wrmsrl(reg2->reg, 0);
-       if (reg2->config != ~0ULL) {
-               wrmsrl(reg2->reg + 1,
-                       reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
-               wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
-                       (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
-               wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
+       if (reg2->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg2->reg, 0);
+               if (reg2->config != ~0ULL) {
+                       wrmsrl(reg2->reg + 1,
+                               reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
+                       wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
+                               (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
+                       wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
+               }
        }
 
        wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
 }
 
-DEFINE_UNCORE_FORMAT_ATTR(count_mode,  count_mode,     "config:2-3");
-DEFINE_UNCORE_FORMAT_ATTR(storage_mode, storage_mode,  "config:4-5");
-DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,   wrap_mode,      "config:6");
-DEFINE_UNCORE_FORMAT_ATTR(flag_mode,   flag_mode,      "config:7");
-DEFINE_UNCORE_FORMAT_ATTR(inc_sel,     inc_sel,        "config:9-13");
-DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,        set_flag_sel,   "config:19-21");
-DEFINE_UNCORE_FORMAT_ATTR(filter_cfg,  filter_cfg,     "config2:63");
-DEFINE_UNCORE_FORMAT_ATTR(filter_match,        filter_match,   "config2:0-33");
-DEFINE_UNCORE_FORMAT_ATTR(filter_mask, filter_mask,    "config2:34-61");
-DEFINE_UNCORE_FORMAT_ATTR(dsp,         dsp,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(thr,         thr,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(fvc,         fvc,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(pgt,         pgt,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(map,         map,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(iss,         iss,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(pld,         pld,            "config1:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(count_mode,          count_mode,     "config:2-3");
+DEFINE_UNCORE_FORMAT_ATTR(storage_mode,                storage_mode,   "config:4-5");
+DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,           wrap_mode,      "config:6");
+DEFINE_UNCORE_FORMAT_ATTR(flag_mode,           flag_mode,      "config:7");
+DEFINE_UNCORE_FORMAT_ATTR(inc_sel,             inc_sel,        "config:9-13");
+DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,                set_flag_sel,   "config:19-21");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,       filter_cfg_en,  "config2:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_match,                filter_match,   "config2:0-33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_mask,         filter_mask,    "config2:34-61");
+DEFINE_UNCORE_FORMAT_ATTR(dsp,                 dsp,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(thr,                 thr,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(fvc,                 fvc,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pgt,                 pgt,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(map,                 map,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(iss,                 iss,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pld,                 pld,            "config1:32-63");
 
 static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
        &format_attr_count_mode.attr,
@@ -1458,7 +1482,7 @@ static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
        &format_attr_flag_mode.attr,
        &format_attr_inc_sel.attr,
        &format_attr_set_flag_sel.attr,
-       &format_attr_filter_cfg.attr,
+       &format_attr_filter_cfg_en.attr,
        &format_attr_filter_match.attr,
        &format_attr_filter_mask.attr,
        &format_attr_dsp.attr,
@@ -1482,6 +1506,12 @@ static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
        { /* end: all zeroes */ },
 };
 
+static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
+       { /* end: all zeroes */ },
+};
+
 static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
        NHMEX_UNCORE_OPS_COMMON_INIT(),
        .enable_event   = nhmex_mbox_msr_enable_event,
@@ -1513,7 +1543,7 @@ void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
        int port;
 
-       /* adjust the main event selector */
+       /* adjust the main event selector and extra register index */
        if (reg1->idx % 2) {
                reg1->idx--;
                hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
@@ -1522,29 +1552,17 @@ void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
                hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
        }
 
-       /* adjust address or config of extra register */
+       /* adjust extra register config */
        port = reg1->idx / 6 + box->pmu->pmu_idx * 4;
        switch (reg1->idx % 6) {
-       case 0:
-               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG0(port);
-               break;
-       case 1:
-               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG1(port);
-               break;
        case 2:
-               /* the 8~15 bits to the 0~7 bits */
+               /* shift the 8~15 bits to the 0~7 bits */
                reg1->config >>= 8;
                break;
        case 3:
-               /* the 0~7 bits to the 8~15 bits */
+               /* shift the 0~7 bits to the 8~15 bits */
                reg1->config <<= 8;
                break;
-       case 4:
-               reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port);
-               break;
-       case 5:
-               reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port);
-               break;
        };
 }
 
@@ -1671,7 +1689,7 @@ static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event
        struct hw_perf_event *hwc = &event->hw;
        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
        struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       int port, idx;
+       int idx;
 
        idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
                NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
@@ -1681,27 +1699,11 @@ static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event
        reg1->idx = idx;
        reg1->config = event->attr.config1;
 
-       port = idx / 6 + box->pmu->pmu_idx * 4;
-       idx %= 6;
-       switch (idx) {
-       case 0:
-               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG0(port);
-               break;
-       case 1:
-               reg1->reg = NHMEX_R_MSR_PORTN_IPERF_CFG1(port);
-               break;
-       case 2:
-       case 3:
-               reg1->reg = NHMEX_R_MSR_PORTN_QLX_CFG(port);
-               break;
+       switch (idx % 6) {
        case 4:
        case 5:
-               if (idx == 4)
-                       reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port);
-               else
-                       reg1->reg = NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port);
-               reg2->config = event->attr.config2;
                hwc->config |= event->attr.config & (~0ULL << 32);
+               reg2->config = event->attr.config2;
                break;
        };
        return 0;
@@ -1727,28 +1729,34 @@ static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct per
        struct hw_perf_event *hwc = &event->hw;
        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
        struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int idx, er_idx;
+       int idx, port;
 
-       idx = reg1->idx % 6;
-       er_idx = idx;
-       if (er_idx > 2)
-               er_idx--;
-       er_idx += (reg1->idx / 6) * 5;
+       idx = reg1->idx;
+       port = idx / 6 + box->pmu->pmu_idx * 4;
 
-       switch (idx) {
+       switch (idx % 6) {
        case 0:
+               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
+               break;
        case 1:
-               wrmsrl(reg1->reg, reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
                break;
        case 2:
        case 3:
-               wrmsrl(reg1->reg, nhmex_rbox_shared_reg_config(box, er_idx));
+               wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
+                       nhmex_rbox_shared_reg_config(box, 2 + (idx / 6) * 5));
                break;
        case 4:
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
+                       hwc->config >> 32);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
+               break;
        case 5:
-               wrmsrl(reg1->reg, reg1->config);
-               wrmsrl(reg1->reg + 1, hwc->config >> 32);
-               wrmsrl(reg1->reg + 2, reg2->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
+                       hwc->config >> 32);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
                break;
        };
 
@@ -1756,8 +1764,8 @@ static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct per
                (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
 }
 
-DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config:32-63");
-DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
 DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
 DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
 DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
@@ -2303,6 +2311,7 @@ int uncore_pmu_event_init(struct perf_event *event)
        event->hw.idx = -1;
        event->hw.last_tag = ~0ULL;
        event->hw.extra_reg.idx = EXTRA_REG_NONE;
+       event->hw.branch_reg.idx = EXTRA_REG_NONE;
 
        if (event->attr.config == UNCORE_FIXED_EVENT) {
                /* no fixed counter */
@@ -2373,7 +2382,7 @@ static void __init uncore_type_exit(struct intel_uncore_type *type)
        type->attr_groups[1] = NULL;
 }
 
-static void uncore_types_exit(struct intel_uncore_type **types)
+static void __init uncore_types_exit(struct intel_uncore_type **types)
 {
        int i;
        for (i = 0; types[i]; i++)
@@ -2814,7 +2823,13 @@ static int __init uncore_cpu_init(void)
                        snbep_uncore_cbox.num_boxes = max_cores;
                msr_uncores = snbep_msr_uncores;
                break;
-       case 46:
+       case 46: /* Nehalem-EX */
+               uncore_nhmex = true;
+       case 47: /* Westmere-EX aka. Xeon E7 */
+               if (!uncore_nhmex)
+                       nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
+               if (nhmex_uncore_cbox.num_boxes > max_cores)
+                       nhmex_uncore_cbox.num_boxes = max_cores;
                msr_uncores = nhmex_msr_uncores;
                break;
        default:
index f3851892e0770c540c9df3a7da4925da9ecf2198..5b81c1856aacadb95da71cdf7474bc1633ac7ecc 100644 (file)
@@ -5,7 +5,7 @@
 #include "perf_event.h"
 
 #define UNCORE_PMU_NAME_LEN            32
-#define UNCORE_PMU_HRTIMER_INTERVAL    (60 * NSEC_PER_SEC)
+#define UNCORE_PMU_HRTIMER_INTERVAL    (60LL * NSEC_PER_SEC)
 
 #define UNCORE_FIXED_EVENT             0xff
 #define UNCORE_PMC_IDX_MAX_GENERIC     8
 #define NHMEX_S1_MSR_MASK                      0xe5a
 
 #define NHMEX_S_PMON_MM_CFG_EN                 (0x1ULL << 63)
+#define NHMEX_S_EVENT_TO_R_PROG_EV             0
 
 /* NHM-EX Mbox */
 #define NHMEX_M0_MSR_GLOBAL_CTL                        0xca0
                 NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
                 NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
 
-
-#define NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK     0x1f
-#define NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK     (0x7 << 5)
-#define NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK      (0x7 << 8)
-#define NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR (1 << 23)
-#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK                  \
-               (NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK |   \
-                NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK |   \
-                NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK  |   \
-                NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR)
+#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 11) - 1) | (1 << 23))
 #define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (11 + 3 * (n)))
 
+#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 12) - 1) | (1 << 24))
+#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (12 + 3 * (n)))
+
 /*
  * use the 9~13 bits to select event If the 7th bit is not set,
  * otherwise use the 19~21 bits to select event.
@@ -368,6 +363,7 @@ struct intel_uncore_type {
        unsigned num_shared_regs:8;
        unsigned single_fixed:1;
        unsigned pair_ctr_ctl:1;
+       unsigned *msr_offsets;
        struct event_constraint unconstrainted;
        struct event_constraint *constraints;
        struct intel_uncore_pmu *pmus;
@@ -485,29 +481,31 @@ unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx)
        return idx * 8 + box->pmu->type->perf_ctr;
 }
 
-static inline
-unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
+static inline unsigned uncore_msr_box_offset(struct intel_uncore_box *box)
+{
+       struct intel_uncore_pmu *pmu = box->pmu;
+       return pmu->type->msr_offsets ?
+               pmu->type->msr_offsets[pmu->pmu_idx] :
+               pmu->type->msr_offset * pmu->pmu_idx;
+}
+
+static inline unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
 {
        if (!box->pmu->type->box_ctl)
                return 0;
-       return box->pmu->type->box_ctl +
-               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+       return box->pmu->type->box_ctl + uncore_msr_box_offset(box);
 }
 
-static inline
-unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box)
+static inline unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box)
 {
        if (!box->pmu->type->fixed_ctl)
                return 0;
-       return box->pmu->type->fixed_ctl +
-               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+       return box->pmu->type->fixed_ctl + uncore_msr_box_offset(box);
 }
 
-static inline
-unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
+static inline unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
 {
-       return box->pmu->type->fixed_ctr +
-               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+       return box->pmu->type->fixed_ctr + uncore_msr_box_offset(box);
 }
 
 static inline
@@ -515,7 +513,7 @@ unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
 {
        return box->pmu->type->event_ctl +
                (box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
-               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+               uncore_msr_box_offset(box);
 }
 
 static inline
@@ -523,7 +521,7 @@ unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
 {
        return box->pmu->type->perf_ctr +
                (box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
-               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+               uncore_msr_box_offset(box);
 }
 
 static inline
index 1f5f1d5d2a022b21a6871c083af70f09b9def90f..7ad683d78645c1b8eed3a816e6fca23de94541f3 100644 (file)
@@ -328,6 +328,7 @@ void fixup_irqs(void)
                                chip->irq_retrigger(data);
                        raw_spin_unlock(&desc->lock);
                }
+               __this_cpu_write(vector_irq[vector], -1);
        }
 }
 #endif
index 1d5d31ea686be2aaedb2790637674cc0c0fec56b..dc1404bf8e4b4c48bc6a137c372ab3b4396fc376 100644 (file)
@@ -107,7 +107,7 @@ static int __init create_setup_data_nodes(struct dentry *parent)
 {
        struct setup_data_node *node;
        struct setup_data *data;
-       int error = -ENOMEM;
+       int error;
        struct dentry *d;
        struct page *pg;
        u64 pa_data;
@@ -121,8 +121,10 @@ static int __init create_setup_data_nodes(struct dentry *parent)
 
        while (pa_data) {
                node = kmalloc(sizeof(*node), GFP_KERNEL);
-               if (!node)
+               if (!node) {
+                       error = -ENOMEM;
                        goto err_dir;
+               }
 
                pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT);
                if (PageHighMem(pg)) {
index 1df8fb9e1d5dafc47000ef644823a748c1b31c91..e498b18f010c7b97480ccf1f1018c87a5f07daa1 100644 (file)
@@ -316,6 +316,11 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
        addr &= 1;
        if (addr == 0) {
                if (val & 0x10) {
+                       u8 edge_irr = s->irr & ~s->elcr;
+                       int i;
+                       bool found;
+                       struct kvm_vcpu *vcpu;
+
                        s->init4 = val & 1;
                        s->last_irr = 0;
                        s->irr &= s->elcr;
@@ -333,6 +338,18 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
                        if (val & 0x08)
                                pr_pic_unimpl(
                                        "level sensitive irq not supported");
+
+                       kvm_for_each_vcpu(i, vcpu, s->pics_state->kvm)
+                               if (kvm_apic_accept_pic_intr(vcpu)) {
+                                       found = true;
+                                       break;
+                               }
+
+
+                       if (found)
+                               for (irq = 0; irq < PIC_NUM_PINS/2; irq++)
+                                       if (edge_irr & (1 << irq))
+                                               pic_clear_isr(s, irq);
                } else if (val & 0x08) {
                        if (val & 0x04)
                                s->poll = 1;
index c39b60707e0262be788b6909d3e46d63d746cadf..c00f03de1b794af8fe65387747813d57ed2885a2 100644 (file)
@@ -1488,13 +1488,6 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
                loadsegment(ds, vmx->host_state.ds_sel);
                loadsegment(es, vmx->host_state.es_sel);
        }
-#else
-       /*
-        * The sysexit path does not restore ds/es, so we must set them to
-        * a reasonable value ourselves.
-        */
-       loadsegment(ds, __USER_DS);
-       loadsegment(es, __USER_DS);
 #endif
        reload_tss();
 #ifdef CONFIG_X86_64
@@ -6370,6 +6363,19 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 #endif
              );
 
+#ifndef CONFIG_X86_64
+       /*
+        * The sysexit path does not restore ds/es, so we must set them to
+        * a reasonable value ourselves.
+        *
+        * We can't defer this to vmx_load_host_state() since that function
+        * may be executed in interrupt context, which saves and restore segments
+        * around it, nullifying its effect.
+        */
+       loadsegment(ds, __USER_DS);
+       loadsegment(es, __USER_DS);
+#endif
+
        vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP)
                                  | (1 << VCPU_EXREG_RFLAGS)
                                  | (1 << VCPU_EXREG_CPL)
index 59b59508ff07dc2623887d6be43859215d5bd589..42bce48f692850cf3cadf96e83c86e5f8bf760ee 100644 (file)
@@ -925,6 +925,10 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
         */
        getboottime(&boot);
 
+       if (kvm->arch.kvmclock_offset) {
+               struct timespec ts = ns_to_timespec(kvm->arch.kvmclock_offset);
+               boot = timespec_sub(boot, ts);
+       }
        wc.sec = boot.tv_sec;
        wc.nsec = boot.tv_nsec;
        wc.version = version;
index f6679a7fb8ca492482f18421d78f438cc9cfba2b..b91e48512425f6f210e9406cbfc666395bad6ad1 100644 (file)
@@ -56,9 +56,16 @@ static int vma_shareable(struct vm_area_struct *vma, unsigned long addr)
 }
 
 /*
- * search for a shareable pmd page for hugetlb.
+ * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc()
+ * and returns the corresponding pte. While this is not necessary for the
+ * !shared pmd case because we can allocate the pmd later as well, it makes the
+ * code much cleaner. pmd allocation is essential for the shared case because
+ * pud has to be populated inside the same i_mmap_mutex section - otherwise
+ * racing tasks could either miss the sharing (see huge_pte_offset) or select a
+ * bad pmd for sharing.
  */
-static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
+static pte_t *
+huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
 {
        struct vm_area_struct *vma = find_vma(mm, addr);
        struct address_space *mapping = vma->vm_file->f_mapping;
@@ -68,9 +75,10 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        struct vm_area_struct *svma;
        unsigned long saddr;
        pte_t *spte = NULL;
+       pte_t *pte;
 
        if (!vma_shareable(vma, addr))
-               return;
+               return (pte_t *)pmd_alloc(mm, pud, addr);
 
        mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) {
@@ -97,7 +105,9 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
                put_page(virt_to_page(spte));
        spin_unlock(&mm->page_table_lock);
 out:
+       pte = (pte_t *)pmd_alloc(mm, pud, addr);
        mutex_unlock(&mapping->i_mmap_mutex);
+       return pte;
 }
 
 /*
@@ -142,8 +152,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
                } else {
                        BUG_ON(sz != PMD_SIZE);
                        if (pud_none(*pud))
-                               huge_pmd_share(mm, addr, pud);
-                       pte = (pte_t *) pmd_alloc(mm, pud, addr);
+                               pte = huge_pmd_share(mm, addr, pud);
+                       else
+                               pte = (pte_t *)pmd_alloc(mm, pud, addr);
                }
        }
        BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte));
index 931930a96160b2de489b1dc9c955b676c7a250dd..a718e0d23503fdc4bb3149d4ad5c7046458f2a57 100644 (file)
@@ -919,13 +919,11 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 
        /*
         * On success we use clflush, when the CPU supports it to
-        * avoid the wbindv. If the CPU does not support it, in the
-        * error case, and during early boot (for EFI) we fall back
-        * to cpa_flush_all (which uses wbinvd):
+        * avoid the wbindv. If the CPU does not support it and in the
+        * error case we fall back to cpa_flush_all (which uses
+        * wbindv):
         */
-       if (early_boot_irqs_disabled)
-               __cpa_flush_all((void *)(long)cache);
-       else if (!ret && cpu_has_clflush) {
+       if (!ret && cpu_has_clflush) {
                if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) {
                        cpa_flush_array(addr, numpages, cache,
                                        cpa.flags, pages);
index 4599c3e8bcb63f39fe618f0075ba9e52e0fbb353..4ddf497ca65beae876d17867d4cd7d32cd37f39b 100644 (file)
@@ -142,23 +142,23 @@ static inline int save_add_info(void) {return 0;}
 #endif
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
-void __init
+int __init
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
        u64 start, end;
        int node, pxm;
 
        if (srat_disabled())
-               return;
+               return -1;
        if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
                bad_srat();
-               return;
+               return -1;
        }
        if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
-               return;
+               return -1;
 
        if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
-               return;
+               return -1;
        start = ma->base_address;
        end = start + ma->length;
        pxm = ma->proximity_domain;
@@ -168,12 +168,12 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        if (node < 0) {
                printk(KERN_ERR "SRAT: Too many proximity domains.\n");
                bad_srat();
-               return;
+               return -1;
        }
 
        if (numa_add_memblk(node, start, end) < 0) {
                bad_srat();
-               return;
+               return -1;
        }
 
        node_set(node, numa_nodes_parsed);
@@ -181,6 +181,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n",
               node, pxm,
               (unsigned long long) start, (unsigned long long) end - 1);
+       return 0;
 }
 
 void __init acpi_numa_arch_fixup(void) {}
index 2dc29f51e75aadbfaa29a0c70be54ce02b291ea9..92660edaa1e72de7b027034d83bb9905d0aebe3a 100644 (file)
@@ -234,7 +234,22 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
        return status;
 }
 
-static int efi_set_rtc_mmss(unsigned long nowtime)
+static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
+                                            efi_time_cap_t *tc)
+{
+       unsigned long flags;
+       efi_status_t status;
+
+       spin_lock_irqsave(&rtc_lock, flags);
+       efi_call_phys_prelog();
+       status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm),
+                               virt_to_phys(tc));
+       efi_call_phys_epilog();
+       spin_unlock_irqrestore(&rtc_lock, flags);
+       return status;
+}
+
+int efi_set_rtc_mmss(unsigned long nowtime)
 {
        int real_seconds, real_minutes;
        efi_status_t    status;
@@ -263,7 +278,7 @@ static int efi_set_rtc_mmss(unsigned long nowtime)
        return 0;
 }
 
-static unsigned long efi_get_time(void)
+unsigned long efi_get_time(void)
 {
        efi_status_t status;
        efi_time_t eft;
@@ -606,13 +621,18 @@ static int __init efi_runtime_init(void)
        }
        /*
         * We will only need *early* access to the following
-        * EFI runtime service before set_virtual_address_map
+        * two EFI runtime services before set_virtual_address_map
         * is invoked.
         */
+       efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
        efi_phys.set_virtual_address_map =
                (efi_set_virtual_address_map_t *)
                runtime->set_virtual_address_map;
-
+       /*
+        * Make efi_get_time can be called before entering
+        * virtual mode.
+        */
+       efi.get_time = phys_efi_get_time;
        early_iounmap(runtime, sizeof(efi_runtime_services_t));
 
        return 0;
@@ -700,10 +720,12 @@ void __init efi_init(void)
                efi_enabled = 0;
                return;
        }
+#ifdef CONFIG_X86_32
        if (efi_native) {
                x86_platform.get_wallclock = efi_get_time;
                x86_platform.set_wallclock = efi_set_rtc_mmss;
        }
+#endif
 
 #if EFI_DEBUG
        print_efi_memmap();
index b2d534cab25fc1500c456efbde000779d794e229..88692871823f9910aeb071ad44a86d8c5c251411 100644 (file)
@@ -72,7 +72,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \
                   -Wall -Wstrict-prototypes \
                   -march=i386 -mregparm=3 \
                   -include $(srctree)/$(src)/../../boot/code16gcc.h \
-                  -fno-strict-aliasing -fomit-frame-pointer \
+                  -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
                   $(call cc-option, -ffreestanding) \
                   $(call cc-option, -fno-toplevel-reorder,\
                        $(call cc-option, -fno-unit-at-a-time)) \
index 51171aeff0dc31483cdc6526e641459b0d64deb3..a582bfed95bb05fd1ae4f62060f719856d49a405 100644 (file)
@@ -60,8 +60,8 @@
 51     common  getsockname             sys_getsockname
 52     common  getpeername             sys_getpeername
 53     common  socketpair              sys_socketpair
-54     common  setsockopt              sys_setsockopt
-55     common  getsockopt              sys_getsockopt
+54     64      setsockopt              sys_setsockopt
+55     64      getsockopt              sys_getsockopt
 56     common  clone                   stub_clone
 57     common  fork                    stub_fork
 58     common  vfork                   stub_vfork
 309    common  getcpu                  sys_getcpu
 310    64      process_vm_readv        sys_process_vm_readv
 311    64      process_vm_writev       sys_process_vm_writev
-312    64      kcmp                    sys_kcmp
+312    common  kcmp                    sys_kcmp
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
 538    x32     sendmmsg                compat_sys_sendmmsg
 539    x32     process_vm_readv        compat_sys_process_vm_readv
 540    x32     process_vm_writev       compat_sys_process_vm_writev
+541    x32     setsockopt              compat_sys_setsockopt
+542    x32     getsockopt              compat_sys_getsockopt
index 64effdc6da9400c09515af384d3d4b94c8efcb50..b2e91d40a4cb32a851006d6194d70f3465ec26f3 100644 (file)
@@ -194,6 +194,11 @@ RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID
  * boundary violation will require three middle nodes. */
 RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
 
+/* When we populate back during bootup, the amount of pages can vary. The
+ * max we have is seen is 395979, but that does not mean it can't be more.
+ * But some machines can have 3GB I/O holes even. So lets reserve enough
+ * for 4GB of I/O and E820 holes. */
+RESERVE_BRK(p2m_populated, PMD_SIZE * 4);
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
        BUG_ON(pfn >= MAX_P2M_PFN);
index ac7034129f3f9e656d6cbf537dc063a2e49ba614..d5fdd36190cce3f385011b30a1f5c729a5b6a4dd 100644 (file)
@@ -69,7 +69,9 @@ static const struct acpi_device_id ac_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, ac_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_ac_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
 
 static struct acpi_driver acpi_ac_driver = {
@@ -313,6 +315,7 @@ static int acpi_ac_add(struct acpi_device *device)
        return result;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_ac_resume(struct device *dev)
 {
        struct acpi_ac *ac;
@@ -332,6 +335,7 @@ static int acpi_ac_resume(struct device *dev)
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
        return 0;
 }
+#endif
 
 static int acpi_ac_remove(struct acpi_device *device, int type)
 {
index 5ccb99ae3a6fae1872a13ab40755aa4ecd693106..5de4ec72766d653924068cb6887d07573ef93539 100644 (file)
@@ -83,22 +83,22 @@ acpi_status acpi_hw_clear_acpi_status(void);
 /*
  * hwsleep - sleep/wake support (Legacy sleep registers)
  */
-acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_legacy_sleep(u8 sleep_state);
 
-acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state);
 
-acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_legacy_wake(u8 sleep_state);
 
 /*
  * hwesleep - sleep/wake support (Extended FADT-V5 sleep registers)
  */
 void acpi_hw_execute_sleep_method(char *method_name, u32 integer_argument);
 
-acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_extended_sleep(u8 sleep_state);
 
-acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_extended_wake_prep(u8 sleep_state);
 
-acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_extended_wake(u8 sleep_state);
 
 /*
  * hwvalid - Port I/O with validation
index 48518dac534230a8f59ee7bbfe1e36475396bb19..94996f9ae3ad164636364af38d6ce0b2524cdd72 100644 (file)
@@ -90,7 +90,6 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
  * FUNCTION:    acpi_hw_extended_sleep
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
- *              flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
@@ -100,7 +99,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 {
        acpi_status status;
        u8 sleep_type_value;
@@ -125,12 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
 
        acpi_gbl_system_awake_and_running = FALSE;
 
-       /* Optionally execute _GTS (Going To Sleep) */
-
-       if (flags & ACPI_EXECUTE_GTS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state);
-       }
-
        /* Flush caches, as per ACPI specification */
 
        ACPI_FLUSH_CPU_CACHE();
@@ -172,7 +165,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
  * FUNCTION:    acpi_hw_extended_wake_prep
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - ACPI_EXECUTE_BFS to run optional method
  *
  * RETURN:      Status
  *
@@ -181,7 +173,7 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
 {
        acpi_status status;
        u8 sleep_type_value;
@@ -200,11 +192,6 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
                                 &acpi_gbl_FADT.sleep_control);
        }
 
-       /* Optionally execute _BFS (Back From Sleep) */
-
-       if (flags & ACPI_EXECUTE_BFS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state);
-       }
        return_ACPI_STATUS(AE_OK);
 }
 
@@ -222,7 +209,7 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_extended_wake(u8 sleep_state)
 {
        ACPI_FUNCTION_TRACE(hw_extended_wake);
 
index 9960fe9ef5334f719ed4e5cbd8cb2cbef530a2aa..3fddde056a5e1774e2e208f2478ce07d53fa5bf5 100644 (file)
@@ -56,7 +56,6 @@ ACPI_MODULE_NAME("hwsleep")
  * FUNCTION:    acpi_hw_legacy_sleep
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
- *              flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
@@ -64,7 +63,7 @@ ACPI_MODULE_NAME("hwsleep")
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
  ******************************************************************************/
-acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
 {
        struct acpi_bit_register_info *sleep_type_reg_info;
        struct acpi_bit_register_info *sleep_enable_reg_info;
@@ -110,12 +109,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
                return_ACPI_STATUS(status);
        }
 
-       /* Optionally execute _GTS (Going To Sleep) */
-
-       if (flags & ACPI_EXECUTE_GTS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state);
-       }
-
        /* Get current value of PM1A control */
 
        status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
@@ -214,7 +207,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
  * FUNCTION:    acpi_hw_legacy_wake_prep
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - ACPI_EXECUTE_BFS to run optional method
  *
  * RETURN:      Status
  *
@@ -224,7 +216,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
 {
        acpi_status status;
        struct acpi_bit_register_info *sleep_type_reg_info;
@@ -275,11 +267,6 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
                }
        }
 
-       /* Optionally execute _BFS (Back From Sleep) */
-
-       if (flags & ACPI_EXECUTE_BFS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state);
-       }
        return_ACPI_STATUS(status);
 }
 
@@ -288,7 +275,6 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
  * FUNCTION:    acpi_hw_legacy_wake
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - Reserved, set to zero
  *
  * RETURN:      Status
  *
@@ -297,7 +283,7 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_legacy_wake(u8 sleep_state)
 {
        acpi_status status;
 
index f8684bfe79079ba170c727b96d7ea404a91ee604..1f165a750ae28736ca5066c908d5ade37ba4740e 100644 (file)
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("hwxfsleep")
 
 /* Local prototypes */
 static acpi_status
-acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id);
+acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id);
 
 /*
  * Dispatch table used to efficiently branch to the various sleep
@@ -235,7 +235,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
  *
  ******************************************************************************/
 static acpi_status
-acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
+acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id)
 {
        acpi_status status;
        struct acpi_sleep_functions *sleep_functions =
@@ -248,11 +248,11 @@ acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
         * use the extended sleep registers
         */
        if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) {
-               status = sleep_functions->extended_function(sleep_state, flags);
+               status = sleep_functions->extended_function(sleep_state);
        } else {
                /* Legacy sleep */
 
-               status = sleep_functions->legacy_function(sleep_state, flags);
+               status = sleep_functions->legacy_function(sleep_state);
        }
 
        return (status);
@@ -262,7 +262,7 @@ acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
         * For the case where reduced-hardware-only code is being generated,
         * we know that only the extended sleep registers are available
         */
-       status = sleep_functions->extended_function(sleep_state, flags);
+       status = sleep_functions->extended_function(sleep_state);
        return (status);
 
 #endif                         /* !ACPI_REDUCED_HARDWARE */
@@ -349,7 +349,6 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
  * FUNCTION:    acpi_enter_sleep_state
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
- *              flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
@@ -357,7 +356,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
  ******************************************************************************/
-acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags)
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
 {
        acpi_status status;
 
@@ -371,7 +370,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags)
        }
 
        status =
-           acpi_hw_sleep_dispatch(sleep_state, flags, ACPI_SLEEP_FUNCTION_ID);
+           acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID);
        return_ACPI_STATUS(status);
 }
 
@@ -391,14 +390,14 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
  *              Called with interrupts DISABLED.
  *
  ******************************************************************************/
-acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags)
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
 {
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
 
        status =
-           acpi_hw_sleep_dispatch(sleep_state, flags,
+           acpi_hw_sleep_dispatch(sleep_state,
                                   ACPI_WAKE_PREP_FUNCTION_ID);
        return_ACPI_STATUS(status);
 }
@@ -423,8 +422,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
 
        ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
 
-
-       status = acpi_hw_sleep_dispatch(sleep_state, 0, ACPI_WAKE_FUNCTION_ID);
+       status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID);
        return_ACPI_STATUS(status);
 }
 
index ea4c6d52605a2af79f141efab1f2615c87b0cab1..29e51bc013838c5d33cf1df0089331ae3380951b 100644 (file)
@@ -387,6 +387,7 @@ acpi_get_table_with_size(char *signature,
 
        return (AE_NOT_FOUND);
 }
+ACPI_EXPORT_SYMBOL(acpi_get_table_with_size)
 
 acpi_status
 acpi_get_table(char *signature,
index ff2c876ec412980a8f9a73188f925c964ecae0ad..45e3e1759fb88c09ddd401921d2a4ea035431bff 100644 (file)
@@ -1052,6 +1052,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 /* this is needed to learn about changes made in suspended state */
 static int acpi_battery_resume(struct device *dev)
 {
@@ -1068,6 +1069,7 @@ static int acpi_battery_resume(struct device *dev)
        acpi_battery_update(battery);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
 
index 79d4c22f7a6d82c21e786b591f02f8bfe28b0f43..314a3b84bbc7e2626a227a4ef2a620204dbf2434 100644 (file)
@@ -78,7 +78,9 @@ static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device, int type);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_button_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
 
 static struct acpi_driver acpi_button_driver = {
@@ -310,6 +312,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_button_resume(struct device *dev)
 {
        struct acpi_device *device = to_acpi_device(dev);
@@ -319,6 +322,7 @@ static int acpi_button_resume(struct device *dev)
                return acpi_lid_send_state(device);
        return 0;
 }
+#endif
 
 static int acpi_button_add(struct acpi_device *device)
 {
index 669d9ee80d1678b7665a3b4b8b2ad709743a44aa..bc36a476f1abf139586391c4e490cad56aff4368 100644 (file)
@@ -53,8 +53,10 @@ static const struct acpi_device_id fan_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, fan_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev);
 static int acpi_fan_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
 
 static struct acpi_driver acpi_fan_driver = {
@@ -184,6 +186,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev)
 {
        if (!dev)
@@ -207,6 +210,7 @@ static int acpi_fan_resume(struct device *dev)
 
        return result;
 }
+#endif
 
 static int __init acpi_fan_init(void)
 {
index e56f3be7b07d36fceb32dce25ede0fa35308f0e7..cb31298ca684f5d99578ada635eb2b011bd07b67 100644 (file)
@@ -237,6 +237,8 @@ acpi_parse_processor_affinity(struct acpi_subtable_header *header,
        return 0;
 }
 
+static int __initdata parsed_numa_memblks;
+
 static int __init
 acpi_parse_memory_affinity(struct acpi_subtable_header * header,
                           const unsigned long end)
@@ -250,8 +252,8 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header,
        acpi_table_print_srat_entry(header);
 
        /* let architecture-dependent part to do it */
-       acpi_numa_memory_affinity_init(memory_affinity);
-
+       if (!acpi_numa_memory_affinity_init(memory_affinity))
+               parsed_numa_memblks++;
        return 0;
 }
 
@@ -304,8 +306,10 @@ int __init acpi_numa_init(void)
 
        acpi_numa_arch_fixup();
 
-       if (cnt <= 0)
-               return cnt ?: -ENOENT;
+       if (cnt < 0)
+               return cnt;
+       else if (!parsed_numa_memblks)
+               return -ENOENT;
        return 0;
 }
 
index ec54014c321c5ffd72cf46cc14d877ecbdec1925..72a2c98bc4298e8518e7d2b388f0e2d5d3abdc5f 100644 (file)
@@ -573,8 +573,15 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
                        OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
        if (pci_msi_enabled())
                flags |= OSC_MSI_SUPPORT;
-       if (flags != base_flags)
-               acpi_pci_osc_support(root, flags);
+       if (flags != base_flags) {
+               status = acpi_pci_osc_support(root, flags);
+               if (ACPI_FAILURE(status)) {
+                       dev_info(root->bus->bridge, "ACPI _OSC support "
+                               "notification failed, disabling PCIe ASPM\n");
+                       pcie_no_aspm();
+                       flags = base_flags;
+               }
+       }
 
        if (!pcie_ports_disabled
            && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
index 215ecd09740888be80ce50bbd4ffb74f292c9753..fc1803414629d8233b0d6f11819efd166838952e 100644 (file)
@@ -67,7 +67,9 @@ static const struct acpi_device_id power_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, power_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_power_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
 
 static struct acpi_driver acpi_power_driver = {
@@ -775,6 +777,7 @@ static int acpi_power_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_power_resume(struct device *dev)
 {
        int result = 0, state;
@@ -803,6 +806,7 @@ static int acpi_power_resume(struct device *dev)
 
        return result;
 }
+#endif
 
 int __init acpi_power_init(void)
 {
index ff8e04f2fab40eb7ea14693a2ba70babe1ec8797..bfc31cb0dd3eac96292af65535c2ee4554cdbf10 100644 (file)
@@ -437,7 +437,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
                /* Normal CPU soft online event */
                } else {
                        acpi_processor_ppc_has_changed(pr, 0);
-                       acpi_processor_cst_has_changed(pr);
+                       acpi_processor_hotplug(pr);
                        acpi_processor_reevaluate_tstate(pr, action);
                        acpi_processor_tstate_has_changed(pr);
                }
index c0b9aa5faf4cdfd8d354fa89e8204704714cccf1..ff0740e0a9c248fc932992e56d23540a59489a55 100644 (file)
@@ -988,6 +988,7 @@ static void acpi_sbs_rmdirs(void)
 #endif
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_sbs_resume(struct device *dev)
 {
        struct acpi_sbs *sbs;
@@ -997,6 +998,7 @@ static int acpi_sbs_resume(struct device *dev)
        acpi_sbs_callback(sbs);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
 
index 7a7a9c929247e6faaecbeca3c9863f02abc1c283..fdcdbb652915a32340d91a7d6e6fcce15c3ee602 100644 (file)
 #include "internal.h"
 #include "sleep.h"
 
-u8 wake_sleep_flags = ACPI_NO_OPTIONAL_METHODS;
-static unsigned int gts, bfs;
-static int set_param_wake_flag(const char *val, struct kernel_param *kp)
-{
-       int ret = param_set_int(val, kp);
-
-       if (ret)
-               return ret;
-
-       if (kp->arg == (const char *)&gts) {
-               if (gts)
-                       wake_sleep_flags |= ACPI_EXECUTE_GTS;
-               else
-                       wake_sleep_flags &= ~ACPI_EXECUTE_GTS;
-       }
-       if (kp->arg == (const char *)&bfs) {
-               if (bfs)
-                       wake_sleep_flags |= ACPI_EXECUTE_BFS;
-               else
-                       wake_sleep_flags &= ~ACPI_EXECUTE_BFS;
-       }
-       return ret;
-}
-module_param_call(gts, set_param_wake_flag, param_get_int, &gts, 0644);
-module_param_call(bfs, set_param_wake_flag, param_get_int, &bfs, 0644);
-MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
-MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
-
 static u8 sleep_states[ACPI_S_STATE_COUNT];
-static bool pwr_btn_event_pending;
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
@@ -110,6 +81,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
 
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+static bool pwr_btn_event_pending;
 
 /*
  * The ACPI specification wants us to save NVS memory regions during hibernation
@@ -305,7 +277,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        switch (acpi_state) {
        case ACPI_STATE_S1:
                barrier();
-               status = acpi_enter_sleep_state(acpi_state, wake_sleep_flags);
+               status = acpi_enter_sleep_state(acpi_state);
                break;
 
        case ACPI_STATE_S3:
@@ -319,8 +291,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        /* This violates the spec but is required for bug compatibility. */
        acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 
-       /* Reprogram control registers and execute _BFS */
-       acpi_leave_sleep_state_prep(acpi_state, wake_sleep_flags);
+       /* Reprogram control registers */
+       acpi_leave_sleep_state_prep(acpi_state);
 
        /* ACPI 3.0 specs (P62) says that it's the responsibility
         * of the OSPM to clear the status bit [ implying that the
@@ -603,9 +575,9 @@ static int acpi_hibernation_enter(void)
        ACPI_FLUSH_CPU_CACHE();
 
        /* This shouldn't return.  If it returns, we have a problem */
-       status = acpi_enter_sleep_state(ACPI_STATE_S4, wake_sleep_flags);
-       /* Reprogram control registers and execute _BFS */
-       acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags);
+       status = acpi_enter_sleep_state(ACPI_STATE_S4);
+       /* Reprogram control registers */
+       acpi_leave_sleep_state_prep(ACPI_STATE_S4);
 
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
@@ -617,8 +589,8 @@ static void acpi_hibernation_leave(void)
         * enable it here.
         */
        acpi_enable();
-       /* Reprogram control registers and execute _BFS */
-       acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags);
+       /* Reprogram control registers */
+       acpi_leave_sleep_state_prep(ACPI_STATE_S4);
        /* Check the hardware signature */
        if (facs && s4_hardware_signature != facs->hardware_signature) {
                printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
@@ -892,33 +864,7 @@ static void acpi_power_off(void)
        /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
        printk(KERN_DEBUG "%s called\n", __func__);
        local_irq_disable();
-       acpi_enter_sleep_state(ACPI_STATE_S5, wake_sleep_flags);
-}
-
-/*
- * ACPI 2.0 created the optional _GTS and _BFS,
- * but industry adoption has been neither rapid nor broad.
- *
- * Linux gets into trouble when it executes poorly validated
- * paths through the BIOS, so disable _GTS and _BFS by default,
- * but do speak up and offer the option to enable them.
- */
-static void __init acpi_gts_bfs_check(void)
-{
-       acpi_handle dummy;
-
-       if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__GTS, &dummy)))
-       {
-               printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n");
-               printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, "
-                       "please notify linux-acpi@vger.kernel.org\n");
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__BFS, &dummy)))
-       {
-               printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n");
-               printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, "
-                       "please notify linux-acpi@vger.kernel.org\n");
-       }
+       acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
 int __init acpi_sleep_init(void)
@@ -979,6 +925,5 @@ int __init acpi_sleep_init(void)
         * object can also be evaluated when the system enters S5.
         */
        register_reboot_notifier(&tts_notifier);
-       acpi_gts_bfs_check();
        return 0;
 }
index 240a24400976929c663b9b3f8ce8bafa36435d5f..7c3f98ba4afefd00686fffc36283ad783a3e4798 100644 (file)
@@ -173,7 +173,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp)
 {
        int result = 0;
 
-       if (!strncmp(val, "enable", strlen("enable"))) {
+       if (!strncmp(val, "enable", sizeof("enable") - 1)) {
                result = acpi_debug_trace(trace_method_name, trace_debug_level,
                                          trace_debug_layer, 0);
                if (result)
@@ -181,7 +181,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp)
                goto exit;
        }
 
-       if (!strncmp(val, "disable", strlen("disable"))) {
+       if (!strncmp(val, "disable", sizeof("disable") - 1)) {
                int name = 0;
                result = acpi_debug_trace((char *)&name, trace_debug_level,
                                          trace_debug_layer, 0);
index 9fe90e9fecb56ada8629a55c472c67653bbd02f5..edda74a43406b5232c01a65ac030303abab830f4 100644 (file)
@@ -106,7 +106,9 @@ static const struct acpi_device_id  thermal_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_thermal_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
 
 static struct acpi_driver acpi_thermal_driver = {
@@ -1041,6 +1043,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_thermal_resume(struct device *dev)
 {
        struct acpi_thermal *tz;
@@ -1075,6 +1078,7 @@ static int acpi_thermal_resume(struct device *dev)
 
        return AE_OK;
 }
+#endif
 
 static int thermal_act(const struct dmi_system_id *d) {
 
index d4386019af5d59657812021e608a506adde44fe3..96cce6d5319592b20fbc8536c350d3cffdd841e8 100644 (file)
@@ -2362,7 +2362,7 @@ static int __devinit ia_init(struct atm_dev *dev)
        {  
                printk(DEV_LABEL " (itf %d): can't set up page mapping\n",  
                            dev->number);  
-               return error;  
+               return -ENOMEM;
        }  
        IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=%p,irq=%d\n",  
                        dev->number, iadev->pci->revision, base, iadev->irq);)
index f338037a4f3d9109e4d69da7a22a4e41070615b4..5e6e00bc1652a064530818e5f87416604eba7e25 100644 (file)
@@ -1865,6 +1865,7 @@ int __dev_printk(const char *level, const struct device *dev,
                 struct va_format *vaf)
 {
        char dict[128];
+       const char *level_extra = "";
        size_t dictlen = 0;
        const char *subsys;
 
@@ -1911,10 +1912,14 @@ int __dev_printk(const char *level, const struct device *dev,
                                    "DEVICE=+%s:%s", subsys, dev_name(dev));
        }
 skip:
+       if (level[2])
+               level_extra = &level[2]; /* skip past KERN_SOH "L" */
+
        return printk_emit(0, level[1] - '0',
                           dictlen ? dict : NULL, dictlen,
-                          "%s %s: %pV",
-                          dev_driver_string(dev), dev_name(dev), vaf);
+                          "%s %s: %s%pV",
+                          dev_driver_string(dev), dev_name(dev),
+                          level_extra, vaf);
 }
 EXPORT_SYMBOL(__dev_printk);
 
index 869d7ff2227f8aa87ba5a390644558e7e0585099..eb78e9640c4a86c0df9c0464e7dbd0b37f4ab75d 100644 (file)
@@ -169,8 +169,7 @@ void pm_clk_init(struct device *dev)
  */
 int pm_clk_create(struct device *dev)
 {
-       int ret = dev_pm_get_subsys_data(dev);
-       return ret < 0 ? ret : 0;
+       return dev_pm_get_subsys_data(dev);
 }
 
 /**
index a14085cc613fdfd2116afeb9da0f620b96c492f7..39c32529b83374c36eda18188c393930732ad99f 100644 (file)
@@ -24,7 +24,6 @@
 int dev_pm_get_subsys_data(struct device *dev)
 {
        struct pm_subsys_data *psd;
-       int ret = 0;
 
        psd = kzalloc(sizeof(*psd), GFP_KERNEL);
        if (!psd)
@@ -40,7 +39,6 @@ int dev_pm_get_subsys_data(struct device *dev)
                dev->power.subsys_data = psd;
                pm_clk_init(dev);
                psd = NULL;
-               ret = 1;
        }
 
        spin_unlock_irq(&dev->power.lock);
@@ -48,7 +46,7 @@ int dev_pm_get_subsys_data(struct device *dev)
        /* kfree() verifies that its argument is nonzero. */
        kfree(psd);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
 
index 59894873a3b37de88a50d3b5e1f22ce67e454858..7d9c1cb1c39a7760081bae4d518efd8acf835902 100644 (file)
@@ -147,6 +147,8 @@ static int rpm_check_suspend_allowed(struct device *dev)
            || (dev->power.request_pending
                        && dev->power.request == RPM_REQ_RESUME))
                retval = -EAGAIN;
+       else if (__dev_pm_qos_read_value(dev) < 0)
+               retval = -EPERM;
        else if (dev->power.runtime_status == RPM_SUSPENDED)
                retval = 1;
 
@@ -388,7 +390,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto repeat;
        }
 
-       dev->power.deferred_resume = false;
        if (dev->power.no_callbacks)
                goto no_callback;       /* Assume success. */
 
@@ -403,12 +404,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto out;
        }
 
-       if (__dev_pm_qos_read_value(dev) < 0) {
-               /* Negative PM QoS constraint means "never suspend". */
-               retval = -EPERM;
-               goto out;
-       }
-
        __update_runtime_status(dev, RPM_SUSPENDING);
 
        if (dev->pm_domain)
@@ -440,6 +435,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
        wake_up_all(&dev->power.wait_queue);
 
        if (dev->power.deferred_resume) {
+               dev->power.deferred_resume = false;
                rpm_resume(dev, 0);
                retval = -EAGAIN;
                goto out;
@@ -584,6 +580,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
                    || dev->parent->power.runtime_status == RPM_ACTIVE) {
                        atomic_inc(&dev->parent->power.child_count);
                        spin_unlock(&dev->parent->power.lock);
+                       retval = 1;
                        goto no_callback;       /* Assume success. */
                }
                spin_unlock(&dev->parent->power.lock);
@@ -664,7 +661,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
        }
        wake_up_all(&dev->power.wait_queue);
 
-       if (!retval)
+       if (retval >= 0)
                rpm_idle(dev, RPM_ASYNC);
 
  out:
index 11b32d2642dfc25dd4b1d22b30c9e3bf0cf65555..a6e5672c67e77f473a8685884ff4626791e99ab2 100644 (file)
@@ -272,6 +272,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
        { 0, },
 };
index 26823d97fd9f60925967b51a4fdfc158454bbe1b..9ea4627dc0c233a808f322816c2560fd9c145d3d 100644 (file)
@@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
                /* for these chips OTP is always available */
                present = true;
                break;
-
+       case BCMA_CHIP_ID_BCM43228:
+               present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
+               break;
        default:
                present = false;
                break;
index a796407123c714174c006f228b1e8e189be2295a..f529407db93ff74dbfa8b9dad13324815467fad2 100644 (file)
@@ -353,18 +353,6 @@ config BLK_DEV_SX8
 
          Use devices /dev/sx8/$N and /dev/sx8/$Np$M.
 
-config BLK_DEV_UB
-       tristate "Low Performance USB Block driver (deprecated)"
-       depends on USB
-       help
-         This driver supports certain USB attached storage devices
-         such as flash keys.
-
-         If you enable this driver, it is recommended to avoid conflicts
-         with usb-storage by enabling USB_LIBUSUAL.
-
-         If unsure, say N.
-
 config BLK_DEV_RAM
        tristate "RAM block device support"
        ---help---
index 5b795059f8fb76107b5f2950dd88c5c9696ad4ee..17e82df3df74f1bae7c48a6106ab3b8cdff1ec7b 100644 (file)
@@ -33,7 +33,6 @@ obj-$(CONFIG_VIRTIO_BLK)      += virtio_blk.o
 
 obj-$(CONFIG_VIODASD)          += viodasd.o
 obj-$(CONFIG_BLK_DEV_SX8)      += sx8.o
-obj-$(CONFIG_BLK_DEV_UB)       += ub.o
 obj-$(CONFIG_BLK_DEV_HD)       += hd.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
index acda773b3720878495d14f5ebfbe1a82f50c0f74..38aa6dda6b81d0deeb355956ead087324f41f3d1 100644 (file)
@@ -763,16 +763,7 @@ static void complete_scsi_command(CommandList_struct *c, int timeout,
                {
                        case CMD_TARGET_STATUS:
                                /* Pass it up to the upper layers... */
-                               if( ei->ScsiStatus)
-                               {
-#if 0
-                                       printk(KERN_WARNING "cciss: cmd %p "
-                                               "has SCSI Status = %x\n",
-                                               c, ei->ScsiStatus);
-#endif
-                                       cmd->result |= (ei->ScsiStatus << 1);
-                               }
-                               else {  /* scsi status is zero??? How??? */
+                               if (!ei->ScsiStatus) {
                                        
        /* Ordinarily, this case should never happen, but there is a bug
           in some released firmware revisions that allows it to happen
index 2e0e7fc1dbbaf50e24d8a446a4e20aeb2239f5bb..dbe6135a2abeddfb78b8d812f4b892c7b5696d03 100644 (file)
@@ -3537,9 +3537,9 @@ static void drbd_cleanup(void)
 }
 
 /**
- * drbd_congested() - Callback for pdflush
+ * drbd_congested() - Callback for the flusher thread
  * @congested_data:    User data
- * @bdi_bits:          Bits pdflush is currently interested in
+ * @bdi_bits:          Bits the BDI flusher thread is currently interested in
  *
  * Returns 1<<BDI_async_congested and/or 1<<BDI_sync_congested if we are congested.
  */
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
deleted file mode 100644 (file)
index fcec022..0000000
+++ /dev/null
@@ -1,2474 +0,0 @@
-/*
- * The low performance USB storage driver (ub).
- *
- * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
- * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com)
- *
- * This work is a part of Linux kernel, is derived from it,
- * and is not licensed separately. See file COPYING for details.
- *
- * TODO (sorted by decreasing priority)
- *  -- Return sense now that rq allows it (we always auto-sense anyway).
- *  -- set readonly flag for CDs, set removable flag for CF readers
- *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
- *  -- verify the 13 conditions and do bulk resets
- *  -- highmem
- *  -- move top_sense and work_bcs into separate allocations (if they survive)
- *     for cache purists and esoteric architectures.
- *  -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
- *  -- prune comments, they are too volumnous
- *  -- Resove XXX's
- *  -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb_usual.h>
-#include <linux/blkdev.h>
-#include <linux/timer.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <scsi/scsi.h>
-
-#define DRV_NAME "ub"
-
-#define UB_MAJOR 180
-
-/*
- * The command state machine is the key model for understanding of this driver.
- *
- * The general rule is that all transitions are done towards the bottom
- * of the diagram, thus preventing any loops.
- *
- * An exception to that is how the STAT state is handled. A counter allows it
- * to be re-entered along the path marked with [C].
- *
- *       +--------+
- *       ! INIT   !
- *       +--------+
- *           !
- *        ub_scsi_cmd_start fails ->--------------------------------------\
- *           !                                                            !
- *           V                                                            !
- *       +--------+                                                       !
- *       ! CMD    !                                                       !
- *       +--------+                                                       !
- *           !                                            +--------+      !
- *         was -EPIPE -->-------------------------------->! CLEAR  !      !
- *           !                                            +--------+      !
- *           !                                                !           !
- *         was error -->------------------------------------- ! --------->\
- *           !                                                !           !
- *  /--<-- cmd->dir == NONE ?                                 !           !
- *  !        !                                                !           !
- *  !        V                                                !           !
- *  !    +--------+                                           !           !
- *  !    ! DATA   !                                           !           !
- *  !    +--------+                                           !           !
- *  !        !                           +---------+          !           !
- *  !      was -EPIPE -->--------------->! CLR2STS !          !           !
- *  !        !                           +---------+          !           !
- *  !        !                                !               !           !
- *  !        !                              was error -->---- ! --------->\
- *  !      was error -->--------------------- ! ------------- ! --------->\
- *  !        !                                !               !           !
- *  !        V                                !               !           !
- *  \--->+--------+                           !               !           !
- *       ! STAT   !<--------------------------/               !           !
- *  /--->+--------+                                           !           !
- *  !        !                                                !           !
- * [C]     was -EPIPE -->-----------\                         !           !
- *  !        !                      !                         !           !
- *  +<---- len == 0                 !                         !           !
- *  !        !                      !                         !           !
- *  !      was error -->--------------------------------------!---------->\
- *  !        !                      !                         !           !
- *  +<---- bad CSW                  !                         !           !
- *  +<---- bad tag                  !                         !           !
- *  !        !                      V                         !           !
- *  !        !                 +--------+                     !           !
- *  !        !                 ! CLRRS  !                     !           !
- *  !        !                 +--------+                     !           !
- *  !        !                      !                         !           !
- *  \------- ! --------------------[C]--------\               !           !
- *           !                                !               !           !
- *         cmd->error---\                +--------+           !           !
- *           !          +--------------->! SENSE  !<----------/           !
- *         STAT_FAIL----/                +--------+                       !
- *           !                                !                           V
- *           !                                V                      +--------+
- *           \--------------------------------\--------------------->! DONE   !
- *                                                                   +--------+
- */
-
-/*
- * This many LUNs per USB device.
- * Every one of them takes a host, see UB_MAX_HOSTS.
- */
-#define UB_MAX_LUNS   9
-
-/*
- */
-
-#define UB_PARTS_PER_LUN      8
-
-#define UB_MAX_CDB_SIZE      16                /* Corresponds to Bulk */
-
-#define UB_SENSE_SIZE  18
-
-/*
- */
-struct ub_dev;
-
-#define UB_MAX_REQ_SG  9       /* cdrecord requires 32KB and maybe a header */
-#define UB_MAX_SECTORS 64
-
-/*
- * A second is more than enough for a 32K transfer (UB_MAX_SECTORS)
- * even if a webcam hogs the bus, but some devices need time to spin up.
- */
-#define UB_URB_TIMEOUT (HZ*2)
-#define UB_DATA_TIMEOUT        (HZ*5)  /* ZIP does spin-ups in the data phase */
-#define UB_STAT_TIMEOUT        (HZ*5)  /* Same spinups and eject for a dataless cmd. */
-#define UB_CTRL_TIMEOUT        (HZ/2)  /* 500ms ought to be enough to clear a stall */
-
-/*
- * An instance of a SCSI command in transit.
- */
-#define UB_DIR_NONE    0
-#define UB_DIR_READ    1
-#define UB_DIR_ILLEGAL2        2
-#define UB_DIR_WRITE   3
-
-#define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
-                        (((c)==UB_DIR_READ)? 'r': 'n'))
-
-enum ub_scsi_cmd_state {
-       UB_CMDST_INIT,                  /* Initial state */
-       UB_CMDST_CMD,                   /* Command submitted */
-       UB_CMDST_DATA,                  /* Data phase */
-       UB_CMDST_CLR2STS,               /* Clearing before requesting status */
-       UB_CMDST_STAT,                  /* Status phase */
-       UB_CMDST_CLEAR,                 /* Clearing a stall (halt, actually) */
-       UB_CMDST_CLRRS,                 /* Clearing before retrying status */
-       UB_CMDST_SENSE,                 /* Sending Request Sense */
-       UB_CMDST_DONE                   /* Final state */
-};
-
-struct ub_scsi_cmd {
-       unsigned char cdb[UB_MAX_CDB_SIZE];
-       unsigned char cdb_len;
-
-       unsigned char dir;              /* 0 - none, 1 - read, 3 - write. */
-       enum ub_scsi_cmd_state state;
-       unsigned int tag;
-       struct ub_scsi_cmd *next;
-
-       int error;                      /* Return code - valid upon done */
-       unsigned int act_len;           /* Return size */
-       unsigned char key, asc, ascq;   /* May be valid if error==-EIO */
-
-       int stat_count;                 /* Retries getting status. */
-       unsigned int timeo;             /* jiffies until rq->timeout changes */
-
-       unsigned int len;               /* Requested length */
-       unsigned int current_sg;
-       unsigned int nsg;               /* sgv[nsg] */
-       struct scatterlist sgv[UB_MAX_REQ_SG];
-
-       struct ub_lun *lun;
-       void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
-       void *back;
-};
-
-struct ub_request {
-       struct request *rq;
-       unsigned int current_try;
-       unsigned int nsg;               /* sgv[nsg] */
-       struct scatterlist sgv[UB_MAX_REQ_SG];
-};
-
-/*
- */
-struct ub_capacity {
-       unsigned long nsec;             /* Linux size - 512 byte sectors */
-       unsigned int bsize;             /* Linux hardsect_size */
-       unsigned int bshift;            /* Shift between 512 and hard sects */
-};
-
-/*
- * This is a direct take-off from linux/include/completion.h
- * The difference is that I do not wait on this thing, just poll.
- * When I want to wait (ub_probe), I just use the stock completion.
- *
- * Note that INIT_COMPLETION takes no lock. It is correct. But why
- * in the bloody hell that thing takes struct instead of pointer to struct
- * is quite beyond me. I just copied it from the stock completion.
- */
-struct ub_completion {
-       unsigned int done;
-       spinlock_t lock;
-};
-
-static DEFINE_MUTEX(ub_mutex);
-static inline void ub_init_completion(struct ub_completion *x)
-{
-       x->done = 0;
-       spin_lock_init(&x->lock);
-}
-
-#define UB_INIT_COMPLETION(x)  ((x).done = 0)
-
-static void ub_complete(struct ub_completion *x)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&x->lock, flags);
-       x->done++;
-       spin_unlock_irqrestore(&x->lock, flags);
-}
-
-static int ub_is_completed(struct ub_completion *x)
-{
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&x->lock, flags);
-       ret = x->done;
-       spin_unlock_irqrestore(&x->lock, flags);
-       return ret;
-}
-
-/*
- */
-struct ub_scsi_cmd_queue {
-       int qlen, qmax;
-       struct ub_scsi_cmd *head, *tail;
-};
-
-/*
- * The block device instance (one per LUN).
- */
-struct ub_lun {
-       struct ub_dev *udev;
-       struct list_head link;
-       struct gendisk *disk;
-       int id;                         /* Host index */
-       int num;                        /* LUN number */
-       char name[16];
-
-       int changed;                    /* Media was changed */
-       int removable;
-       int readonly;
-
-       struct ub_request urq;
-
-       /* Use Ingo's mempool if or when we have more than one command. */
-       /*
-        * Currently we never need more than one command for the whole device.
-        * However, giving every LUN a command is a cheap and automatic way
-        * to enforce fairness between them.
-        */
-       int cmda[1];
-       struct ub_scsi_cmd cmdv[1];
-
-       struct ub_capacity capacity; 
-};
-
-/*
- * The USB device instance.
- */
-struct ub_dev {
-       spinlock_t *lock;
-       atomic_t poison;                /* The USB device is disconnected */
-       int openc;                      /* protected by ub_lock! */
-                                       /* kref is too implicit for our taste */
-       int reset;                      /* Reset is running */
-       int bad_resid;
-       unsigned int tagcnt;
-       char name[12];
-       struct usb_device *dev;
-       struct usb_interface *intf;
-
-       struct list_head luns;
-
-       unsigned int send_bulk_pipe;    /* cached pipe values */
-       unsigned int recv_bulk_pipe;
-       unsigned int send_ctrl_pipe;
-       unsigned int recv_ctrl_pipe;
-
-       struct tasklet_struct tasklet;
-
-       struct ub_scsi_cmd_queue cmd_queue;
-       struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */
-       unsigned char top_sense[UB_SENSE_SIZE];
-
-       struct ub_completion work_done;
-       struct urb work_urb;
-       struct timer_list work_timer;
-       int last_pipe;                  /* What might need clearing */
-       __le32 signature;               /* Learned signature */
-       struct bulk_cb_wrap work_bcb;
-       struct bulk_cs_wrap work_bcs;
-       struct usb_ctrlrequest work_cr;
-
-       struct work_struct reset_work;
-       wait_queue_head_t reset_wait;
-};
-
-/*
- */
-static void ub_cleanup(struct ub_dev *sc);
-static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
-static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq);
-static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq);
-static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_end_rq(struct request *rq, unsigned int status);
-static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_request *urq, struct ub_scsi_cmd *cmd);
-static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_urb_complete(struct urb *urb);
-static void ub_scsi_action(unsigned long _dev);
-static void ub_scsi_dispatch(struct ub_dev *sc);
-static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
-static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    int stalled_pipe);
-static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
-static void ub_reset_enter(struct ub_dev *sc, int try);
-static void ub_reset_task(struct work_struct *work);
-static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_capacity *ret);
-static int ub_sync_reset(struct ub_dev *sc);
-static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe);
-static int ub_probe_lun(struct ub_dev *sc, int lnum);
-
-/*
- */
-#ifdef CONFIG_USB_LIBUSUAL
-
-#define ub_usb_ids  usb_storage_usb_ids
-#else
-
-static const struct usb_device_id ub_usb_ids[] = {
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, ub_usb_ids);
-#endif /* CONFIG_USB_LIBUSUAL */
-
-/*
- * Find me a way to identify "next free minor" for add_disk(),
- * and the array disappears the next day. However, the number of
- * hosts has something to do with the naming and /proc/partitions.
- * This has to be thought out in detail before changing.
- * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure.
- */
-#define UB_MAX_HOSTS  26
-static char ub_hostv[UB_MAX_HOSTS];
-
-#define UB_QLOCK_NUM 5
-static spinlock_t ub_qlockv[UB_QLOCK_NUM];
-static int ub_qlock_next = 0;
-
-static DEFINE_SPINLOCK(ub_lock);       /* Locks globals and ->openc */
-
-/*
- * The id allocator.
- *
- * This also stores the host for indexing by minor, which is somewhat dirty.
- */
-static int ub_id_get(void)
-{
-       unsigned long flags;
-       int i;
-
-       spin_lock_irqsave(&ub_lock, flags);
-       for (i = 0; i < UB_MAX_HOSTS; i++) {
-               if (ub_hostv[i] == 0) {
-                       ub_hostv[i] = 1;
-                       spin_unlock_irqrestore(&ub_lock, flags);
-                       return i;
-               }
-       }
-       spin_unlock_irqrestore(&ub_lock, flags);
-       return -1;
-}
-
-static void ub_id_put(int id)
-{
-       unsigned long flags;
-
-       if (id < 0 || id >= UB_MAX_HOSTS) {
-               printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id);
-               return;
-       }
-
-       spin_lock_irqsave(&ub_lock, flags);
-       if (ub_hostv[id] == 0) {
-               spin_unlock_irqrestore(&ub_lock, flags);
-               printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
-               return;
-       }
-       ub_hostv[id] = 0;
-       spin_unlock_irqrestore(&ub_lock, flags);
-}
-
-/*
- * This is necessitated by the fact that blk_cleanup_queue does not
- * necesserily destroy the queue. Instead, it may merely decrease q->refcnt.
- * Since our blk_init_queue() passes a spinlock common with ub_dev,
- * we have life time issues when ub_cleanup frees ub_dev.
- */
-static spinlock_t *ub_next_lock(void)
-{
-       unsigned long flags;
-       spinlock_t *ret;
-
-       spin_lock_irqsave(&ub_lock, flags);
-       ret = &ub_qlockv[ub_qlock_next];
-       ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM;
-       spin_unlock_irqrestore(&ub_lock, flags);
-       return ret;
-}
-
-/*
- * Downcount for deallocation. This rides on two assumptions:
- *  - once something is poisoned, its refcount cannot grow
- *  - opens cannot happen at this time (del_gendisk was done)
- * If the above is true, we can drop the lock, which we need for
- * blk_cleanup_queue(): the silly thing may attempt to sleep.
- * [Actually, it never needs to sleep for us, but it calls might_sleep()]
- */
-static void ub_put(struct ub_dev *sc)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ub_lock, flags);
-       --sc->openc;
-       if (sc->openc == 0 && atomic_read(&sc->poison)) {
-               spin_unlock_irqrestore(&ub_lock, flags);
-               ub_cleanup(sc);
-       } else {
-               spin_unlock_irqrestore(&ub_lock, flags);
-       }
-}
-
-/*
- * Final cleanup and deallocation.
- */
-static void ub_cleanup(struct ub_dev *sc)
-{
-       struct list_head *p;
-       struct ub_lun *lun;
-       struct request_queue *q;
-
-       while (!list_empty(&sc->luns)) {
-               p = sc->luns.next;
-               lun = list_entry(p, struct ub_lun, link);
-               list_del(p);
-
-               /* I don't think queue can be NULL. But... Stolen from sx8.c */
-               if ((q = lun->disk->queue) != NULL)
-                       blk_cleanup_queue(q);
-               /*
-                * If we zero disk->private_data BEFORE put_disk, we have
-                * to check for NULL all over the place in open, release,
-                * check_media and revalidate, because the block level
-                * semaphore is well inside the put_disk.
-                * But we cannot zero after the call, because *disk is gone.
-                * The sd.c is blatantly racy in this area.
-                */
-               /* disk->private_data = NULL; */
-               put_disk(lun->disk);
-               lun->disk = NULL;
-
-               ub_id_put(lun->id);
-               kfree(lun);
-       }
-
-       usb_set_intfdata(sc->intf, NULL);
-       usb_put_intf(sc->intf);
-       usb_put_dev(sc->dev);
-       kfree(sc);
-}
-
-/*
- * The "command allocator".
- */
-static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun)
-{
-       struct ub_scsi_cmd *ret;
-
-       if (lun->cmda[0])
-               return NULL;
-       ret = &lun->cmdv[0];
-       lun->cmda[0] = 1;
-       return ret;
-}
-
-static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd)
-{
-       if (cmd != &lun->cmdv[0]) {
-               printk(KERN_WARNING "%s: releasing a foreign cmd %p\n",
-                   lun->name, cmd);
-               return;
-       }
-       if (!lun->cmda[0]) {
-               printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name);
-               return;
-       }
-       lun->cmda[0] = 0;
-}
-
-/*
- * The command queue.
- */
-static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
-
-       if (t->qlen++ == 0) {
-               t->head = cmd;
-               t->tail = cmd;
-       } else {
-               t->tail->next = cmd;
-               t->tail = cmd;
-       }
-
-       if (t->qlen > t->qmax)
-               t->qmax = t->qlen;
-}
-
-static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
-
-       if (t->qlen++ == 0) {
-               t->head = cmd;
-               t->tail = cmd;
-       } else {
-               cmd->next = t->head;
-               t->head = cmd;
-       }
-
-       if (t->qlen > t->qmax)
-               t->qmax = t->qlen;
-}
-
-static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
-{
-       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
-       struct ub_scsi_cmd *cmd;
-
-       if (t->qlen == 0)
-               return NULL;
-       if (--t->qlen == 0)
-               t->tail = NULL;
-       cmd = t->head;
-       t->head = cmd->next;
-       cmd->next = NULL;
-       return cmd;
-}
-
-#define ub_cmdq_peek(sc)  ((sc)->cmd_queue.head)
-
-/*
- * The request function is our main entry point
- */
-
-static void ub_request_fn(struct request_queue *q)
-{
-       struct ub_lun *lun = q->queuedata;
-       struct request *rq;
-
-       while ((rq = blk_peek_request(q)) != NULL) {
-               if (ub_request_fn_1(lun, rq) != 0) {
-                       blk_stop_queue(q);
-                       break;
-               }
-       }
-}
-
-static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
-{
-       struct ub_dev *sc = lun->udev;
-       struct ub_scsi_cmd *cmd;
-       struct ub_request *urq;
-       int n_elem;
-
-       if (atomic_read(&sc->poison)) {
-               blk_start_request(rq);
-               ub_end_rq(rq, DID_NO_CONNECT << 16);
-               return 0;
-       }
-
-       if (lun->changed && rq->cmd_type != REQ_TYPE_BLOCK_PC) {
-               blk_start_request(rq);
-               ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
-               return 0;
-       }
-
-       if (lun->urq.rq != NULL)
-               return -1;
-       if ((cmd = ub_get_cmd(lun)) == NULL)
-               return -1;
-       memset(cmd, 0, sizeof(struct ub_scsi_cmd));
-
-       blk_start_request(rq);
-
-       urq = &lun->urq;
-       memset(urq, 0, sizeof(struct ub_request));
-       urq->rq = rq;
-
-       /*
-        * get scatterlist from block layer
-        */
-       sg_init_table(&urq->sgv[0], UB_MAX_REQ_SG);
-       n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
-       if (n_elem < 0) {
-               /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */
-               printk(KERN_INFO "%s: failed request map (%d)\n",
-                   lun->name, n_elem);
-               goto drop;
-       }
-       if (n_elem > UB_MAX_REQ_SG) {   /* Paranoia */
-               printk(KERN_WARNING "%s: request with %d segments\n",
-                   lun->name, n_elem);
-               goto drop;
-       }
-       urq->nsg = n_elem;
-
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-               ub_cmd_build_packet(sc, lun, cmd, urq);
-       } else {
-               ub_cmd_build_block(sc, lun, cmd, urq);
-       }
-       cmd->state = UB_CMDST_INIT;
-       cmd->lun = lun;
-       cmd->done = ub_rw_cmd_done;
-       cmd->back = urq;
-
-       cmd->tag = sc->tagcnt++;
-       if (ub_submit_scsi(sc, cmd) != 0)
-               goto drop;
-
-       return 0;
-
-drop:
-       ub_put_cmd(lun, cmd);
-       ub_end_rq(rq, DID_ERROR << 16);
-       return 0;
-}
-
-static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq)
-{
-       struct request *rq = urq->rq;
-       unsigned int block, nblks;
-
-       if (rq_data_dir(rq) == WRITE)
-               cmd->dir = UB_DIR_WRITE;
-       else
-               cmd->dir = UB_DIR_READ;
-
-       cmd->nsg = urq->nsg;
-       memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
-
-       /*
-        * build the command
-        *
-        * The call to blk_queue_logical_block_size() guarantees that request
-        * is aligned, but it is given in terms of 512 byte units, always.
-        */
-       block = blk_rq_pos(rq) >> lun->capacity.bshift;
-       nblks = blk_rq_sectors(rq) >> lun->capacity.bshift;
-
-       cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
-       /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
-       cmd->cdb[2] = block >> 24;
-       cmd->cdb[3] = block >> 16;
-       cmd->cdb[4] = block >> 8;
-       cmd->cdb[5] = block;
-       cmd->cdb[7] = nblks >> 8;
-       cmd->cdb[8] = nblks;
-       cmd->cdb_len = 10;
-
-       cmd->len = blk_rq_bytes(rq);
-}
-
-static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_scsi_cmd *cmd, struct ub_request *urq)
-{
-       struct request *rq = urq->rq;
-
-       if (blk_rq_bytes(rq) == 0) {
-               cmd->dir = UB_DIR_NONE;
-       } else {
-               if (rq_data_dir(rq) == WRITE)
-                       cmd->dir = UB_DIR_WRITE;
-               else
-                       cmd->dir = UB_DIR_READ;
-       }
-
-       cmd->nsg = urq->nsg;
-       memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
-
-       memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
-       cmd->cdb_len = rq->cmd_len;
-
-       cmd->len = blk_rq_bytes(rq);
-
-       /*
-        * To reapply this to every URB is not as incorrect as it looks.
-        * In return, we avoid any complicated tracking calculations.
-        */
-       cmd->timeo = rq->timeout;
-}
-
-static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct ub_lun *lun = cmd->lun;
-       struct ub_request *urq = cmd->back;
-       struct request *rq;
-       unsigned int scsi_status;
-
-       rq = urq->rq;
-
-       if (cmd->error == 0) {
-               if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-                       if (cmd->act_len >= rq->resid_len)
-                               rq->resid_len = 0;
-                       else
-                               rq->resid_len -= cmd->act_len;
-                       scsi_status = 0;
-               } else {
-                       if (cmd->act_len != cmd->len) {
-                               scsi_status = SAM_STAT_CHECK_CONDITION;
-                       } else {
-                               scsi_status = 0;
-                       }
-               }
-       } else {
-               if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-                       /* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
-                       memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
-                       rq->sense_len = UB_SENSE_SIZE;
-                       if (sc->top_sense[0] != 0)
-                               scsi_status = SAM_STAT_CHECK_CONDITION;
-                       else
-                               scsi_status = DID_ERROR << 16;
-               } else {
-                       if (cmd->error == -EIO &&
-                           (cmd->key == 0 ||
-                            cmd->key == MEDIUM_ERROR ||
-                            cmd->key == UNIT_ATTENTION)) {
-                               if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
-                                       return;
-                       }
-                       scsi_status = SAM_STAT_CHECK_CONDITION;
-               }
-       }
-
-       urq->rq = NULL;
-
-       ub_put_cmd(lun, cmd);
-       ub_end_rq(rq, scsi_status);
-       blk_start_queue(lun->disk->queue);
-}
-
-static void ub_end_rq(struct request *rq, unsigned int scsi_status)
-{
-       int error;
-
-       if (scsi_status == 0) {
-               error = 0;
-       } else {
-               error = -EIO;
-               rq->errors = scsi_status;
-       }
-       __blk_end_request_all(rq, error);
-}
-
-static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_request *urq, struct ub_scsi_cmd *cmd)
-{
-
-       if (atomic_read(&sc->poison))
-               return -ENXIO;
-
-       ub_reset_enter(sc, urq->current_try);
-
-       if (urq->current_try >= 3)
-               return -EIO;
-       urq->current_try++;
-
-       /* Remove this if anyone complains of flooding. */
-       printk(KERN_DEBUG "%s: dir %c len/act %d/%d "
-           "[sense %x %02x %02x] retry %d\n",
-           sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len,
-           cmd->key, cmd->asc, cmd->ascq, urq->current_try);
-
-       memset(cmd, 0, sizeof(struct ub_scsi_cmd));
-       ub_cmd_build_block(sc, lun, cmd, urq);
-
-       cmd->state = UB_CMDST_INIT;
-       cmd->lun = lun;
-       cmd->done = ub_rw_cmd_done;
-       cmd->back = urq;
-
-       cmd->tag = sc->tagcnt++;
-
-#if 0 /* Wasteful */
-       return ub_submit_scsi(sc, cmd);
-#else
-       ub_cmdq_add(sc, cmd);
-       return 0;
-#endif
-}
-
-/*
- * Submit a regular SCSI operation (not an auto-sense).
- *
- * The Iron Law of Good Submit Routine is:
- * Zero return - callback is done, Nonzero return - callback is not done.
- * No exceptions.
- *
- * Host is assumed locked.
- */
-static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-
-       if (cmd->state != UB_CMDST_INIT ||
-           (cmd->dir != UB_DIR_NONE && cmd->len == 0)) {
-               return -EINVAL;
-       }
-
-       ub_cmdq_add(sc, cmd);
-       /*
-        * We can call ub_scsi_dispatch(sc) right away here, but it's a little
-        * safer to jump to a tasklet, in case upper layers do something silly.
-        */
-       tasklet_schedule(&sc->tasklet);
-       return 0;
-}
-
-/*
- * Submit the first URB for the queued command.
- * This function does not deal with queueing in any way.
- */
-static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct bulk_cb_wrap *bcb;
-       int rc;
-
-       bcb = &sc->work_bcb;
-
-       /*
-        * ``If the allocation length is eighteen or greater, and a device
-        * server returns less than eithteen bytes of data, the application
-        * client should assume that the bytes not transferred would have been
-        * zeroes had the device server returned those bytes.''
-        *
-        * We zero sense for all commands so that when a packet request
-        * fails it does not return a stale sense.
-        */
-       memset(&sc->top_sense, 0, UB_SENSE_SIZE);
-
-       /* set up the command wrapper */
-       bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
-       bcb->Tag = cmd->tag;            /* Endianness is not important */
-       bcb->DataTransferLength = cpu_to_le32(cmd->len);
-       bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0;
-       bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0;
-       bcb->Length = cmd->cdb_len;
-
-       /* copy the command payload */
-       memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE);
-
-       UB_INIT_COMPLETION(sc->work_done);
-
-       sc->last_pipe = sc->send_bulk_pipe;
-       usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
-           bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-               /* XXX Clear stalls */
-               ub_complete(&sc->work_done);
-               return rc;
-       }
-
-       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
-       add_timer(&sc->work_timer);
-
-       cmd->state = UB_CMDST_CMD;
-       return 0;
-}
-
-/*
- * Timeout handler.
- */
-static void ub_urb_timeout(unsigned long arg)
-{
-       struct ub_dev *sc = (struct ub_dev *) arg;
-       unsigned long flags;
-
-       spin_lock_irqsave(sc->lock, flags);
-       if (!ub_is_completed(&sc->work_done))
-               usb_unlink_urb(&sc->work_urb);
-       spin_unlock_irqrestore(sc->lock, flags);
-}
-
-/*
- * Completion routine for the work URB.
- *
- * This can be called directly from usb_submit_urb (while we have
- * the sc->lock taken) and from an interrupt (while we do NOT have
- * the sc->lock taken). Therefore, bounce this off to a tasklet.
- */
-static void ub_urb_complete(struct urb *urb)
-{
-       struct ub_dev *sc = urb->context;
-
-       ub_complete(&sc->work_done);
-       tasklet_schedule(&sc->tasklet);
-}
-
-static void ub_scsi_action(unsigned long _dev)
-{
-       struct ub_dev *sc = (struct ub_dev *) _dev;
-       unsigned long flags;
-
-       spin_lock_irqsave(sc->lock, flags);
-       ub_scsi_dispatch(sc);
-       spin_unlock_irqrestore(sc->lock, flags);
-}
-
-static void ub_scsi_dispatch(struct ub_dev *sc)
-{
-       struct ub_scsi_cmd *cmd;
-       int rc;
-
-       while (!sc->reset && (cmd = ub_cmdq_peek(sc)) != NULL) {
-               if (cmd->state == UB_CMDST_DONE) {
-                       ub_cmdq_pop(sc);
-                       (*cmd->done)(sc, cmd);
-               } else if (cmd->state == UB_CMDST_INIT) {
-                       if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
-                               break;
-                       cmd->error = rc;
-                       cmd->state = UB_CMDST_DONE;
-               } else {
-                       if (!ub_is_completed(&sc->work_done))
-                               break;
-                       del_timer(&sc->work_timer);
-                       ub_scsi_urb_compl(sc, cmd);
-               }
-       }
-}
-
-static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct urb *urb = &sc->work_urb;
-       struct bulk_cs_wrap *bcs;
-       int endp;
-       int len;
-       int rc;
-
-       if (atomic_read(&sc->poison)) {
-               ub_state_done(sc, cmd, -ENODEV);
-               return;
-       }
-
-       endp = usb_pipeendpoint(sc->last_pipe);
-       if (usb_pipein(sc->last_pipe))
-               endp |= USB_DIR_IN;
-
-       if (cmd->state == UB_CMDST_CLEAR) {
-               if (urb->status == -EPIPE) {
-                       /*
-                        * STALL while clearning STALL.
-                        * The control pipe clears itself - nothing to do.
-                        */
-                       printk(KERN_NOTICE "%s: stall on control pipe\n",
-                           sc->name);
-                       goto Bad_End;
-               }
-
-               /*
-                * We ignore the result for the halt clear.
-                */
-
-               usb_reset_endpoint(sc->dev, endp);
-
-               ub_state_sense(sc, cmd);
-
-       } else if (cmd->state == UB_CMDST_CLR2STS) {
-               if (urb->status == -EPIPE) {
-                       printk(KERN_NOTICE "%s: stall on control pipe\n",
-                           sc->name);
-                       goto Bad_End;
-               }
-
-               /*
-                * We ignore the result for the halt clear.
-                */
-
-               usb_reset_endpoint(sc->dev, endp);
-
-               ub_state_stat(sc, cmd);
-
-       } else if (cmd->state == UB_CMDST_CLRRS) {
-               if (urb->status == -EPIPE) {
-                       printk(KERN_NOTICE "%s: stall on control pipe\n",
-                           sc->name);
-                       goto Bad_End;
-               }
-
-               /*
-                * We ignore the result for the halt clear.
-                */
-
-               usb_reset_endpoint(sc->dev, endp);
-
-               ub_state_stat_counted(sc, cmd);
-
-       } else if (cmd->state == UB_CMDST_CMD) {
-               switch (urb->status) {
-               case 0:
-                       break;
-               case -EOVERFLOW:
-                       goto Bad_End;
-               case -EPIPE:
-                       rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
-                       if (rc != 0) {
-                               printk(KERN_NOTICE "%s: "
-                                   "unable to submit clear (%d)\n",
-                                   sc->name, rc);
-                               /*
-                                * This is typically ENOMEM or some other such shit.
-                                * Retrying is pointless. Just do Bad End on it...
-                                */
-                               ub_state_done(sc, cmd, rc);
-                               return;
-                       }
-                       cmd->state = UB_CMDST_CLEAR;
-                       return;
-               case -ESHUTDOWN:        /* unplug */
-               case -EILSEQ:           /* unplug timeout on uhci */
-                       ub_state_done(sc, cmd, -ENODEV);
-                       return;
-               default:
-                       goto Bad_End;
-               }
-               if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
-                       goto Bad_End;
-               }
-
-               if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
-                       ub_state_stat(sc, cmd);
-                       return;
-               }
-
-               // udelay(125);         // usb-storage has this
-               ub_data_start(sc, cmd);
-
-       } else if (cmd->state == UB_CMDST_DATA) {
-               if (urb->status == -EPIPE) {
-                       rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
-                       if (rc != 0) {
-                               printk(KERN_NOTICE "%s: "
-                                   "unable to submit clear (%d)\n",
-                                   sc->name, rc);
-                               ub_state_done(sc, cmd, rc);
-                               return;
-                       }
-                       cmd->state = UB_CMDST_CLR2STS;
-                       return;
-               }
-               if (urb->status == -EOVERFLOW) {
-                       /*
-                        * A babble? Failure, but we must transfer CSW now.
-                        */
-                       cmd->error = -EOVERFLOW;        /* A cheap trick... */
-                       ub_state_stat(sc, cmd);
-                       return;
-               }
-
-               if (cmd->dir == UB_DIR_WRITE) {
-                       /*
-                        * Do not continue writes in case of a failure.
-                        * Doing so would cause sectors to be mixed up,
-                        * which is worse than sectors lost.
-                        *
-                        * We must try to read the CSW, or many devices
-                        * get confused.
-                        */
-                       len = urb->actual_length;
-                       if (urb->status != 0 ||
-                           len != cmd->sgv[cmd->current_sg].length) {
-                               cmd->act_len += len;
-
-                               cmd->error = -EIO;
-                               ub_state_stat(sc, cmd);
-                               return;
-                       }
-
-               } else {
-                       /*
-                        * If an error occurs on read, we record it, and
-                        * continue to fetch data in order to avoid bubble.
-                        *
-                        * As a small shortcut, we stop if we detect that
-                        * a CSW mixed into data.
-                        */
-                       if (urb->status != 0)
-                               cmd->error = -EIO;
-
-                       len = urb->actual_length;
-                       if (urb->status != 0 ||
-                           len != cmd->sgv[cmd->current_sg].length) {
-                               if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN)
-                                       goto Bad_End;
-                       }
-               }
-
-               cmd->act_len += urb->actual_length;
-
-               if (++cmd->current_sg < cmd->nsg) {
-                       ub_data_start(sc, cmd);
-                       return;
-               }
-               ub_state_stat(sc, cmd);
-
-       } else if (cmd->state == UB_CMDST_STAT) {
-               if (urb->status == -EPIPE) {
-                       rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
-                       if (rc != 0) {
-                               printk(KERN_NOTICE "%s: "
-                                   "unable to submit clear (%d)\n",
-                                   sc->name, rc);
-                               ub_state_done(sc, cmd, rc);
-                               return;
-                       }
-
-                       /*
-                        * Having a stall when getting CSW is an error, so
-                        * make sure uppper levels are not oblivious to it.
-                        */
-                       cmd->error = -EIO;              /* A cheap trick... */
-
-                       cmd->state = UB_CMDST_CLRRS;
-                       return;
-               }
-
-               /* Catch everything, including -EOVERFLOW and other nasties. */
-               if (urb->status != 0)
-                       goto Bad_End;
-
-               if (urb->actual_length == 0) {
-                       ub_state_stat_counted(sc, cmd);
-                       return;
-               }
-
-               /*
-                * Check the returned Bulk protocol status.
-                * The status block has to be validated first.
-                */
-
-               bcs = &sc->work_bcs;
-
-               if (sc->signature == cpu_to_le32(0)) {
-                       /*
-                        * This is the first reply, so do not perform the check.
-                        * Instead, remember the signature the device uses
-                        * for future checks. But do not allow a nul.
-                        */
-                       sc->signature = bcs->Signature;
-                       if (sc->signature == cpu_to_le32(0)) {
-                               ub_state_stat_counted(sc, cmd);
-                               return;
-                       }
-               } else {
-                       if (bcs->Signature != sc->signature) {
-                               ub_state_stat_counted(sc, cmd);
-                               return;
-                       }
-               }
-
-               if (bcs->Tag != cmd->tag) {
-                       /*
-                        * This usually happens when we disagree with the
-                        * device's microcode about something. For instance,
-                        * a few of them throw this after timeouts. They buffer
-                        * commands and reply at commands we timed out before.
-                        * Without flushing these replies we loop forever.
-                        */
-                       ub_state_stat_counted(sc, cmd);
-                       return;
-               }
-
-               if (!sc->bad_resid) {
-                       len = le32_to_cpu(bcs->Residue);
-                       if (len != cmd->len - cmd->act_len) {
-                               /*
-                                * Only start ignoring if this cmd ended well.
-                                */
-                               if (cmd->len == cmd->act_len) {
-                                       printk(KERN_NOTICE "%s: "
-                                           "bad residual %d of %d, ignoring\n",
-                                           sc->name, len, cmd->len);
-                                       sc->bad_resid = 1;
-                               }
-                       }
-               }
-
-               switch (bcs->Status) {
-               case US_BULK_STAT_OK:
-                       break;
-               case US_BULK_STAT_FAIL:
-                       ub_state_sense(sc, cmd);
-                       return;
-               case US_BULK_STAT_PHASE:
-                       goto Bad_End;
-               default:
-                       printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
-                           sc->name, bcs->Status);
-                       ub_state_done(sc, cmd, -EINVAL);
-                       return;
-               }
-
-               /* Not zeroing error to preserve a babble indicator */
-               if (cmd->error != 0) {
-                       ub_state_sense(sc, cmd);
-                       return;
-               }
-               cmd->state = UB_CMDST_DONE;
-               ub_cmdq_pop(sc);
-               (*cmd->done)(sc, cmd);
-
-       } else if (cmd->state == UB_CMDST_SENSE) {
-               ub_state_done(sc, cmd, -EIO);
-
-       } else {
-               printk(KERN_WARNING "%s: wrong command state %d\n",
-                   sc->name, cmd->state);
-               ub_state_done(sc, cmd, -EINVAL);
-               return;
-       }
-       return;
-
-Bad_End: /* Little Excel is dead */
-       ub_state_done(sc, cmd, -EIO);
-}
-
-/*
- * Factorization helper for the command state machine:
- * Initiate a data segment transfer.
- */
-static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct scatterlist *sg = &cmd->sgv[cmd->current_sg];
-       int pipe;
-       int rc;
-
-       UB_INIT_COMPLETION(sc->work_done);
-
-       if (cmd->dir == UB_DIR_READ)
-               pipe = sc->recv_bulk_pipe;
-       else
-               pipe = sc->send_bulk_pipe;
-       sc->last_pipe = pipe;
-       usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
-           sg->length, ub_urb_complete, sc);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-               /* XXX Clear stalls */
-               ub_complete(&sc->work_done);
-               ub_state_done(sc, cmd, rc);
-               return;
-       }
-
-       if (cmd->timeo)
-               sc->work_timer.expires = jiffies + cmd->timeo;
-       else
-               sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
-       add_timer(&sc->work_timer);
-
-       cmd->state = UB_CMDST_DATA;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Finish the command.
- */
-static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
-{
-
-       cmd->error = rc;
-       cmd->state = UB_CMDST_DONE;
-       ub_cmdq_pop(sc);
-       (*cmd->done)(sc, cmd);
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a CSW read.
- */
-static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       int rc;
-
-       UB_INIT_COMPLETION(sc->work_done);
-
-       sc->last_pipe = sc->recv_bulk_pipe;
-       usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
-           &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-               /* XXX Clear stalls */
-               ub_complete(&sc->work_done);
-               ub_state_done(sc, cmd, rc);
-               return -1;
-       }
-
-       if (cmd->timeo)
-               sc->work_timer.expires = jiffies + cmd->timeo;
-       else
-               sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
-       add_timer(&sc->work_timer);
-       return 0;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a CSW read and go to STAT state.
- */
-static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-
-       if (__ub_state_stat(sc, cmd) != 0)
-               return;
-
-       cmd->stat_count = 0;
-       cmd->state = UB_CMDST_STAT;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a CSW read and go to STAT state with counter (along [C] path).
- */
-static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-
-       if (++cmd->stat_count >= 4) {
-               ub_state_sense(sc, cmd);
-               return;
-       }
-
-       if (__ub_state_stat(sc, cmd) != 0)
-               return;
-
-       cmd->state = UB_CMDST_STAT;
-}
-
-/*
- * Factorization helper for the command state machine:
- * Submit a REQUEST SENSE and go to SENSE state.
- */
-static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct ub_scsi_cmd *scmd;
-       struct scatterlist *sg;
-       int rc;
-
-       if (cmd->cdb[0] == REQUEST_SENSE) {
-               rc = -EPIPE;
-               goto error;
-       }
-
-       scmd = &sc->top_rqs_cmd;
-       memset(scmd, 0, sizeof(struct ub_scsi_cmd));
-       scmd->cdb[0] = REQUEST_SENSE;
-       scmd->cdb[4] = UB_SENSE_SIZE;
-       scmd->cdb_len = 6;
-       scmd->dir = UB_DIR_READ;
-       scmd->state = UB_CMDST_INIT;
-       scmd->nsg = 1;
-       sg = &scmd->sgv[0];
-       sg_init_table(sg, UB_MAX_REQ_SG);
-       sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE,
-                       (unsigned long)sc->top_sense & (PAGE_SIZE-1));
-       scmd->len = UB_SENSE_SIZE;
-       scmd->lun = cmd->lun;
-       scmd->done = ub_top_sense_done;
-       scmd->back = cmd;
-
-       scmd->tag = sc->tagcnt++;
-
-       cmd->state = UB_CMDST_SENSE;
-
-       ub_cmdq_insert(sc, scmd);
-       return;
-
-error:
-       ub_state_done(sc, cmd, rc);
-}
-
-/*
- * A helper for the command's state machine:
- * Submit a stall clear.
- */
-static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    int stalled_pipe)
-{
-       int endp;
-       struct usb_ctrlrequest *cr;
-       int rc;
-
-       endp = usb_pipeendpoint(stalled_pipe);
-       if (usb_pipein (stalled_pipe))
-               endp |= USB_DIR_IN;
-
-       cr = &sc->work_cr;
-       cr->bRequestType = USB_RECIP_ENDPOINT;
-       cr->bRequest = USB_REQ_CLEAR_FEATURE;
-       cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);
-       cr->wIndex = cpu_to_le16(endp);
-       cr->wLength = cpu_to_le16(0);
-
-       UB_INIT_COMPLETION(sc->work_done);
-
-       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
-           (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-               ub_complete(&sc->work_done);
-               return rc;
-       }
-
-       sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
-       add_timer(&sc->work_timer);
-       return 0;
-}
-
-/*
- */
-static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
-{
-       unsigned char *sense = sc->top_sense;
-       struct ub_scsi_cmd *cmd;
-
-       /*
-        * Find the command which triggered the unit attention or a check,
-        * save the sense into it, and advance its state machine.
-        */
-       if ((cmd = ub_cmdq_peek(sc)) == NULL) {
-               printk(KERN_WARNING "%s: sense done while idle\n", sc->name);
-               return;
-       }
-       if (cmd != scmd->back) {
-               printk(KERN_WARNING "%s: "
-                   "sense done for wrong command 0x%x\n",
-                   sc->name, cmd->tag);
-               return;
-       }
-       if (cmd->state != UB_CMDST_SENSE) {
-               printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
-                   sc->name, cmd->state);
-               return;
-       }
-
-       /*
-        * Ignoring scmd->act_len, because the buffer was pre-zeroed.
-        */
-       cmd->key = sense[2] & 0x0F;
-       cmd->asc = sense[12];
-       cmd->ascq = sense[13];
-
-       ub_scsi_urb_compl(sc, cmd);
-}
-
-/*
- * Reset management
- */
-
-static void ub_reset_enter(struct ub_dev *sc, int try)
-{
-
-       if (sc->reset) {
-               /* This happens often on multi-LUN devices. */
-               return;
-       }
-       sc->reset = try + 1;
-
-#if 0 /* Not needed because the disconnect waits for us. */
-       unsigned long flags;
-       spin_lock_irqsave(&ub_lock, flags);
-       sc->openc++;
-       spin_unlock_irqrestore(&ub_lock, flags);
-#endif
-
-#if 0 /* We let them stop themselves. */
-       struct ub_lun *lun;
-       list_for_each_entry(lun, &sc->luns, link) {
-               blk_stop_queue(lun->disk->queue);
-       }
-#endif
-
-       schedule_work(&sc->reset_work);
-}
-
-static void ub_reset_task(struct work_struct *work)
-{
-       struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
-       unsigned long flags;
-       struct ub_lun *lun;
-       int rc;
-
-       if (!sc->reset) {
-               printk(KERN_WARNING "%s: Running reset unrequested\n",
-                   sc->name);
-               return;
-       }
-
-       if (atomic_read(&sc->poison)) {
-               ;
-       } else if ((sc->reset & 1) == 0) {
-               ub_sync_reset(sc);
-               msleep(700);    /* usb-storage sleeps 6s (!) */
-               ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-               ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-       } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
-               ;
-       } else {
-               rc = usb_lock_device_for_reset(sc->dev, sc->intf);
-               if (rc < 0) {
-                       printk(KERN_NOTICE
-                           "%s: usb_lock_device_for_reset failed (%d)\n",
-                           sc->name, rc);
-               } else {
-                       rc = usb_reset_device(sc->dev);
-                       if (rc < 0) {
-                               printk(KERN_NOTICE "%s: "
-                                   "usb_lock_device_for_reset failed (%d)\n",
-                                   sc->name, rc);
-                       }
-                       usb_unlock_device(sc->dev);
-               }
-       }
-
-       /*
-        * In theory, no commands can be running while reset is active,
-        * so nobody can ask for another reset, and so we do not need any
-        * queues of resets or anything. We do need a spinlock though,
-        * to interact with block layer.
-        */
-       spin_lock_irqsave(sc->lock, flags);
-       sc->reset = 0;
-       tasklet_schedule(&sc->tasklet);
-       list_for_each_entry(lun, &sc->luns, link) {
-               blk_start_queue(lun->disk->queue);
-       }
-       wake_up(&sc->reset_wait);
-       spin_unlock_irqrestore(sc->lock, flags);
-}
-
-/*
- * XXX Reset brackets are too much hassle to implement, so just stub them
- * in order to prevent forced unbinding (which deadlocks solid when our
- * ->disconnect method waits for the reset to complete and this kills keventd).
- *
- * XXX Tell Alan to move usb_unlock_device inside of usb_reset_device,
- * or else the post_reset is invoked, and restats I/O on a locked device.
- */
-static int ub_pre_reset(struct usb_interface *iface) {
-       return 0;
-}
-
-static int ub_post_reset(struct usb_interface *iface) {
-       return 0;
-}
-
-/*
- * This is called from a process context.
- */
-static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
-{
-
-       lun->readonly = 0;      /* XXX Query this from the device */
-
-       lun->capacity.nsec = 0;
-       lun->capacity.bsize = 512;
-       lun->capacity.bshift = 0;
-
-       if (ub_sync_tur(sc, lun) != 0)
-               return;                 /* Not ready */
-       lun->changed = 0;
-
-       if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
-               /*
-                * The retry here means something is wrong, either with the
-                * device, with the transport, or with our code.
-                * We keep this because sd.c has retries for capacity.
-                */
-               if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
-                       lun->capacity.nsec = 0;
-                       lun->capacity.bsize = 512;
-                       lun->capacity.bshift = 0;
-               }
-       }
-}
-
-/*
- * The open funcion.
- * This is mostly needed to keep refcounting, but also to support
- * media checks on removable media drives.
- */
-static int ub_bd_open(struct block_device *bdev, fmode_t mode)
-{
-       struct ub_lun *lun = bdev->bd_disk->private_data;
-       struct ub_dev *sc = lun->udev;
-       unsigned long flags;
-       int rc;
-
-       spin_lock_irqsave(&ub_lock, flags);
-       if (atomic_read(&sc->poison)) {
-               spin_unlock_irqrestore(&ub_lock, flags);
-               return -ENXIO;
-       }
-       sc->openc++;
-       spin_unlock_irqrestore(&ub_lock, flags);
-
-       if (lun->removable || lun->readonly)
-               check_disk_change(bdev);
-
-       /*
-        * The sd.c considers ->media_present and ->changed not equivalent,
-        * under some pretty murky conditions (a failure of READ CAPACITY).
-        * We may need it one day.
-        */
-       if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) {
-               rc = -ENOMEDIUM;
-               goto err_open;
-       }
-
-       if (lun->readonly && (mode & FMODE_WRITE)) {
-               rc = -EROFS;
-               goto err_open;
-       }
-
-       return 0;
-
-err_open:
-       ub_put(sc);
-       return rc;
-}
-
-static int ub_bd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
-       int ret;
-
-       mutex_lock(&ub_mutex);
-       ret = ub_bd_open(bdev, mode);
-       mutex_unlock(&ub_mutex);
-
-       return ret;
-}
-
-
-/*
- */
-static int ub_bd_release(struct gendisk *disk, fmode_t mode)
-{
-       struct ub_lun *lun = disk->private_data;
-       struct ub_dev *sc = lun->udev;
-
-       mutex_lock(&ub_mutex);
-       ub_put(sc);
-       mutex_unlock(&ub_mutex);
-
-       return 0;
-}
-
-/*
- * The ioctl interface.
- */
-static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode,
-    unsigned int cmd, unsigned long arg)
-{
-       void __user *usermem = (void __user *) arg;
-       int ret;
-
-       mutex_lock(&ub_mutex);
-       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem);
-       mutex_unlock(&ub_mutex);
-
-       return ret;
-}
-
-/*
- * This is called by check_disk_change if we reported a media change.
- * The main onjective here is to discover the features of the media such as
- * the capacity, read-only status, etc. USB storage generally does not
- * need to be spun up, but if we needed it, this would be the place.
- *
- * This call can sleep.
- *
- * The return code is not used.
- */
-static int ub_bd_revalidate(struct gendisk *disk)
-{
-       struct ub_lun *lun = disk->private_data;
-
-       ub_revalidate(lun->udev, lun);
-
-       /* XXX Support sector size switching like in sr.c */
-       blk_queue_logical_block_size(disk->queue, lun->capacity.bsize);
-       set_capacity(disk, lun->capacity.nsec);
-       // set_disk_ro(sdkp->disk, lun->readonly);
-
-       return 0;
-}
-
-/*
- * The check is called by the block layer to verify if the media
- * is still available. It is supposed to be harmless, lightweight and
- * non-intrusive in case the media was not changed.
- *
- * This call can sleep.
- *
- * The return code is bool!
- */
-static unsigned int ub_bd_check_events(struct gendisk *disk,
-                                      unsigned int clearing)
-{
-       struct ub_lun *lun = disk->private_data;
-
-       if (!lun->removable)
-               return 0;
-
-       /*
-        * We clean checks always after every command, so this is not
-        * as dangerous as it looks. If the TEST_UNIT_READY fails here,
-        * the device is actually not ready with operator or software
-        * intervention required. One dangerous item might be a drive which
-        * spins itself down, and come the time to write dirty pages, this
-        * will fail, then block layer discards the data. Since we never
-        * spin drives up, such devices simply cannot be used with ub anyway.
-        */
-       if (ub_sync_tur(lun->udev, lun) != 0) {
-               lun->changed = 1;
-               return DISK_EVENT_MEDIA_CHANGE;
-       }
-
-       return lun->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static const struct block_device_operations ub_bd_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ub_bd_unlocked_open,
-       .release        = ub_bd_release,
-       .ioctl          = ub_bd_ioctl,
-       .check_events   = ub_bd_check_events,
-       .revalidate_disk = ub_bd_revalidate,
-};
-
-/*
- * Common ->done routine for commands executed synchronously.
- */
-static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
-{
-       struct completion *cop = cmd->back;
-       complete(cop);
-}
-
-/*
- * Test if the device has a check condition on it, synchronously.
- */
-static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
-{
-       struct ub_scsi_cmd *cmd;
-       enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) };
-       unsigned long flags;
-       struct completion compl;
-       int rc;
-
-       init_completion(&compl);
-
-       rc = -ENOMEM;
-       if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
-               goto err_alloc;
-
-       cmd->cdb[0] = TEST_UNIT_READY;
-       cmd->cdb_len = 6;
-       cmd->dir = UB_DIR_NONE;
-       cmd->state = UB_CMDST_INIT;
-       cmd->lun = lun;                 /* This may be NULL, but that's ok */
-       cmd->done = ub_probe_done;
-       cmd->back = &compl;
-
-       spin_lock_irqsave(sc->lock, flags);
-       cmd->tag = sc->tagcnt++;
-
-       rc = ub_submit_scsi(sc, cmd);
-       spin_unlock_irqrestore(sc->lock, flags);
-
-       if (rc != 0)
-               goto err_submit;
-
-       wait_for_completion(&compl);
-
-       rc = cmd->error;
-
-       if (rc == -EIO && cmd->key != 0)        /* Retries for benh's key */
-               rc = cmd->key;
-
-err_submit:
-       kfree(cmd);
-err_alloc:
-       return rc;
-}
-
-/*
- * Read the SCSI capacity synchronously (for probing).
- */
-static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
-    struct ub_capacity *ret)
-{
-       struct ub_scsi_cmd *cmd;
-       struct scatterlist *sg;
-       char *p;
-       enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
-       unsigned long flags;
-       unsigned int bsize, shift;
-       unsigned long nsec;
-       struct completion compl;
-       int rc;
-
-       init_completion(&compl);
-
-       rc = -ENOMEM;
-       if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
-               goto err_alloc;
-       p = (char *)cmd + sizeof(struct ub_scsi_cmd);
-
-       cmd->cdb[0] = 0x25;
-       cmd->cdb_len = 10;
-       cmd->dir = UB_DIR_READ;
-       cmd->state = UB_CMDST_INIT;
-       cmd->nsg = 1;
-       sg = &cmd->sgv[0];
-       sg_init_table(sg, UB_MAX_REQ_SG);
-       sg_set_page(sg, virt_to_page(p), 8, (unsigned long)p & (PAGE_SIZE-1));
-       cmd->len = 8;
-       cmd->lun = lun;
-       cmd->done = ub_probe_done;
-       cmd->back = &compl;
-
-       spin_lock_irqsave(sc->lock, flags);
-       cmd->tag = sc->tagcnt++;
-
-       rc = ub_submit_scsi(sc, cmd);
-       spin_unlock_irqrestore(sc->lock, flags);
-
-       if (rc != 0)
-               goto err_submit;
-
-       wait_for_completion(&compl);
-
-       if (cmd->error != 0) {
-               rc = -EIO;
-               goto err_read;
-       }
-       if (cmd->act_len != 8) {
-               rc = -EIO;
-               goto err_read;
-       }
-
-       /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */
-       nsec = be32_to_cpu(*(__be32 *)p) + 1;
-       bsize = be32_to_cpu(*(__be32 *)(p + 4));
-       switch (bsize) {
-       case 512:       shift = 0;      break;
-       case 1024:      shift = 1;      break;
-       case 2048:      shift = 2;      break;
-       case 4096:      shift = 3;      break;
-       default:
-               rc = -EDOM;
-               goto err_inv_bsize;
-       }
-
-       ret->bsize = bsize;
-       ret->bshift = shift;
-       ret->nsec = nsec << shift;
-       rc = 0;
-
-err_inv_bsize:
-err_read:
-err_submit:
-       kfree(cmd);
-err_alloc:
-       return rc;
-}
-
-/*
- */
-static void ub_probe_urb_complete(struct urb *urb)
-{
-       struct completion *cop = urb->context;
-       complete(cop);
-}
-
-static void ub_probe_timeout(unsigned long arg)
-{
-       struct completion *cop = (struct completion *) arg;
-       complete(cop);
-}
-
-/*
- * Reset with a Bulk reset.
- */
-static int ub_sync_reset(struct ub_dev *sc)
-{
-       int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
-       struct usb_ctrlrequest *cr;
-       struct completion compl;
-       struct timer_list timer;
-       int rc;
-
-       init_completion(&compl);
-
-       cr = &sc->work_cr;
-       cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-       cr->bRequest = US_BULK_RESET_REQUEST;
-       cr->wValue = cpu_to_le16(0);
-       cr->wIndex = cpu_to_le16(ifnum);
-       cr->wLength = cpu_to_le16(0);
-
-       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
-           (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
-               printk(KERN_WARNING
-                    "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc);
-               return rc;
-       }
-
-       init_timer(&timer);
-       timer.function = ub_probe_timeout;
-       timer.data = (unsigned long) &compl;
-       timer.expires = jiffies + UB_CTRL_TIMEOUT;
-       add_timer(&timer);
-
-       wait_for_completion(&compl);
-
-       del_timer_sync(&timer);
-       usb_kill_urb(&sc->work_urb);
-
-       return sc->work_urb.status;
-}
-
-/*
- * Get number of LUNs by the way of Bulk GetMaxLUN command.
- */
-static int ub_sync_getmaxlun(struct ub_dev *sc)
-{
-       int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
-       unsigned char *p;
-       enum { ALLOC_SIZE = 1 };
-       struct usb_ctrlrequest *cr;
-       struct completion compl;
-       struct timer_list timer;
-       int nluns;
-       int rc;
-
-       init_completion(&compl);
-
-       rc = -ENOMEM;
-       if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
-               goto err_alloc;
-       *p = 55;
-
-       cr = &sc->work_cr;
-       cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-       cr->bRequest = US_BULK_GET_MAX_LUN;
-       cr->wValue = cpu_to_le16(0);
-       cr->wIndex = cpu_to_le16(ifnum);
-       cr->wLength = cpu_to_le16(1);
-
-       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
-           (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
-               goto err_submit;
-
-       init_timer(&timer);
-       timer.function = ub_probe_timeout;
-       timer.data = (unsigned long) &compl;
-       timer.expires = jiffies + UB_CTRL_TIMEOUT;
-       add_timer(&timer);
-
-       wait_for_completion(&compl);
-
-       del_timer_sync(&timer);
-       usb_kill_urb(&sc->work_urb);
-
-       if ((rc = sc->work_urb.status) < 0)
-               goto err_io;
-
-       if (sc->work_urb.actual_length != 1) {
-               nluns = 0;
-       } else {
-               if ((nluns = *p) == 55) {
-                       nluns = 0;
-               } else {
-                       /* GetMaxLUN returns the maximum LUN number */
-                       nluns += 1;
-                       if (nluns > UB_MAX_LUNS)
-                               nluns = UB_MAX_LUNS;
-               }
-       }
-
-       kfree(p);
-       return nluns;
-
-err_io:
-err_submit:
-       kfree(p);
-err_alloc:
-       return rc;
-}
-
-/*
- * Clear initial stalls.
- */
-static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
-{
-       int endp;
-       struct usb_ctrlrequest *cr;
-       struct completion compl;
-       struct timer_list timer;
-       int rc;
-
-       init_completion(&compl);
-
-       endp = usb_pipeendpoint(stalled_pipe);
-       if (usb_pipein (stalled_pipe))
-               endp |= USB_DIR_IN;
-
-       cr = &sc->work_cr;
-       cr->bRequestType = USB_RECIP_ENDPOINT;
-       cr->bRequest = USB_REQ_CLEAR_FEATURE;
-       cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);
-       cr->wIndex = cpu_to_le16(endp);
-       cr->wLength = cpu_to_le16(0);
-
-       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
-           (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-
-       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
-               printk(KERN_WARNING
-                    "%s: Unable to submit a probe clear (%d)\n", sc->name, rc);
-               return rc;
-       }
-
-       init_timer(&timer);
-       timer.function = ub_probe_timeout;
-       timer.data = (unsigned long) &compl;
-       timer.expires = jiffies + UB_CTRL_TIMEOUT;
-       add_timer(&timer);
-
-       wait_for_completion(&compl);
-
-       del_timer_sync(&timer);
-       usb_kill_urb(&sc->work_urb);
-
-       usb_reset_endpoint(sc->dev, endp);
-
-       return 0;
-}
-
-/*
- * Get the pipe settings.
- */
-static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
-    struct usb_interface *intf)
-{
-       struct usb_host_interface *altsetting = intf->cur_altsetting;
-       struct usb_endpoint_descriptor *ep_in = NULL;
-       struct usb_endpoint_descriptor *ep_out = NULL;
-       struct usb_endpoint_descriptor *ep;
-       int i;
-
-       /*
-        * Find the endpoints we need.
-        * We are expecting a minimum of 2 endpoints - in and out (bulk).
-        * We will ignore any others.
-        */
-       for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
-               ep = &altsetting->endpoint[i].desc;
-
-               /* Is it a BULK endpoint? */
-               if (usb_endpoint_xfer_bulk(ep)) {
-                       /* BULK in or out? */
-                       if (usb_endpoint_dir_in(ep)) {
-                               if (ep_in == NULL)
-                                       ep_in = ep;
-                       } else {
-                               if (ep_out == NULL)
-                                       ep_out = ep;
-                       }
-               }
-       }
-
-       if (ep_in == NULL || ep_out == NULL) {
-               printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
-               return -ENODEV;
-       }
-
-       /* Calculate and store the pipe values */
-       sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0);
-       sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0);
-       sc->send_bulk_pipe = usb_sndbulkpipe(dev,
-               usb_endpoint_num(ep_out));
-       sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, 
-               usb_endpoint_num(ep_in));
-
-       return 0;
-}
-
-/*
- * Probing is done in the process context, which allows us to cheat
- * and not to build a state machine for the discovery.
- */
-static int ub_probe(struct usb_interface *intf,
-    const struct usb_device_id *dev_id)
-{
-       struct ub_dev *sc;
-       int nluns;
-       int rc;
-       int i;
-
-       if (usb_usual_check_type(dev_id, USB_US_TYPE_UB))
-               return -ENXIO;
-
-       rc = -ENOMEM;
-       if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
-               goto err_core;
-       sc->lock = ub_next_lock();
-       INIT_LIST_HEAD(&sc->luns);
-       usb_init_urb(&sc->work_urb);
-       tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
-       atomic_set(&sc->poison, 0);
-       INIT_WORK(&sc->reset_work, ub_reset_task);
-       init_waitqueue_head(&sc->reset_wait);
-
-       init_timer(&sc->work_timer);
-       sc->work_timer.data = (unsigned long) sc;
-       sc->work_timer.function = ub_urb_timeout;
-
-       ub_init_completion(&sc->work_done);
-       sc->work_done.done = 1;         /* A little yuk, but oh well... */
-
-       sc->dev = interface_to_usbdev(intf);
-       sc->intf = intf;
-       // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-       usb_set_intfdata(intf, sc);
-       usb_get_dev(sc->dev);
-       /*
-        * Since we give the interface struct to the block level through
-        * disk->driverfs_dev, we have to pin it. Otherwise, block_uevent
-        * oopses on close after a disconnect (kernels 2.6.16 and up).
-        */
-       usb_get_intf(sc->intf);
-
-       snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
-           sc->dev->bus->busnum, sc->dev->devnum);
-
-       /* XXX Verify that we can handle the device (from descriptors) */
-
-       if (ub_get_pipes(sc, sc->dev, intf) != 0)
-               goto err_dev_desc;
-
-       /*
-        * At this point, all USB initialization is done, do upper layer.
-        * We really hate halfway initialized structures, so from the
-        * invariants perspective, this ub_dev is fully constructed at
-        * this point.
-        */
-
-       /*
-        * This is needed to clear toggles. It is a problem only if we do
-        * `rmmod ub && modprobe ub` without disconnects, but we like that.
-        */
-#if 0 /* iPod Mini fails if we do this (big white iPod works) */
-       ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-       ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-#endif
-
-       /*
-        * The way this is used by the startup code is a little specific.
-        * A SCSI check causes a USB stall. Our common case code sees it
-        * and clears the check, after which the device is ready for use.
-        * But if a check was not present, any command other than
-        * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE).
-        *
-        * If we neglect to clear the SCSI check, the first real command fails
-        * (which is the capacity readout). We clear that and retry, but why
-        * causing spurious retries for no reason.
-        *
-        * Revalidation may start with its own TEST_UNIT_READY, but that one
-        * has to succeed, so we clear checks with an additional one here.
-        * In any case it's not our business how revaliadation is implemented.
-        */
-       for (i = 0; i < 3; i++) {  /* Retries for the schwag key from KS'04 */
-               if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
-               if (rc != 0x6) break;
-               msleep(10);
-       }
-
-       nluns = 1;
-       for (i = 0; i < 3; i++) {
-               if ((rc = ub_sync_getmaxlun(sc)) < 0)
-                       break;
-               if (rc != 0) {
-                       nluns = rc;
-                       break;
-               }
-               msleep(100);
-       }
-
-       for (i = 0; i < nluns; i++) {
-               ub_probe_lun(sc, i);
-       }
-       return 0;
-
-err_dev_desc:
-       usb_set_intfdata(intf, NULL);
-       usb_put_intf(sc->intf);
-       usb_put_dev(sc->dev);
-       kfree(sc);
-err_core:
-       return rc;
-}
-
-static int ub_probe_lun(struct ub_dev *sc, int lnum)
-{
-       struct ub_lun *lun;
-       struct request_queue *q;
-       struct gendisk *disk;
-       int rc;
-
-       rc = -ENOMEM;
-       if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
-               goto err_alloc;
-       lun->num = lnum;
-
-       rc = -ENOSR;
-       if ((lun->id = ub_id_get()) == -1)
-               goto err_id;
-
-       lun->udev = sc;
-
-       snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
-           lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
-
-       lun->removable = 1;             /* XXX Query this from the device */
-       lun->changed = 1;               /* ub_revalidate clears only */
-       ub_revalidate(sc, lun);
-
-       rc = -ENOMEM;
-       if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
-               goto err_diskalloc;
-
-       sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
-       disk->major = UB_MAJOR;
-       disk->first_minor = lun->id * UB_PARTS_PER_LUN;
-       disk->fops = &ub_bd_fops;
-       disk->private_data = lun;
-       disk->driverfs_dev = &sc->intf->dev;
-
-       rc = -ENOMEM;
-       if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
-               goto err_blkqinit;
-
-       disk->queue = q;
-
-       blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
-       blk_queue_max_segments(q, UB_MAX_REQ_SG);
-       blk_queue_segment_boundary(q, 0xffffffff);      /* Dubious. */
-       blk_queue_max_hw_sectors(q, UB_MAX_SECTORS);
-       blk_queue_logical_block_size(q, lun->capacity.bsize);
-
-       lun->disk = disk;
-       q->queuedata = lun;
-       list_add(&lun->link, &sc->luns);
-
-       set_capacity(disk, lun->capacity.nsec);
-       if (lun->removable)
-               disk->flags |= GENHD_FL_REMOVABLE;
-
-       add_disk(disk);
-
-       return 0;
-
-err_blkqinit:
-       put_disk(disk);
-err_diskalloc:
-       ub_id_put(lun->id);
-err_id:
-       kfree(lun);
-err_alloc:
-       return rc;
-}
-
-static void ub_disconnect(struct usb_interface *intf)
-{
-       struct ub_dev *sc = usb_get_intfdata(intf);
-       struct ub_lun *lun;
-       unsigned long flags;
-
-       /*
-        * Prevent ub_bd_release from pulling the rug from under us.
-        * XXX This is starting to look like a kref.
-        * XXX Why not to take this ref at probe time?
-        */
-       spin_lock_irqsave(&ub_lock, flags);
-       sc->openc++;
-       spin_unlock_irqrestore(&ub_lock, flags);
-
-       /*
-        * Fence stall clearings, operations triggered by unlinkings and so on.
-        * We do not attempt to unlink any URBs, because we do not trust the
-        * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
-        */
-       atomic_set(&sc->poison, 1);
-
-       /*
-        * Wait for reset to end, if any.
-        */
-       wait_event(sc->reset_wait, !sc->reset);
-
-       /*
-        * Blow away queued commands.
-        *
-        * Actually, this never works, because before we get here
-        * the HCD terminates outstanding URB(s). It causes our
-        * SCSI command queue to advance, commands fail to submit,
-        * and the whole queue drains. So, we just use this code to
-        * print warnings.
-        */
-       spin_lock_irqsave(sc->lock, flags);
-       {
-               struct ub_scsi_cmd *cmd;
-               int cnt = 0;
-               while ((cmd = ub_cmdq_peek(sc)) != NULL) {
-                       cmd->error = -ENOTCONN;
-                       cmd->state = UB_CMDST_DONE;
-                       ub_cmdq_pop(sc);
-                       (*cmd->done)(sc, cmd);
-                       cnt++;
-               }
-               if (cnt != 0) {
-                       printk(KERN_WARNING "%s: "
-                           "%d was queued after shutdown\n", sc->name, cnt);
-               }
-       }
-       spin_unlock_irqrestore(sc->lock, flags);
-
-       /*
-        * Unregister the upper layer.
-        */
-       list_for_each_entry(lun, &sc->luns, link) {
-               del_gendisk(lun->disk);
-               /*
-                * I wish I could do:
-                *    queue_flag_set(QUEUE_FLAG_DEAD, q);
-                * As it is, we rely on our internal poisoning and let
-                * the upper levels to spin furiously failing all the I/O.
-                */
-       }
-
-       /*
-        * Testing for -EINPROGRESS is always a bug, so we are bending
-        * the rules a little.
-        */
-       spin_lock_irqsave(sc->lock, flags);
-       if (sc->work_urb.status == -EINPROGRESS) {      /* janitors: ignore */
-               printk(KERN_WARNING "%s: "
-                   "URB is active after disconnect\n", sc->name);
-       }
-       spin_unlock_irqrestore(sc->lock, flags);
-
-       /*
-        * There is virtually no chance that other CPU runs a timeout so long
-        * after ub_urb_complete should have called del_timer, but only if HCD
-        * didn't forget to deliver a callback on unlink.
-        */
-       del_timer_sync(&sc->work_timer);
-
-       /*
-        * At this point there must be no commands coming from anyone
-        * and no URBs left in transit.
-        */
-
-       ub_put(sc);
-}
-
-static struct usb_driver ub_driver = {
-       .name =         "ub",
-       .probe =        ub_probe,
-       .disconnect =   ub_disconnect,
-       .id_table =     ub_usb_ids,
-       .pre_reset =    ub_pre_reset,
-       .post_reset =   ub_post_reset,
-};
-
-static int __init ub_init(void)
-{
-       int rc;
-       int i;
-
-       pr_info("'Low Performance USB Block' driver is deprecated. "
-                       "Please switch to usb-storage\n");
-       for (i = 0; i < UB_QLOCK_NUM; i++)
-               spin_lock_init(&ub_qlockv[i]);
-
-       if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
-               goto err_regblkdev;
-
-       if ((rc = usb_register(&ub_driver)) != 0)
-               goto err_register;
-
-       usb_usual_set_present(USB_US_TYPE_UB);
-       return 0;
-
-err_register:
-       unregister_blkdev(UB_MAJOR, DRV_NAME);
-err_regblkdev:
-       return rc;
-}
-
-static void __exit ub_exit(void)
-{
-       usb_deregister(&ub_driver);
-
-       unregister_blkdev(UB_MAJOR, DRV_NAME);
-       usb_usual_clear_present(USB_US_TYPE_UB);
-}
-
-module_init(ub_init);
-module_exit(ub_exit);
-
-MODULE_LICENSE("GPL");
index 10308cd8a7ed2276f146c86c752383de5517464a..11f36e5021367d7dd7c2b0794241154a0544ad0a 100644 (file)
@@ -79,6 +79,7 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x0CF3, 0xE004) },
        { USB_DEVICE(0x0930, 0x0219) },
+       { USB_DEVICE(0x0489, 0xe057) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -104,6 +105,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
index e272214110365510fcfcbb6f6f3f75778f65ed46..cef3bac1a543d83113b54939585f807748accaf7 100644 (file)
@@ -98,6 +98,7 @@ static struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x0a5c, 0x21e6) },
        { USB_DEVICE(0x0a5c, 0x21e8) },
        { USB_DEVICE(0x0a5c, 0x21f3) },
+       { USB_DEVICE(0x0a5c, 0x21f4) },
        { USB_DEVICE(0x413c, 0x8197) },
 
        /* Foxconn - Hon Hai */
@@ -133,6 +134,7 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
index 57226424690cb1f05ebfa560f776aa8adf967c55..6ec0fff79bc2f6dfce8eb2be78019dca56bb18e6 100644 (file)
@@ -64,6 +64,7 @@
 #define I830_PTE_SYSTEM_CACHED  0x00000006
 /* GT PTE cache control fields */
 #define GEN6_PTE_UNCACHED      0x00000002
+#define HSW_PTE_UNCACHED       0x00000000
 #define GEN6_PTE_LLC           0x00000004
 #define GEN6_PTE_LLC_MLC       0x00000006
 #define GEN6_PTE_GFDT          0x00000008
 #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG         0x016A
 #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_HB              0x0F00 /* VLV1 */
 #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG              0x0F30
-#define PCI_DEVICE_ID_INTEL_HASWELL_HB                         0x0400 /* Desktop */
+#define PCI_DEVICE_ID_INTEL_HASWELL_HB                 0x0400 /* Desktop */
 #define PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG           0x0402
 #define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG           0x0412
-#define PCI_DEVICE_ID_INTEL_HASWELL_M_HB                       0x0404 /* Mobile */
+#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_PLUS_IG      0x0422
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_HB               0x0404 /* Mobile */
 #define PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG           0x0406
 #define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG           0x0416
-#define PCI_DEVICE_ID_INTEL_HASWELL_S_HB                       0x0408 /* Server */
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_PLUS_IG      0x0426
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_HB               0x0408 /* Server */
 #define PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG           0x040a
 #define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG           0x041a
-#define PCI_DEVICE_ID_INTEL_HASWELL_SDV                0x0c16 /* SDV */
-#define PCI_DEVICE_ID_INTEL_HASWELL_E_HB                       0x0c04
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_PLUS_IG      0x042a
+#define PCI_DEVICE_ID_INTEL_HASWELL_E_HB               0x0c04
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT1_IG       0x0C02
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_IG       0x0C12
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_PLUS_IG  0x0C22
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT1_IG       0x0C06
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_IG       0x0C16
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_PLUS_IG  0x0C26
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT1_IG       0x0C0A
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_IG       0x0C1A
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_PLUS_IG  0x0C2A
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT1_IG       0x0A02
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_IG       0x0A12
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_PLUS_IG  0x0A22
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT1_IG       0x0A06
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_IG       0x0A16
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_PLUS_IG  0x0A26
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT1_IG       0x0A0A
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_IG       0x0A1A
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_PLUS_IG  0x0A2A
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT1_IG       0x0D12
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_IG       0x0D22
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_PLUS_IG  0x0D32
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT1_IG       0x0D16
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_IG       0x0D26
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_PLUS_IG  0x0D36
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT1_IG       0x0D1A
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_IG       0x0D2A
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_PLUS_IG  0x0D3A
 
 #endif
index 9ed92ef5829b8f54bb318e0b6510e59c2b40e939..58e32f7c322956209bd3a63ce16f5ce16135c59b 100644 (file)
@@ -1156,6 +1156,30 @@ static bool gen6_check_flags(unsigned int flags)
        return true;
 }
 
+static void haswell_write_entry(dma_addr_t addr, unsigned int entry,
+                               unsigned int flags)
+{
+       unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
+       unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
+       u32 pte_flags;
+
+       if (type_mask == AGP_USER_MEMORY)
+               pte_flags = HSW_PTE_UNCACHED | I810_PTE_VALID;
+       else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
+               pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
+               if (gfdt)
+                       pte_flags |= GEN6_PTE_GFDT;
+       } else { /* set 'normal'/'cached' to LLC by default */
+               pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
+               if (gfdt)
+                       pte_flags |= GEN6_PTE_GFDT;
+       }
+
+       /* gen6 has bit11-4 for physical addr bit39-32 */
+       addr |= (addr >> 28) & 0xff0;
+       writel(addr | pte_flags, intel_private.gtt + entry);
+}
+
 static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
                             unsigned int flags)
 {
@@ -1382,6 +1406,15 @@ static const struct intel_gtt_driver sandybridge_gtt_driver = {
        .check_flags = gen6_check_flags,
        .chipset_flush = i9xx_chipset_flush,
 };
+static const struct intel_gtt_driver haswell_gtt_driver = {
+       .gen = 6,
+       .setup = i9xx_setup,
+       .cleanup = gen6_cleanup,
+       .write_entry = haswell_write_entry,
+       .dma_mask_size = 40,
+       .check_flags = gen6_check_flags,
+       .chipset_flush = i9xx_chipset_flush,
+};
 static const struct intel_gtt_driver valleyview_gtt_driver = {
        .gen = 7,
        .setup = i9xx_setup,
@@ -1499,19 +1532,77 @@ static const struct intel_gtt_driver_description {
        { PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG,
            "ValleyView", &valleyview_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG,
-           "Haswell", &sandybridge_gtt_driver },
+           "Haswell", &haswell_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG,
-           "Haswell", &sandybridge_gtt_driver },
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG,
-           "Haswell", &sandybridge_gtt_driver },
+           "Haswell", &haswell_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG,
-           "Haswell", &sandybridge_gtt_driver },
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG,
-           "Haswell", &sandybridge_gtt_driver },
+           "Haswell", &haswell_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG,
-           "Haswell", &sandybridge_gtt_driver },
-       { PCI_DEVICE_ID_INTEL_HASWELL_SDV,
-           "Haswell", &sandybridge_gtt_driver },
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT1_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_IG,
+           "Haswell", &haswell_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_PLUS_IG,
+           "Haswell", &haswell_gtt_driver },
        { 0, NULL, NULL }
 };
 
index d706bd0e9e800fd791e198b4b573b64296f3f40e..4fbdceb6f773d7e45189a22347668c34a0b52c63 100644 (file)
@@ -160,7 +160,7 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int omap_rng_suspend(struct device *dev)
 {
index 89682fa8801ea0fafb1f8e9556ca148ab0b4f6f9..c4be3519a587c4fe33c3a14be17ba72e6067d9a0 100644 (file)
@@ -807,6 +807,7 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 #endif
 
+#ifdef CONFIG_PM_SLEEP
 static int tpm_tis_resume(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
@@ -816,6 +817,7 @@ static int tpm_tis_resume(struct device *dev)
 
        return tpm_pm_resume(dev);
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
 
index 540795cd0760b434e53c0b10afd41d295892c836..d9279385304d8b86fff47d58f3b623b0c804a046 100644 (file)
@@ -53,7 +53,7 @@ static struct cs5535_mfgpt_timer *cs5535_event_clock;
 #define MFGPT_PERIODIC (MFGPT_HZ / HZ)
 
 /*
- * The MFPGT timers on the CS5536 provide us with suitable timers to use
+ * The MFGPT timers on the CS5536 provide us with suitable timers to use
  * as clock event sources - not as good as a HPET or APIC, but certainly
  * better than the PIT.  This isn't a general purpose MFGPT driver, but
  * a simplified one designed specifically to act as a clock event source.
@@ -144,7 +144,7 @@ static int __init cs5535_mfgpt_init(void)
 
        timer = cs5535_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
        if (!timer) {
-               printk(KERN_ERR DRV_NAME ": Could not allocate MFPGT timer\n");
+               printk(KERN_ERR DRV_NAME ": Could not allocate MFGPT timer\n");
                return -ENODEV;
        }
        cs5535_event_clock = timer;
index cdc02ac8f41a7ff5d3f121e2b0927fd8bf99ae7a..503996a94a6af3d4f41292794c14f261ada96ae1 100644 (file)
@@ -454,6 +454,7 @@ static int __init pcc_cpufreq_probe(void)
                                        mem_resource->address_length);
        if (pcch_virt_addr == NULL) {
                pr_debug("probe: could not map shared mem region\n");
+               ret = -ENOMEM;
                goto out_free;
        }
        pcch_hdr = pcch_virt_addr;
index 2c9bf2692232e51a66e5455368d9881383ccfc2f..3265844839bfe9c79ef8849705262a52d16cc4e1 100644 (file)
@@ -678,10 +678,22 @@ static int cpuidle_coupled_cpu_notify(struct notifier_block *nb,
        int cpu = (unsigned long)hcpu;
        struct cpuidle_device *dev;
 
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+       case CPU_DOWN_PREPARE:
+       case CPU_ONLINE:
+       case CPU_DEAD:
+       case CPU_UP_CANCELED:
+       case CPU_DOWN_FAILED:
+               break;
+       default:
+               return NOTIFY_OK;
+       }
+
        mutex_lock(&cpuidle_lock);
 
        dev = per_cpu(cpuidle_devices, cpu);
-       if (!dev->coupled)
+       if (!dev || !dev->coupled)
                goto out;
 
        switch (action & ~CPU_TASKS_FROZEN) {
index fcfeb3cd8d3170aff7c30d6d151a0e7e15ecd968..5084975d793cd25949e62ae68f5932bd3c456763 100644 (file)
@@ -172,7 +172,8 @@ struct imxdma_engine {
        struct device_dma_parameters    dma_parms;
        struct dma_device               dma_device;
        void __iomem                    *base;
-       struct clk                      *dma_clk;
+       struct clk                      *dma_ahb;
+       struct clk                      *dma_ipg;
        spinlock_t                      lock;
        struct imx_dma_2d_config        slots_2d[IMX_DMA_2D_SLOTS];
        struct imxdma_channel           channel[IMX_DMA_CHANNELS];
@@ -976,10 +977,20 @@ static int __init imxdma_probe(struct platform_device *pdev)
                return 0;
        }
 
-       imxdma->dma_clk = clk_get(NULL, "dma");
-       if (IS_ERR(imxdma->dma_clk))
-               return PTR_ERR(imxdma->dma_clk);
-       clk_enable(imxdma->dma_clk);
+       imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(imxdma->dma_ipg)) {
+               ret = PTR_ERR(imxdma->dma_ipg);
+               goto err_clk;
+       }
+
+       imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(imxdma->dma_ahb)) {
+               ret = PTR_ERR(imxdma->dma_ahb);
+               goto err_clk;
+       }
+
+       clk_prepare_enable(imxdma->dma_ipg);
+       clk_prepare_enable(imxdma->dma_ahb);
 
        /* reset DMA module */
        imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR);
@@ -988,16 +999,14 @@ static int __init imxdma_probe(struct platform_device *pdev)
                ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma);
                if (ret) {
                        dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
-                       kfree(imxdma);
-                       return ret;
+                       goto err_enable;
                }
 
                ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma);
                if (ret) {
                        dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
                        free_irq(MX1_DMA_INT, NULL);
-                       kfree(imxdma);
-                       return ret;
+                       goto err_enable;
                }
        }
 
@@ -1094,7 +1103,10 @@ err_init:
                free_irq(MX1_DMA_INT, NULL);
                free_irq(MX1_DMA_ERR, NULL);
        }
-
+err_enable:
+       clk_disable_unprepare(imxdma->dma_ipg);
+       clk_disable_unprepare(imxdma->dma_ahb);
+err_clk:
        kfree(imxdma);
        return ret;
 }
@@ -1114,7 +1126,9 @@ static int __exit imxdma_remove(struct platform_device *pdev)
                free_irq(MX1_DMA_ERR, NULL);
        }
 
-        kfree(imxdma);
+       clk_disable_unprepare(imxdma->dma_ipg);
+       clk_disable_unprepare(imxdma->dma_ahb);
+       kfree(imxdma);
 
         return 0;
 }
index d52dbc6c54abdb346278b65bfbd8715f317d3e58..24acd711e0326852e2bf97bce308fb1fe272cea6 100644 (file)
@@ -1119,15 +1119,21 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
 static int tegra_dma_alloc_chan_resources(struct dma_chan *dc)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+       struct tegra_dma *tdma = tdc->tdma;
+       int ret;
 
        dma_cookie_init(&tdc->dma_chan);
        tdc->config_init = false;
-       return 0;
+       ret = clk_prepare_enable(tdma->dma_clk);
+       if (ret < 0)
+               dev_err(tdc2dev(tdc), "clk_prepare_enable failed: %d\n", ret);
+       return ret;
 }
 
 static void tegra_dma_free_chan_resources(struct dma_chan *dc)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+       struct tegra_dma *tdma = tdc->tdma;
 
        struct tegra_dma_desc *dma_desc;
        struct tegra_dma_sg_req *sg_req;
@@ -1163,6 +1169,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
                list_del(&sg_req->node);
                kfree(sg_req);
        }
+       clk_disable_unprepare(tdma->dma_clk);
 }
 
 /* Tegra20 specific DMA controller information */
@@ -1255,6 +1262,13 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev)
                }
        }
 
+       /* Enable clock before accessing registers */
+       ret = clk_prepare_enable(tdma->dma_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+               goto err_pm_disable;
+       }
+
        /* Reset DMA controller */
        tegra_periph_reset_assert(tdma->dma_clk);
        udelay(2);
@@ -1265,6 +1279,8 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev)
        tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0);
        tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul);
 
+       clk_disable_unprepare(tdma->dma_clk);
+
        INIT_LIST_HEAD(&tdma->dma_dev.channels);
        for (i = 0; i < cdata->nr_channels; i++) {
                struct tegra_dma_channel *tdc = &tdma->channels[i];
index fe3db45fa83c13604db19590cb29546dc38efae1..3cc152e690b06087c8374bf35cb72106f9bfde32 100644 (file)
@@ -107,7 +107,8 @@ static int __devinit gpio_extcon_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
+       ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
+                                   pdev->name);
        if (ret < 0)
                goto err;
 
index 150d9768811d4a09d30cef2ca9b69bdaf3c57275..ae37181798b3c979d9ce423a437f7ba09511166a 100644 (file)
@@ -266,7 +266,7 @@ static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
        return 0;
 }
 
-static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
+static void em_gio_irq_domain_cleanup(struct em_gio_priv *p)
 {
        struct gpio_em_config *pdata = p->pdev->dev.platform_data;
 
index a1c8754f52cf1b523c3da1bb9e572dc084ddde0b..202a99207b7d40c1a0e98dbe728cb7f782704a0d 100644 (file)
@@ -339,7 +339,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        resource_size_t start, len;
        struct lnw_gpio *lnw;
        u32 gpio_base;
-       int retval = 0;
+       int retval;
        int ngpio = id->driver_data;
 
        retval = pci_enable_device(pdev);
@@ -357,6 +357,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        base = ioremap_nocache(start, len);
        if (!base) {
                dev_err(&pdev->dev, "error mapping bar1\n");
+               retval = -EFAULT;
                goto err3;
        }
        gpio_base = *((u32 *)base + 1);
@@ -381,8 +382,10 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
 
        lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
                                            &lnw_gpio_irq_ops, lnw);
-       if (!lnw->domain)
+       if (!lnw->domain) {
+               retval = -ENOMEM;
                goto err3;
+       }
 
        lnw->reg_base = base;
        lnw->chip.label = dev_name(&pdev->dev);
index 71a838f44501065b76e6253a3780959f15c85e0b..b38986285868ab96151c2c522463ccfb377aeae1 100644 (file)
@@ -99,7 +99,7 @@ static int msic_gpio_to_oreg(unsigned offset)
        if (offset < 20)
                return INTEL_MSIC_GPIO0HV0CTLO - offset + 16;
 
-       return INTEL_MSIC_GPIO1HV0CTLO + offset + 20;
+       return INTEL_MSIC_GPIO1HV0CTLO - offset + 20;
 }
 
 static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
index 4db460b6ecf7dbf1ffe7bfd14a1361d271609667..80f44bb64a871835b9cdf59561d8bff90d03126d 100644 (file)
@@ -465,9 +465,8 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
                goto out_iounmap;
 
        port->bgc.gc.to_irq = mxc_gpio_to_irq;
-       port->bgc.gc.base = pdev->id * 32;
-       port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir);
-       port->bgc.data = port->bgc.read_reg(port->bgc.reg_set);
+       port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
+                                            pdev->id * 32;
 
        err = gpiochip_add(&port->bgc.gc);
        if (err)
index 58a6a63a6ece65ed9de822449ee0d53cd41e66eb..9cac88a65f78402e2a45b919799576810d9ab9fd 100644 (file)
@@ -62,6 +62,7 @@ int pxa_last_gpio;
 
 #ifdef CONFIG_OF
 static struct irq_domain *domain;
+static struct device_node *pxa_gpio_of_node;
 #endif
 
 struct pxa_gpio_chip {
@@ -277,6 +278,24 @@ static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                                (value ? GPSR_OFFSET : GPCR_OFFSET));
 }
 
+#ifdef CONFIG_OF_GPIO
+static int pxa_gpio_of_xlate(struct gpio_chip *gc,
+                            const struct of_phandle_args *gpiospec,
+                            u32 *flags)
+{
+       if (gpiospec->args[0] > pxa_last_gpio)
+               return -EINVAL;
+
+       if (gc != &pxa_gpio_chips[gpiospec->args[0] / 32].chip)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[1];
+
+       return gpiospec->args[0] % 32;
+}
+#endif
+
 static int __devinit pxa_init_gpio_chip(int gpio_end,
                                        int (*set_wake)(unsigned int, unsigned int))
 {
@@ -304,6 +323,11 @@ static int __devinit pxa_init_gpio_chip(int gpio_end,
                c->get = pxa_gpio_get;
                c->set = pxa_gpio_set;
                c->to_irq = pxa_gpio_to_irq;
+#ifdef CONFIG_OF_GPIO
+               c->of_node = pxa_gpio_of_node;
+               c->of_xlate = pxa_gpio_of_xlate;
+               c->of_gpio_n_cells = 2;
+#endif
 
                /* number of GPIOs on last bank may be less than 32 */
                c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
@@ -488,6 +512,7 @@ static int pxa_gpio_nums(void)
        return count;
 }
 
+#ifdef CONFIG_OF
 static struct of_device_id pxa_gpio_dt_ids[] = {
        { .compatible = "mrvl,pxa-gpio" },
        { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
@@ -505,9 +530,9 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
 
 const struct irq_domain_ops pxa_irq_domain_ops = {
        .map    = pxa_irq_domain_map,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
-#ifdef CONFIG_OF
 static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
 {
        int ret, nr_banks, nr_gpios, irq_base;
@@ -545,6 +570,7 @@ static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
        }
        domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
                                       &pxa_irq_domain_ops, NULL);
+       pxa_gpio_of_node = np;
        return 0;
 err:
        iounmap(gpio_reg_base);
@@ -653,7 +679,7 @@ static struct platform_driver pxa_gpio_driver = {
        .probe          = pxa_gpio_probe,
        .driver         = {
                .name   = "pxa-gpio",
-               .of_match_table = pxa_gpio_dt_ids,
+               .of_match_table = of_match_ptr(pxa_gpio_dt_ids),
        },
 };
 
index 92f7b2bb79d40ccf277d19a4d234a53fd8c98d83..ba126cc04073e04c0d304bd8b6cbbd455d3d1d67 100644 (file)
@@ -2452,12 +2452,6 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = {
                        .ngpio  = EXYNOS5_GPIO_C3_NR,
                        .label  = "GPC3",
                },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC4(0),
-                       .ngpio  = EXYNOS5_GPIO_C4_NR,
-                       .label  = "GPC4",
-               },
        }, {
                .chip   = {
                        .base   = EXYNOS5_GPD0(0),
@@ -2512,6 +2506,12 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = {
                        .ngpio  = EXYNOS5_GPIO_Y6_NR,
                        .label  = "GPY6",
                },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC4(0),
+                       .ngpio  = EXYNOS5_GPIO_C4_NR,
+                       .label  = "GPC4",
+               },
        }, {
                .config = &samsung_gpio_cfgs[9],
                .irq_base = IRQ_EINT(0),
@@ -2836,7 +2836,7 @@ static __init void exynos5_gpiolib_init(void)
        }
 
        /* need to set base address for gpc4 */
-       exynos5_gpios_1[11].base = gpio_base1 + 0x2E0;
+       exynos5_gpios_1[20].base = gpio_base1 + 0x2E0;
 
        /* need to set base address for gpx */
        chip = &exynos5_gpios_1[21];
index 424dce8e3f30107ce2e9b5eb9b5d2bb394164cf9..8707d4572a06bfee4713fab5b521cd58f220aefa 100644 (file)
@@ -241,7 +241,8 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
                        break;
 
                default:
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto err_sch_gpio_core;
        }
 
        sch_gpio_core.dev = &pdev->dev;
index 23120c00a88175db9c74d4c33bff8a4d9e324fdc..90e28081712dbd7c68343f88bd10b468c10f604a 100644 (file)
@@ -22,6 +22,7 @@ menuconfig DRM
 config DRM_USB
        tristate
        depends on DRM
+       depends on USB_ARCH_HAS_HCD
        select USB
 
 config DRM_KMS_HELPER
index 66d4a28ad5a23fc2cf4b7b745091296444e287b1..0303935d10e2ca45165509a7e9e8165962c99774 100644 (file)
@@ -119,7 +119,7 @@ static int edid_load(struct drm_connector *connector, char *name,
 {
        const struct firmware *fw;
        struct platform_device *pdev;
-       u8 *fwdata = NULL, *edid;
+       u8 *fwdata = NULL, *edid, *new_edid;
        int fwsize, expected;
        int builtin = 0, err = 0;
        int i, valid_extensions = 0;
@@ -195,12 +195,14 @@ static int edid_load(struct drm_connector *connector, char *name,
                    "\"%s\" for connector \"%s\"\n", valid_extensions,
                    edid[0x7e], name, connector_name);
                edid[0x7e] = valid_extensions;
-               edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
+               new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
                    GFP_KERNEL);
-               if (edid == NULL) {
+               if (new_edid == NULL) {
                        err = -ENOMEM;
+                       kfree(edid);
                        goto relfw_out;
                }
+               edid = new_edid;
        }
 
        connector->display_info.raw_edid = edid;
index b7adb4a967fd02b80eee0f0bd6e78b2d76c7e9b1..28637c181b15045fb0d2e9235a5d653ee0204f92 100644 (file)
@@ -706,9 +706,6 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
        p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
        p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
        p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
-
-       p->crtc_hadjusted = false;
-       p->crtc_vadjusted = false;
 }
 EXPORT_SYMBOL(drm_mode_set_crtcinfo);
 
index 371c695322d9f8f1736510eeaeeab7ea153cbe9e..da457b18eaaf601c7f4aa7ebec6b294355bbcc41 100644 (file)
@@ -89,7 +89,7 @@ static const struct file_operations drm_proc_fops = {
  * Create a given set of proc files represented by an array of
  * gdm_proc_lists in the given root directory.
  */
-int drm_proc_create_files(struct drm_info_list *files, int count,
+static int drm_proc_create_files(struct drm_info_list *files, int count,
                          struct proc_dir_entry *root, struct drm_minor *minor)
 {
        struct drm_device *dev = minor->dev;
@@ -172,7 +172,7 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
        return 0;
 }
 
-int drm_proc_remove_files(struct drm_info_list *files, int count,
+static int drm_proc_remove_files(struct drm_info_list *files, int count,
                          struct drm_minor *minor)
 {
        struct list_head *pos, *q;
index ed22612bc8477a3aa6dc95cfc2e058f7071c4878..a24ffbe97c01cffd8a8fa5093a5ba15ff04db30b 100644 (file)
@@ -346,11 +346,40 @@ static const struct pci_device_id pciidlist[] = {         /* aka */
        INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
        INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
        INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
+       INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT2 desktop */
        INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
        INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
+       INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT2 server */
        INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
        INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
-       INTEL_VGA_DEVICE(0x0c16, &intel_haswell_d_info), /* SDV */
+       INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */
+       INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */
+       INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */
+       INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT2 desktop */
+       INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */
+       INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */
+       INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT2 server */
+       INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */
+       INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */
+       INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT2 mobile */
+       INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */
+       INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */
+       INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT2 desktop */
+       INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */
+       INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */
+       INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT2 server */
+       INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */
+       INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */
+       INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */
+       INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT1 desktop */
+       INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */
+       INTEL_VGA_DEVICE(0x0D32, &intel_haswell_d_info), /* CRW GT2 desktop */
+       INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT1 server */
+       INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */
+       INTEL_VGA_DEVICE(0x0D3A, &intel_haswell_d_info), /* CRW GT2 server */
+       INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT1 mobile */
+       INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */
+       INTEL_VGA_DEVICE(0x0D36, &intel_haswell_m_info), /* CRW GT2 mobile */
        INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info),
        INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info),
        INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info),
index 5c4657a54f977689c1668a9a70b8a8f6e39743c9..489e2b162b2736b4fc3d43e171ebddb25c66b12e 100644 (file)
@@ -2365,6 +2365,10 @@ int i915_gpu_idle(struct drm_device *dev)
 
        /* Flush everything onto the inactive list. */
        for_each_ring(ring, dev_priv, i) {
+               ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID);
+               if (ret)
+                       return ret;
+
                ret = i915_ring_idle(ring);
                if (ret)
                        return ret;
@@ -2372,10 +2376,6 @@ int i915_gpu_idle(struct drm_device *dev)
                /* Is the device fubar? */
                if (WARN_ON(!list_empty(&ring->gpu_write_list)))
                        return -EBUSY;
-
-               ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID);
-               if (ret)
-                       return ret;
        }
 
        return 0;
index da8b01fb1bf8dbbc1cbe34457bb67f4ff3fe28eb..a9d58d72bb4da2215592bb8ba6554e9835fb48cf 100644 (file)
@@ -451,7 +451,6 @@ int i915_switch_context(struct intel_ring_buffer *ring,
        struct drm_i915_file_private *file_priv = NULL;
        struct i915_hw_context *to;
        struct drm_i915_gem_object *from_obj = ring->last_context_obj;
-       int ret;
 
        if (dev_priv->hw_contexts_disabled)
                return 0;
index 5af631e788c8e6d39118eac4483ff9e2a40f329d..ff2819ea08130fb98da5f67550a18d9ca3c5974d 100644 (file)
@@ -291,6 +291,16 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        target_i915_obj = to_intel_bo(target_obj);
        target_offset = target_i915_obj->gtt_offset;
 
+       /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
+        * pipe_control writes because the gpu doesn't properly redirect them
+        * through the ppgtt for non_secure batchbuffers. */
+       if (unlikely(IS_GEN6(dev) &&
+           reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
+           !target_i915_obj->has_global_gtt_mapping)) {
+               i915_gem_gtt_bind_object(target_i915_obj,
+                                        target_i915_obj->cache_level);
+       }
+
        /* The target buffer should have appeared before us in the
         * exec_object list, so it should have a GTT space bound by now.
         */
@@ -399,16 +409,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                io_mapping_unmap_atomic(reloc_page);
        }
 
-       /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
-        * pipe_control writes because the gpu doesn't properly redirect them
-        * through the ppgtt for non_secure batchbuffers. */
-       if (unlikely(IS_GEN6(dev) &&
-           reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
-           !target_i915_obj->has_global_gtt_mapping)) {
-               i915_gem_gtt_bind_object(target_i915_obj,
-                                        target_i915_obj->cache_level);
-       }
-
        /* and update the user's relocation entry */
        reloc->presumed_offset = target_offset;
 
index 9fd25a435536121a33651c66ac00f5999c81f6f4..d9a5372ec56f84a76f1e270e1edeb704462ed2e8 100644 (file)
@@ -261,7 +261,10 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
                pte_flags |= GEN6_PTE_CACHE_LLC;
                break;
        case I915_CACHE_NONE:
-               pte_flags |= GEN6_PTE_UNCACHED;
+               if (IS_HASWELL(dev))
+                       pte_flags |= HSW_PTE_UNCACHED;
+               else
+                       pte_flags |= GEN6_PTE_UNCACHED;
                break;
        default:
                BUG();
@@ -361,7 +364,8 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->mm.gtt->needs_dmar)
+       /* don't map imported dma buf objects */
+       if (dev_priv->mm.gtt->needs_dmar && !obj->sg_table)
                return intel_gtt_map_memory(obj->pages,
                                            obj->base.size >> PAGE_SHIFT,
                                            &obj->sg_list,
index acc99b21e0b66d4fd215c16fb6f1e81b49b5fe8b..28725ce5b82cc052a4469828166a7f9c8d987236 100644 (file)
 
 #define GEN6_PTE_VALID                 (1 << 0)
 #define GEN6_PTE_UNCACHED              (1 << 1)
+#define HSW_PTE_UNCACHED               (0)
 #define GEN6_PTE_CACHE_LLC             (2 << 1)
 #define GEN6_PTE_CACHE_LLC_MLC         (3 << 1)
 #define GEN6_PTE_CACHE_BITS            (3 << 1)
index 2f5388af8df9cdf775d66d4d4f72f50f29bdecc0..7631807a27886e2483d77de1046461350f9c7d15 100644 (file)
@@ -32,6 +32,7 @@
 #include "intel_drv.h"
 #include "i915_drv.h"
 
+#ifdef CONFIG_PM
 static u32 calc_residency(struct drm_device *dev, const u32 reg)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -224,3 +225,14 @@ void i915_teardown_sysfs(struct drm_device *dev)
        device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
        sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
 }
+#else
+void i915_setup_sysfs(struct drm_device *dev)
+{
+       return;
+}
+
+void i915_teardown_sysfs(struct drm_device *dev)
+{
+       return;
+}
+#endif /* CONFIG_PM */
index 7ed4a41c396590f77b477d36f4400fb687e86990..23bdc8cd145864f8346ce8d8ce4a255e436b0b6f 100644 (file)
@@ -326,6 +326,36 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
        return ret;
 }
 
+static struct edid *intel_crt_get_edid(struct drm_connector *connector,
+                               struct i2c_adapter *i2c)
+{
+       struct edid *edid;
+
+       edid = drm_get_edid(connector, i2c);
+
+       if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
+               DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n");
+               intel_gmbus_force_bit(i2c, true);
+               edid = drm_get_edid(connector, i2c);
+               intel_gmbus_force_bit(i2c, false);
+       }
+
+       return edid;
+}
+
+/* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */
+static int intel_crt_ddc_get_modes(struct drm_connector *connector,
+                               struct i2c_adapter *adapter)
+{
+       struct edid *edid;
+
+       edid = intel_crt_get_edid(connector, adapter);
+       if (!edid)
+               return 0;
+
+       return intel_connector_update_modes(connector, edid);
+}
+
 static bool intel_crt_detect_ddc(struct drm_connector *connector)
 {
        struct intel_crt *crt = intel_attached_crt(connector);
@@ -336,7 +366,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
        BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
 
        i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
-       edid = drm_get_edid(connector, i2c);
+       edid = intel_crt_get_edid(connector, i2c);
 
        if (edid) {
                bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
@@ -544,13 +574,13 @@ static int intel_crt_get_modes(struct drm_connector *connector)
        struct i2c_adapter *i2c;
 
        i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
-       ret = intel_ddc_get_modes(connector, i2c);
+       ret = intel_crt_ddc_get_modes(connector, i2c);
        if (ret || !IS_G4X(dev))
                return ret;
 
        /* Try to probe digital port for output in DVI-I -> VGA mode. */
        i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
-       return intel_ddc_get_modes(connector, i2c);
+       return intel_crt_ddc_get_modes(connector, i2c);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
index f6159765f1ebe8cf8f6844c092deddd37bd44040..a69a3d0d3acf6c7bc81119342aa830b41c047025 100644 (file)
@@ -869,6 +869,7 @@ intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
        unsigned long bestppm, ppm, absppm;
        int dotclk, flag;
 
+       flag = 0;
        dotclk = target * 1000;
        bestppm = 1000000;
        ppm = absppm = 0;
@@ -3753,17 +3754,6 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
                        continue;
                }
 
-               if (intel_encoder->type == INTEL_OUTPUT_EDP) {
-                       /* Use VBT settings if we have an eDP panel */
-                       unsigned int edp_bpc = dev_priv->edp.bpp / 3;
-
-                       if (edp_bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
-                               display_bpc = edp_bpc;
-                       }
-                       continue;
-               }
-
                /* Not one of the known troublemakers, check the EDID */
                list_for_each_entry(connector, &dev->mode_config.connector_list,
                                    head) {
index 0a56b9ab0f5893d49b60499ae75db9f387b6fa2e..a6c426afaa7aca46144f5a3710c0ea6f10a46b83 100644 (file)
@@ -1174,10 +1174,14 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp)
        WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
 
        pp = ironlake_get_pp_control(dev_priv);
-       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       /* We need to switch off panel power _and_ force vdd, for otherwise some
+        * panels get very unhappy and cease to work. */
+       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
 
+       intel_dp->want_panel_vdd = false;
+
        ironlake_wait_panel_off(intel_dp);
 }
 
@@ -1287,11 +1291,9 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
         * ensure that we have vdd while we switch off the panel. */
        ironlake_edp_panel_vdd_on(intel_dp);
        ironlake_edp_backlight_off(intel_dp);
-       ironlake_edp_panel_off(intel_dp);
-
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       ironlake_edp_panel_off(intel_dp);
        intel_dp_link_down(intel_dp);
-       ironlake_edp_panel_vdd_off(intel_dp, false);
 }
 
 static void intel_dp_commit(struct drm_encoder *encoder)
@@ -1326,11 +1328,9 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
                /* Switching the panel off requires vdd. */
                ironlake_edp_panel_vdd_on(intel_dp);
                ironlake_edp_backlight_off(intel_dp);
-               ironlake_edp_panel_off(intel_dp);
-
                intel_dp_sink_dpms(intel_dp, mode);
+               ironlake_edp_panel_off(intel_dp);
                intel_dp_link_down(intel_dp);
-               ironlake_edp_panel_vdd_off(intel_dp, false);
 
                if (is_cpu_edp(intel_dp))
                        ironlake_edp_pll_off(encoder);
index 84353559441cc2169dde4bef5042949de62ef251..cd54cf88a28fe408519a6bd14e8f0b71659fd498 100644 (file)
 })
 
 #define wait_for_atomic_us(COND, US) ({ \
-       int i, ret__ = -ETIMEDOUT;      \
-       for (i = 0; i < (US); i++) {    \
-               if ((COND)) {           \
-                       ret__ = 0;      \
-                       break;          \
-               }                       \
-               udelay(1);              \
-       }                               \
-       ret__;                          \
+       unsigned long timeout__ = jiffies + usecs_to_jiffies(US);       \
+       int ret__ = 0;                                                  \
+       while (!(COND)) {                                               \
+               if (time_after(jiffies, timeout__)) {                   \
+                       ret__ = -ETIMEDOUT;                             \
+                       break;                                          \
+               }                                                       \
+               cpu_relax();                                            \
+       }                                                               \
+       ret__;                                                          \
 })
 
 #define wait_for(COND, MS) _wait_for(COND, MS, 1)
@@ -341,6 +342,8 @@ struct intel_fbc_work {
        int interval;
 };
 
+int intel_connector_update_modes(struct drm_connector *connector,
+                               struct edid *edid);
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
 
 extern void intel_attach_force_audio_property(struct drm_connector *connector);
@@ -380,7 +383,6 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
                                    const struct drm_display_mode *mode,
                                    struct drm_display_mode *adjusted_mode);
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
-extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 extern int intel_panel_setup_backlight(struct drm_device *dev);
 extern void intel_panel_enable_backlight(struct drm_device *dev,
index 1991a4408cf9e10896bd5295ba4b3b4b1d74856b..b9755f6378d8d5a6b4ad9a979ce54b49b84a9814 100644 (file)
@@ -486,9 +486,6 @@ int intel_setup_gmbus(struct drm_device *dev)
                bus->dev_priv = dev_priv;
 
                bus->adapter.algo = &gmbus_algorithm;
-               ret = i2c_add_adapter(&bus->adapter);
-               if (ret)
-                       goto err;
 
                /* By default use a conservative clock rate */
                bus->reg0 = port | GMBUS_RATE_100KHZ;
@@ -498,6 +495,10 @@ int intel_setup_gmbus(struct drm_device *dev)
                        bus->force_bit = true;
 
                intel_gpio_setup(bus, port);
+
+               ret = i2c_add_adapter(&bus->adapter);
+               if (ret)
+                       goto err;
        }
 
        intel_i2c_reset(dev_priv->dev);
@@ -540,9 +541,6 @@ void intel_teardown_gmbus(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       if (dev_priv->gmbus == NULL)
-               return;
-
        for (i = 0; i < GMBUS_NUM_PORTS; i++) {
                struct intel_gmbus *bus = &dev_priv->gmbus[i];
                i2c_del_adapter(&bus->adapter);
index 45848b9b670b0538625a18fca7427fd98a3155ae..29b72593fbb276fbce8b2ae00828cc7c48a06bf3 100644 (file)
 #include "intel_drv.h"
 #include "i915_drv.h"
 
+/**
+ * intel_connector_update_modes - update connector from edid
+ * @connector: DRM connector device to use
+ * @edid: previously read EDID information
+ */
+int intel_connector_update_modes(struct drm_connector *connector,
+                               struct edid *edid)
+{
+       int ret;
+
+       drm_mode_connector_update_edid_property(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+       drm_edid_to_eld(connector, edid);
+       connector->display_info.raw_edid = NULL;
+       kfree(edid);
+
+       return ret;
+}
+
 /**
  * intel_ddc_get_modes - get modelist from monitor
  * @connector: DRM connector device to use
@@ -43,18 +62,12 @@ int intel_ddc_get_modes(struct drm_connector *connector,
                        struct i2c_adapter *adapter)
 {
        struct edid *edid;
-       int ret = 0;
 
        edid = drm_get_edid(connector, adapter);
-       if (edid) {
-               drm_mode_connector_update_edid_property(connector, edid);
-               ret = drm_add_edid_modes(connector, edid);
-               drm_edid_to_eld(connector, edid);
-               connector->display_info.raw_edid = NULL;
-               kfree(edid);
-       }
+       if (!edid)
+               return 0;
 
-       return ret;
+       return intel_connector_update_modes(connector, edid);
 }
 
 static const struct drm_prop_enum_list force_audio_names[] = {
index 10c7d39034e1c8c0a3e17491e17ffa3286b5f97a..3df4f5fa892ad847b394c2050e8956779473afd8 100644 (file)
@@ -213,7 +213,7 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
        return val;
 }
 
-u32 intel_panel_get_backlight(struct drm_device *dev)
+static u32 intel_panel_get_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
@@ -311,9 +311,6 @@ void intel_panel_enable_backlight(struct drm_device *dev,
        if (dev_priv->backlight_level == 0)
                dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
-       dev_priv->backlight_enabled = true;
-       intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
-
        if (INTEL_INFO(dev)->gen >= 4) {
                uint32_t reg, tmp;
 
@@ -326,7 +323,7 @@ void intel_panel_enable_backlight(struct drm_device *dev,
                 * we don't track the backlight dpms state, hence check whether
                 * we have to do anything first. */
                if (tmp & BLM_PWM_ENABLE)
-                       return;
+                       goto set_level;
 
                if (dev_priv->num_pipe == 3)
                        tmp &= ~BLM_PIPE_SELECT_IVB;
@@ -347,6 +344,14 @@ void intel_panel_enable_backlight(struct drm_device *dev,
                        I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
                }
        }
+
+set_level:
+       /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
+        * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
+        * registers are set.
+        */
+       dev_priv->backlight_enabled = true;
+       intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
 }
 
 static void intel_panel_init_backlight(struct drm_device *dev)
index 94aabcaa3a673a46aa0e9361133aa3331ed8e453..1881c8c83f0e0c44ab009dfed7049235c4074d97 100644 (file)
@@ -2441,17 +2441,10 @@ static void gen6_enable_rps(struct drm_device *dev)
                   dev_priv->max_delay << 24 |
                   dev_priv->min_delay << 16);
 
-       if (IS_HASWELL(dev)) {
-               I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
-               I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
-               I915_WRITE(GEN6_RP_UP_EI, 66000);
-               I915_WRITE(GEN6_RP_DOWN_EI, 350000);
-       } else {
-               I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
-               I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
-               I915_WRITE(GEN6_RP_UP_EI, 100000);
-               I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
-       }
+       I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
+       I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
+       I915_WRITE(GEN6_RP_UP_EI, 66000);
+       I915_WRITE(GEN6_RP_DOWN_EI, 350000);
 
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
        I915_WRITE(GEN6_RP_CONTROL,
@@ -3963,6 +3956,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
                DRM_ERROR("Force wake wait timed out\n");
 
        I915_WRITE_NOTRACE(FORCEWAKE, 1);
+       POSTING_READ(FORCEWAKE);
 
        if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500))
                DRM_ERROR("Force wake wait timed out\n");
@@ -3983,6 +3977,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
                DRM_ERROR("Force wake wait timed out\n");
 
        I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
+       POSTING_READ(FORCEWAKE_MT);
 
        if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500))
                DRM_ERROR("Force wake wait timed out\n");
@@ -4018,14 +4013,14 @@ void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
 static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE, 0);
-       /* The below doubles as a POSTING_READ */
+       POSTING_READ(FORCEWAKE);
        gen6_gt_check_fifodbg(dev_priv);
 }
 
 static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1));
-       /* The below doubles as a POSTING_READ */
+       POSTING_READ(FORCEWAKE_MT);
        gen6_gt_check_fifodbg(dev_priv);
 }
 
index bf0195a96d5308c48d273cb492081a8d415ba188..e2a73b38abe96e7dc49674d39806c5ca3cab6e51 100644 (file)
@@ -227,31 +227,36 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
         * number of bits based on the write domains has little performance
         * impact.
         */
-       flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
-       flags |= PIPE_CONTROL_TLB_INVALIDATE;
-       flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
-       flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
-       /*
-        * Ensure that any following seqno writes only happen when the render
-        * cache is indeed flushed (but only if the caller actually wants that).
-        */
-       if (flush_domains)
+       if (flush_domains) {
+               flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               /*
+                * Ensure that any following seqno writes only happen
+                * when the render cache is indeed flushed.
+                */
                flags |= PIPE_CONTROL_CS_STALL;
+       }
+       if (invalidate_domains) {
+               flags |= PIPE_CONTROL_TLB_INVALIDATE;
+               flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               /*
+                * TLB invalidate requires a post-sync write.
+                */
+               flags |= PIPE_CONTROL_QW_WRITE;
+       }
 
-       ret = intel_ring_begin(ring, 6);
+       ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(5));
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
        intel_ring_emit(ring, flags);
        intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
-       intel_ring_emit(ring, 0); /* lower dword */
-       intel_ring_emit(ring, 0); /* uppwer dword */
-       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, 0);
        intel_ring_advance(ring);
 
        return 0;
@@ -289,8 +294,6 @@ static int init_ring_common(struct intel_ring_buffer *ring)
        I915_WRITE_HEAD(ring, 0);
        ring->write_tail(ring, 0);
 
-       /* Initialize the ring. */
-       I915_WRITE_START(ring, obj->gtt_offset);
        head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
        /* G45 ring initialization fails to reset head to zero */
@@ -316,6 +319,11 @@ static int init_ring_common(struct intel_ring_buffer *ring)
                }
        }
 
+       /* Initialize the ring. This must happen _after_ we've cleared the ring
+        * registers with the above sequence (the readback of the HEAD registers
+        * also enforces ordering), otherwise the hw might lose the new ring
+        * register values. */
+       I915_WRITE_START(ring, obj->gtt_offset);
        I915_WRITE_CTL(ring,
                        ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_VALID);
index 26a6a4d0d0788b536de65f3b4ca6261768115179..d81bb0bf28850f4ea734dedabec44d8478b12d44 100644 (file)
@@ -444,13 +444,16 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
        struct i2c_msg *msgs;
        int i, ret = true;
 
+        /* Would be simpler to allocate both in one go ? */        
        buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL);
        if (!buf)
                return false;
 
        msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL);
-       if (!msgs)
+       if (!msgs) {
+               kfree(buf);
                return false;
+        }
 
        intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
 
@@ -1689,6 +1692,7 @@ static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
        edid = intel_sdvo_get_edid(connector);
        if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL)
                has_audio = drm_detect_monitor_audio(edid);
+       kfree(edid);
 
        return has_audio;
 }
index a4d7c500c97b7f43d049a8ed8cc6bca59b20c100..b69642d5d850581694fe8741056a5d0529f4eeed 100644 (file)
@@ -468,10 +468,11 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
 {
        unsigned int vcomax, vcomin, pllreffreq;
        unsigned int delta, tmpdelta;
-       unsigned int testr, testn, testm, testo;
+       int testr, testn, testm, testo;
        unsigned int p, m, n;
-       unsigned int computed;
+       unsigned int computed, vco;
        int tmp;
+       const unsigned int m_div_val[] = { 1, 2, 4, 8 };
 
        m = n = p = 0;
        vcomax = 1488000;
@@ -490,12 +491,13 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
                                if (delta == 0)
                                        break;
                                for (testo = 5; testo < 33; testo++) {
-                                       computed = pllreffreq * (testn + 1) /
+                                       vco = pllreffreq * (testn + 1) /
                                                (testr + 1);
-                                       if (computed < vcomin)
+                                       if (vco < vcomin)
                                                continue;
-                                       if (computed > vcomax)
+                                       if (vco > vcomax)
                                                continue;
+                                       computed = vco / (m_div_val[testm] * (testo + 1));
                                        if (computed > clock)
                                                tmpdelta = computed - clock;
                                        else
index fc841e87b343a6aa71cc05bb7f4ae94e7399fafc..26ebffebe7107db7accfecc619b282ba0b271252 100644 (file)
@@ -211,11 +211,6 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
        return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }
 
-static int nouveau_dsm_init(void)
-{
-       return 0;
-}
-
 static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 {
        /* easy option one - intel vendor ID means Integrated */
@@ -232,7 +227,6 @@ static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 static struct vga_switcheroo_handler nouveau_dsm_handler = {
        .switchto = nouveau_dsm_switchto,
        .power_state = nouveau_dsm_power_state,
-       .init = nouveau_dsm_init,
        .get_client_id = nouveau_dsm_get_client_id,
 };
 
index 77e564667b5c89d6fec1ad5e58f55ce5082f2c42..240cf962c999ee322e4f77fe2e612ffc731e6eb7 100644 (file)
@@ -229,7 +229,7 @@ nouveau_i2c_init(struct drm_device *dev)
                        }
                        break;
                case 6: /* NV50- DP AUX */
-                       port->drive = entry[0];
+                       port->drive = entry[0] & 0x0f;
                        port->sense = port->drive;
                        port->adapter.algo = &nouveau_dp_i2c_algo;
                        break;
index 1cdfd6e757ce7455c03ea35eaef42dbe6253ab7b..1866dbb499792e4e4758938c50802d11beb29bb7 100644 (file)
@@ -731,7 +731,6 @@ nouveau_card_init(struct drm_device *dev)
                        case 0xa3:
                        case 0xa5:
                        case 0xa8:
-                       case 0xaf:
                                nva3_copy_create(dev);
                                break;
                        }
index cc82d799fc3ba162ae2798d3a5e0df1e6db4abec..c564c5e4c30aa97841f5cf1060d3bbcf8686ebbf 100644 (file)
@@ -117,17 +117,22 @@ nv84_fifo_context_del(struct nouveau_channel *chan, int engine)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        unsigned long flags;
+       u32 save;
 
        /* remove channel from playlist, will context switch if active */
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
        nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
        nv50_fifo_playlist_update(dev);
 
+       save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
+
        /* tell any engines on this channel to unload their contexts */
        nv_wr32(dev, 0x0032fc, chan->ramin->vinst >> 12);
        if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff))
                NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
 
+       nv_wr32(dev, 0x002520, save);
+
        nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
@@ -184,10 +189,13 @@ nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv84_fifo_priv *priv = nv_engine(dev, engine);
        int i;
+       u32 save;
 
        /* set playlist length to zero, fifo will unload context */
        nv_wr32(dev, 0x0032ec, 0);
 
+       save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
+
        /* tell all connected engines to unload their contexts */
        for (i = 0; i < priv->base.channels; i++) {
                struct nouveau_channel *chan = dev_priv->channels.ptr[i];
@@ -199,6 +207,7 @@ nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
                }
        }
 
+       nv_wr32(dev, 0x002520, save);
        nv_wr32(dev, 0x002140, 0);
        return 0;
 }
index 7c95c44e2887b870096964d600b98c80a0e16505..4e712b10ebdb682c7956c74a5f3e694ff57e61dd 100644 (file)
@@ -557,7 +557,7 @@ prog_mem(struct drm_device *dev, struct nvc0_pm_state *info)
        nouveau_mem_exec(&exec, info->perflvl);
 
        if (dev_priv->chipset < 0xd0)
-               nv_wr32(dev, 0x611200, 0x00003300);
+               nv_wr32(dev, 0x611200, 0x00003330);
        else
                nv_wr32(dev, 0x62c000, 0x03030300);
 }
index d0d60e1e7f95bf74c7209f81f6cd205edd8d71a5..dac525b2994ee4bd28ff862625e7a6fe7649d2cd 100644 (file)
@@ -790,7 +790,7 @@ nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ch = EVO_CURS(nv_crtc->index);
 
-       evo_piow(crtc->dev, ch, 0x0084, (y << 16) | x);
+       evo_piow(crtc->dev, ch, 0x0084, (y << 16) | (x & 0xffff));
        evo_piow(crtc->dev, ch, 0x0080, 0x00000000);
        return 0;
 }
index 1855ecbd843b81161245cfd15ccb1f4e7f8e2343..e98d144e6eb9df766fc458e03bdd35acef349ce4 100644 (file)
@@ -294,6 +294,25 @@ nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
        printk(" on channel 0x%010llx\n", (u64)inst << 12);
 }
 
+static int
+nve0_fifo_page_flip(struct drm_device *dev, u32 chid)
+{
+       struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_channel *chan = NULL;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->channels.lock, flags);
+       if (likely(chid >= 0 && chid < priv->base.channels)) {
+               chan = dev_priv->channels.ptr[chid];
+               if (likely(chan))
+                       ret = nouveau_finish_page_flip(chan, NULL);
+       }
+       spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+       return ret;
+}
+
 static void
 nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
 {
@@ -303,11 +322,21 @@ nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
        u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
        u32 subc = (addr & 0x00070000);
        u32 mthd = (addr & 0x00003ffc);
+       u32 show = stat;
+
+       if (stat & 0x00200000) {
+               if (mthd == 0x0054) {
+                       if (!nve0_fifo_page_flip(dev, chid))
+                               show &= ~0x00200000;
+               }
+       }
 
-       NV_INFO(dev, "PSUBFIFO %d:", unit);
-       nouveau_bitfield_print(nve0_fifo_subfifo_intr, stat);
-       NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
-               unit, chid, subc, mthd, data);
+       if (show) {
+               NV_INFO(dev, "PFIFO%d:", unit);
+               nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
+               NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
+                       unit, chid, subc, mthd, data);
+       }
 
        nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
        nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
index 9e6f76fec52789b4931e4e1098b9b52df765c270..f4d4505fe831b9c60b676b2f761727af6987ac13 100644 (file)
@@ -259,7 +259,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
                /* adjust pm to dpms changes BEFORE enabling crtcs */
                radeon_pm_compute_clocks(rdev);
                /* disable crtc pair power gating before programming */
-               if (ASIC_IS_DCE6(rdev))
+               if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set)
                        atombios_powergate_crtc(crtc, ATOM_DISABLE);
                atombios_enable_crtc(crtc, ATOM_ENABLE);
                if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
@@ -279,7 +279,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
                atombios_enable_crtc(crtc, ATOM_DISABLE);
                radeon_crtc->enabled = false;
                /* power gating is per-pair */
-               if (ASIC_IS_DCE6(rdev)) {
+               if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) {
                        struct drm_crtc *other_crtc;
                        struct radeon_crtc *other_radeon_crtc;
                        list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) {
@@ -444,11 +444,28 @@ union atom_enable_ss {
 static void atombios_crtc_program_ss(struct radeon_device *rdev,
                                     int enable,
                                     int pll_id,
+                                    int crtc_id,
                                     struct radeon_atom_ss *ss)
 {
+       unsigned i;
        int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
        union atom_enable_ss args;
 
+       if (!enable) {
+               for (i = 0; i < rdev->num_crtc; i++) {
+                       if (rdev->mode_info.crtcs[i] &&
+                           rdev->mode_info.crtcs[i]->enabled &&
+                           i != crtc_id &&
+                           pll_id == rdev->mode_info.crtcs[i]->pll_id) {
+                               /* one other crtc is using this pll don't turn
+                                * off spread spectrum as it might turn off
+                                * display on active crtc
+                                */
+                               return;
+                       }
+               }
+       }
+
        memset(&args, 0, sizeof(args));
 
        if (ASIC_IS_DCE5(rdev)) {
@@ -1028,7 +1045,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
                                          &ref_div, &post_div);
 
-       atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, &ss);
+       atombios_crtc_program_ss(rdev, ATOM_DISABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss);
 
        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
                                  encoder_mode, radeon_encoder->encoder_id, mode->clock,
@@ -1051,7 +1068,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                        ss.step = step_size;
                }
 
-               atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, &ss);
+               atombios_crtc_program_ss(rdev, ATOM_ENABLE, radeon_crtc->pll_id, radeon_crtc->crtc_id, &ss);
        }
 }
 
@@ -1531,12 +1548,12 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                 * crtc virtual pixel clock.
                                 */
                                if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
-                                       if (ASIC_IS_DCE5(rdev))
-                                               return ATOM_DCPLL;
+                                       if (rdev->clock.dp_extclk)
+                                               return ATOM_PPLL_INVALID;
                                        else if (ASIC_IS_DCE6(rdev))
                                                return ATOM_PPLL0;
-                                       else if (rdev->clock.dp_extclk)
-                                               return ATOM_PPLL_INVALID;
+                                       else if (ASIC_IS_DCE5(rdev))
+                                               return ATOM_DCPLL;
                                }
                        }
                }
@@ -1572,11 +1589,11 @@ void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev)
                                                                   ASIC_INTERNAL_SS_ON_DCPLL,
                                                                   rdev->clock.default_dispclk);
                if (ss_enabled)
-                       atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, &ss);
+                       atombios_crtc_program_ss(rdev, ATOM_DISABLE, ATOM_DCPLL, -1, &ss);
                /* XXX: DCE5, make sure voltage, dispclk is high enough */
                atombios_crtc_set_disp_eng_pll(rdev, rdev->clock.default_dispclk);
                if (ss_enabled)
-                       atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, &ss);
+                       atombios_crtc_program_ss(rdev, ATOM_ENABLE, ATOM_DCPLL, -1, &ss);
        }
 
 }
@@ -1635,18 +1652,28 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
 static void atombios_crtc_prepare(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
 
+       radeon_crtc->in_mode_set = true;
        /* pick pll */
        radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
 
+       /* disable crtc pair power gating before programming */
+       if (ASIC_IS_DCE6(rdev))
+               atombios_powergate_crtc(crtc, ATOM_DISABLE);
+
        atombios_lock_crtc(crtc, ATOM_ENABLE);
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 static void atombios_crtc_commit(struct drm_crtc *crtc)
 {
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
        atombios_lock_crtc(crtc, ATOM_DISABLE);
+       radeon_crtc->in_mode_set = false;
 }
 
 static void atombios_crtc_disable(struct drm_crtc *crtc)
index e585a3b947eb7c169fe9869aa18880744ab92ef2..e93b80a6d4e969a30cdbbc934d2e8ddd8b8e8a1a 100644 (file)
@@ -1229,24 +1229,8 @@ void evergreen_agp_enable(struct radeon_device *rdev)
 
 void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
-       save->vga_control[0] = RREG32(D1VGA_CONTROL);
-       save->vga_control[1] = RREG32(D2VGA_CONTROL);
        save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
        save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
-       save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
-       save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
-       if (rdev->num_crtc >= 4) {
-               save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
-               save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
-               save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
-               save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
-       }
-       if (rdev->num_crtc >= 6) {
-               save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
-               save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
-               save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
-               save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
-       }
 
        /* Stop all video */
        WREG32(VGA_RENDER_CONTROL, 0);
@@ -1357,47 +1341,6 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
        /* Unlock host access */
        WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
        mdelay(1);
-       /* Restore video state */
-       WREG32(D1VGA_CONTROL, save->vga_control[0]);
-       WREG32(D2VGA_CONTROL, save->vga_control[1]);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
-               WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
-               WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
-       }
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
-       }
-       WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
-       WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
-       }
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-       }
        WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
 }
 
@@ -1986,10 +1929,18 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        if (rdev->flags & RADEON_IS_IGP)
                rdev->config.evergreen.tile_config |= 1 << 4;
        else {
-               if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-                       rdev->config.evergreen.tile_config |= 1 << 4;
-               else
+               switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
+               case 0: /* four banks */
                        rdev->config.evergreen.tile_config |= 0 << 4;
+                       break;
+               case 1: /* eight banks */
+                       rdev->config.evergreen.tile_config |= 1 << 4;
+                       break;
+               case 2: /* sixteen banks */
+               default:
+                       rdev->config.evergreen.tile_config |= 2 << 4;
+                       break;
+               }
        }
        rdev->config.evergreen.tile_config |= 0 << 8;
        rdev->config.evergreen.tile_config |=
index c16554122ccd0fb482aa2f03bc93e8b47af55430..e44a62a07fe396f36e70dd6dce1b4460c6786b45 100644 (file)
@@ -788,6 +788,13 @@ static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,
        case V_030000_SQ_TEX_DIM_1D_ARRAY:
        case V_030000_SQ_TEX_DIM_2D_ARRAY:
                depth = 1;
+               break;
+       case V_030000_SQ_TEX_DIM_2D_MSAA:
+       case V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA:
+               surf.nsamples = 1 << llevel;
+               llevel = 0;
+               depth = 1;
+               break;
        case V_030000_SQ_TEX_DIM_3D:
                break;
        default:
@@ -961,13 +968,15 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)
 
        if (track->db_dirty) {
                /* Check stencil buffer */
-               if (G_028800_STENCIL_ENABLE(track->db_depth_control)) {
+               if (G_028044_FORMAT(track->db_s_info) != V_028044_STENCIL_INVALID &&
+                   G_028800_STENCIL_ENABLE(track->db_depth_control)) {
                        r = evergreen_cs_track_validate_stencil(p);
                        if (r)
                                return r;
                }
                /* Check depth buffer */
-               if (G_028800_Z_ENABLE(track->db_depth_control)) {
+               if (G_028040_FORMAT(track->db_z_info) != V_028040_Z_INVALID &&
+                   G_028800_Z_ENABLE(track->db_depth_control)) {
                        r = evergreen_cs_track_validate_depth(p);
                        if (r)
                                return r;
index d3bd098e4e19d453aee64b691e6519a0d8c97066..79347855d9bf50cf024a34677ca2a4287f9f3df5 100644 (file)
 #define   S_028044_FORMAT(x)                           (((x) & 0x1) << 0)
 #define   G_028044_FORMAT(x)                           (((x) >> 0) & 0x1)
 #define   C_028044_FORMAT                              0xFFFFFFFE
+#define            V_028044_STENCIL_INVALID                    0
+#define            V_028044_STENCIL_8                          1
 #define   G_028044_TILE_SPLIT(x)                       (((x) >> 8) & 0x7)
 #define DB_Z_READ_BASE                                 0x28048
 #define DB_STENCIL_READ_BASE                           0x2804c
index 9945d86d900153b13210bcc967c594c638213f5c..853800e8582f972233dd20f6f6b4573d24f71f2f 100644 (file)
@@ -574,10 +574,18 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        if (rdev->flags & RADEON_IS_IGP)
                rdev->config.cayman.tile_config |= 1 << 4;
        else {
-               if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-                       rdev->config.cayman.tile_config |= 1 << 4;
-               else
+               switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
+               case 0: /* four banks */
                        rdev->config.cayman.tile_config |= 0 << 4;
+                       break;
+               case 1: /* eight banks */
+                       rdev->config.cayman.tile_config |= 1 << 4;
+                       break;
+               case 2: /* sixteen banks */
+               default:
+                       rdev->config.cayman.tile_config |= 2 << 4;
+                       break;
+               }
        }
        rdev->config.cayman.tile_config |=
                ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
index 637280f541a38492e8a0289e209285e0bb518aaf..d79c639ae739cf68a35039d4ca94357d423c534a 100644 (file)
@@ -3789,3 +3789,23 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)
                WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
        }
 }
+
+/**
+ * r600_get_gpu_clock - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (R6xx-cayman).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t r600_get_gpu_clock(struct radeon_device *rdev)
+{
+       uint64_t clock;
+
+       mutex_lock(&rdev->gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&rdev->gpu_clock_mutex);
+       return clock;
+}
index ca87f7afaf2374d02117ec91e479c1e5a385b8d2..ab74e6b149e7468c16f47d0f4e6228abdcf41e14 100644 (file)
@@ -47,13 +47,17 @@ struct r600_cs_track {
        u32                     npipes;
        /* value we track */
        u32                     sq_config;
+       u32                     log_nsamples;
        u32                     nsamples;
        u32                     cb_color_base_last[8];
        struct radeon_bo        *cb_color_bo[8];
        u64                     cb_color_bo_mc[8];
-       u32                     cb_color_bo_offset[8];
-       struct radeon_bo        *cb_color_frag_bo[8]; /* unused */
-       struct radeon_bo        *cb_color_tile_bo[8]; /* unused */
+       u64                     cb_color_bo_offset[8];
+       struct radeon_bo        *cb_color_frag_bo[8];
+       u64                     cb_color_frag_offset[8];
+       struct radeon_bo        *cb_color_tile_bo[8];
+       u64                     cb_color_tile_offset[8];
+       u32                     cb_color_mask[8];
        u32                     cb_color_info[8];
        u32                     cb_color_view[8];
        u32                     cb_color_size_idx[8]; /* unused */
@@ -349,10 +353,6 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        unsigned array_mode;
        u32 format;
 
-       if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
-               dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
-               return -EINVAL;
-       }
        size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
        format = G_0280A0_FORMAT(track->cb_color_info[i]);
        if (!r600_fmt_is_valid_color(format)) {
@@ -420,7 +420,8 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        }
 
        /* check offset */
-       tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * r600_fmt_get_blocksize(format);
+       tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) *
+             r600_fmt_get_blocksize(format) * track->nsamples;
        switch (array_mode) {
        default:
        case V_0280A0_ARRAY_LINEAR_GENERAL:
@@ -441,7 +442,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                         * broken userspace.
                         */
                } else {
-                       dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big (%d %d) (%d %d %d)\n",
+                       dev_warn(p->dev, "%s offset[%d] %d %llu %d %lu too big (%d %d) (%d %d %d)\n",
                                 __func__, i, array_mode,
                                 track->cb_color_bo_offset[i], tmp,
                                 radeon_bo_size(track->cb_color_bo[i]),
@@ -458,6 +459,51 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |
                S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
        ib[track->cb_color_size_idx[i]] = tmp;
+
+       /* FMASK/CMASK */
+       switch (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
+       case V_0280A0_TILE_DISABLE:
+               break;
+       case V_0280A0_FRAG_ENABLE:
+               if (track->nsamples > 1) {
+                       uint32_t tile_max = G_028100_FMASK_TILE_MAX(track->cb_color_mask[i]);
+                       /* the tile size is 8x8, but the size is in units of bits.
+                        * for bytes, do just * 8. */
+                       uint32_t bytes = track->nsamples * track->log_nsamples * 8 * (tile_max + 1);
+
+                       if (bytes + track->cb_color_frag_offset[i] >
+                           radeon_bo_size(track->cb_color_frag_bo[i])) {
+                               dev_warn(p->dev, "%s FMASK_TILE_MAX too large "
+                                        "(tile_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n",
+                                        __func__, tile_max, bytes,
+                                        track->cb_color_frag_offset[i],
+                                        radeon_bo_size(track->cb_color_frag_bo[i]));
+                               return -EINVAL;
+                       }
+               }
+               /* fall through */
+       case V_0280A0_CLEAR_ENABLE:
+       {
+               uint32_t block_max = G_028100_CMASK_BLOCK_MAX(track->cb_color_mask[i]);
+               /* One block = 128x128 pixels, one 8x8 tile has 4 bits..
+                * (128*128) / (8*8) / 2 = 128 bytes per block. */
+               uint32_t bytes = (block_max + 1) * 128;
+
+               if (bytes + track->cb_color_tile_offset[i] >
+                   radeon_bo_size(track->cb_color_tile_bo[i])) {
+                       dev_warn(p->dev, "%s CMASK_BLOCK_MAX too large "
+                                "(block_max=%u, bytes=%u, offset=%llu, bo_size=%lu)\n",
+                                __func__, block_max, bytes,
+                                track->cb_color_tile_offset[i],
+                                radeon_bo_size(track->cb_color_tile_bo[i]));
+                       return -EINVAL;
+               }
+               break;
+       }
+       default:
+               dev_warn(p->dev, "%s invalid tile mode\n", __func__);
+               return -EINVAL;
+       }
        return 0;
 }
 
@@ -566,7 +612,7 @@ static int r600_cs_track_validate_db(struct radeon_cs_parser *p)
 
                ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
                nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
-               tmp = ntiles * bpe * 64 * nviews;
+               tmp = ntiles * bpe * 64 * nviews * track->nsamples;
                if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
                        dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
                                        array_mode,
@@ -764,8 +810,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
        }
 
        /* Check depth buffer */
-       if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
-               G_028800_Z_ENABLE(track->db_depth_control))) {
+       if (track->db_dirty &&
+           G_028010_FORMAT(track->db_depth_info) != V_028010_DEPTH_INVALID &&
+           (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+            G_028800_Z_ENABLE(track->db_depth_control))) {
                r = r600_cs_track_validate_db(p);
                if (r)
                        return r;
@@ -1229,6 +1277,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                break;
        case R_028C04_PA_SC_AA_CONFIG:
                tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx));
+               track->log_nsamples = tmp;
                track->nsamples = 1 << tmp;
                track->cb_dirty = true;
                break;
@@ -1310,16 +1359,21 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
                                return -EINVAL;
                        }
-                       ib[idx] = track->cb_color_base_last[tmp];
                        track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
+                       track->cb_color_frag_offset[tmp] = track->cb_color_bo_offset[tmp];
+                       ib[idx] = track->cb_color_base_last[tmp];
                } else {
                        r = r600_cs_packet_next_reloc(p, &reloc);
                        if (r) {
                                dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
                                return -EINVAL;
                        }
-                       ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                        track->cb_color_frag_bo[tmp] = reloc->robj;
+                       track->cb_color_frag_offset[tmp] = (u64)ib[idx] << 8;
+                       ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               }
+               if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
+                       track->cb_dirty = true;
                }
                break;
        case R_0280C0_CB_COLOR0_TILE:
@@ -1336,16 +1390,35 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
                                return -EINVAL;
                        }
-                       ib[idx] = track->cb_color_base_last[tmp];
                        track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
+                       track->cb_color_tile_offset[tmp] = track->cb_color_bo_offset[tmp];
+                       ib[idx] = track->cb_color_base_last[tmp];
                } else {
                        r = r600_cs_packet_next_reloc(p, &reloc);
                        if (r) {
                                dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
                                return -EINVAL;
                        }
-                       ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                        track->cb_color_tile_bo[tmp] = reloc->robj;
+                       track->cb_color_tile_offset[tmp] = (u64)ib[idx] << 8;
+                       ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               }
+               if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
+                       track->cb_dirty = true;
+               }
+               break;
+       case R_028100_CB_COLOR0_MASK:
+       case R_028104_CB_COLOR1_MASK:
+       case R_028108_CB_COLOR2_MASK:
+       case R_02810C_CB_COLOR3_MASK:
+       case R_028110_CB_COLOR4_MASK:
+       case R_028114_CB_COLOR5_MASK:
+       case R_028118_CB_COLOR6_MASK:
+       case R_02811C_CB_COLOR7_MASK:
+               tmp = (reg - R_028100_CB_COLOR0_MASK) / 4;
+               track->cb_color_mask[tmp] = ib[idx];
+               if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
+                       track->cb_dirty = true;
                }
                break;
        case CB_COLOR0_BASE:
@@ -1490,7 +1563,7 @@ unsigned r600_mip_minify(unsigned size, unsigned level)
 }
 
 static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel,
-                             unsigned w0, unsigned h0, unsigned d0, unsigned format,
+                             unsigned w0, unsigned h0, unsigned d0, unsigned nsamples, unsigned format,
                              unsigned block_align, unsigned height_align, unsigned base_align,
                              unsigned *l0_size, unsigned *mipmap_size)
 {
@@ -1518,7 +1591,7 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned llevel,
 
                depth = r600_mip_minify(d0, i);
 
-               size = nbx * nby * blocksize;
+               size = nbx * nby * blocksize * nsamples;
                if (nfaces)
                        size *= nfaces;
                else
@@ -1557,13 +1630,14 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                                              u32 tiling_flags)
 {
        struct r600_cs_track *track = p->track;
-       u32 nfaces, llevel, blevel, w0, h0, d0;
-       u32 word0, word1, l0_size, mipmap_size, word2, word3;
+       u32 dim, nfaces, llevel, blevel, w0, h0, d0;
+       u32 word0, word1, l0_size, mipmap_size, word2, word3, word4, word5;
        u32 height_align, pitch, pitch_align, depth_align;
-       u32 array, barray, larray;
+       u32 barray, larray;
        u64 base_align;
        struct array_mode_checker array_check;
        u32 format;
+       bool is_array;
 
        /* on legacy kernel we don't perform advanced check */
        if (p->rdev == NULL)
@@ -1581,12 +1655,28 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                        word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
        }
        word1 = radeon_get_ib_value(p, idx + 1);
+       word2 = radeon_get_ib_value(p, idx + 2) << 8;
+       word3 = radeon_get_ib_value(p, idx + 3) << 8;
+       word4 = radeon_get_ib_value(p, idx + 4);
+       word5 = radeon_get_ib_value(p, idx + 5);
+       dim = G_038000_DIM(word0);
        w0 = G_038000_TEX_WIDTH(word0) + 1;
+       pitch = (G_038000_PITCH(word0) + 1) * 8;
        h0 = G_038004_TEX_HEIGHT(word1) + 1;
        d0 = G_038004_TEX_DEPTH(word1);
+       format = G_038004_DATA_FORMAT(word1);
+       blevel = G_038010_BASE_LEVEL(word4);
+       llevel = G_038014_LAST_LEVEL(word5);
+       /* pitch in texels */
+       array_check.array_mode = G_038000_TILE_MODE(word0);
+       array_check.group_size = track->group_size;
+       array_check.nbanks = track->nbanks;
+       array_check.npipes = track->npipes;
+       array_check.nsamples = 1;
+       array_check.blocksize = r600_fmt_get_blocksize(format);
        nfaces = 1;
-       array = 0;
-       switch (G_038000_DIM(word0)) {
+       is_array = false;
+       switch (dim) {
        case V_038000_SQ_TEX_DIM_1D:
        case V_038000_SQ_TEX_DIM_2D:
        case V_038000_SQ_TEX_DIM_3D:
@@ -1599,29 +1689,25 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                break;
        case V_038000_SQ_TEX_DIM_1D_ARRAY:
        case V_038000_SQ_TEX_DIM_2D_ARRAY:
-               array = 1;
+               is_array = true;
                break;
-       case V_038000_SQ_TEX_DIM_2D_MSAA:
        case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA:
+               is_array = true;
+               /* fall through */
+       case V_038000_SQ_TEX_DIM_2D_MSAA:
+               array_check.nsamples = 1 << llevel;
+               llevel = 0;
+               break;
        default:
                dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0));
                return -EINVAL;
        }
-       format = G_038004_DATA_FORMAT(word1);
        if (!r600_fmt_is_valid_texture(format, p->family)) {
                dev_warn(p->dev, "%s:%d texture invalid format %d\n",
                         __func__, __LINE__, format);
                return -EINVAL;
        }
 
-       /* pitch in texels */
-       pitch = (G_038000_PITCH(word0) + 1) * 8;
-       array_check.array_mode = G_038000_TILE_MODE(word0);
-       array_check.group_size = track->group_size;
-       array_check.nbanks = track->nbanks;
-       array_check.npipes = track->npipes;
-       array_check.nsamples = 1;
-       array_check.blocksize = r600_fmt_get_blocksize(format);
        if (r600_get_array_mode_alignment(&array_check,
                                          &pitch_align, &height_align, &depth_align, &base_align)) {
                dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
@@ -1647,24 +1733,17 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                return -EINVAL;
        }
 
-       word2 = radeon_get_ib_value(p, idx + 2) << 8;
-       word3 = radeon_get_ib_value(p, idx + 3) << 8;
-
-       word0 = radeon_get_ib_value(p, idx + 4);
-       word1 = radeon_get_ib_value(p, idx + 5);
-       blevel = G_038010_BASE_LEVEL(word0);
-       llevel = G_038014_LAST_LEVEL(word1);
        if (blevel > llevel) {
                dev_warn(p->dev, "texture blevel %d > llevel %d\n",
                         blevel, llevel);
        }
-       if (array == 1) {
-               barray = G_038014_BASE_ARRAY(word1);
-               larray = G_038014_LAST_ARRAY(word1);
+       if (is_array) {
+               barray = G_038014_BASE_ARRAY(word5);
+               larray = G_038014_LAST_ARRAY(word5);
 
                nfaces = larray - barray + 1;
        }
-       r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, format,
+       r600_texture_size(nfaces, blevel, llevel, w0, h0, d0, array_check.nsamples, format,
                          pitch_align, height_align, base_align,
                          &l0_size, &mipmap_size);
        /* using get ib will give us the offset into the texture bo */
@@ -1677,7 +1756,6 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                return -EINVAL;
        }
        /* using get ib will give us the offset into the mipmap bo */
-       word3 = radeon_get_ib_value(p, idx + 3) << 8;
        if ((mipmap_size + word3) > radeon_bo_size(mipmap)) {
                /*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
                  w0, h0, format, blevel, nlevels, word3, mipmap_size, radeon_bo_size(texture));*/
index 4b116ae75fc2cedd41b2e446f1a421b7a085d81b..bdb69a63062fd72947b924503d5fb201c7e33f00 100644 (file)
 #define R_028094_CB_COLOR5_VIEW                      0x028094
 #define R_028098_CB_COLOR6_VIEW                      0x028098
 #define R_02809C_CB_COLOR7_VIEW                      0x02809C
+#define R_028100_CB_COLOR0_MASK                      0x028100
+#define   S_028100_CMASK_BLOCK_MAX(x)                  (((x) & 0xFFF) << 0)
+#define   G_028100_CMASK_BLOCK_MAX(x)                  (((x) >> 0) & 0xFFF)
+#define   C_028100_CMASK_BLOCK_MAX                     0xFFFFF000
+#define   S_028100_FMASK_TILE_MAX(x)                   (((x) & 0xFFFFF) << 12)
+#define   G_028100_FMASK_TILE_MAX(x)                   (((x) >> 12) & 0xFFFFF)
+#define   C_028100_FMASK_TILE_MAX                      0x00000FFF
+#define R_028104_CB_COLOR1_MASK                      0x028104
+#define R_028108_CB_COLOR2_MASK                      0x028108
+#define R_02810C_CB_COLOR3_MASK                      0x02810C
+#define R_028110_CB_COLOR4_MASK                      0x028110
+#define R_028114_CB_COLOR5_MASK                      0x028114
+#define R_028118_CB_COLOR6_MASK                      0x028118
+#define R_02811C_CB_COLOR7_MASK                      0x02811C
 #define CB_COLOR0_INFO                                  0x280a0
 #      define CB_FORMAT(x)                             ((x) << 2)
 #       define CB_ARRAY_MODE(x)                         ((x) << 8)
 #define RLC_HB_WPTR                                       0x3f1c
 #define RLC_HB_WPTR_LSB_ADDR                              0x3f14
 #define RLC_HB_WPTR_MSB_ADDR                              0x3f18
+#define RLC_GPU_CLOCK_COUNT_LSB                                  0x3f38
+#define RLC_GPU_CLOCK_COUNT_MSB                                  0x3f3c
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                      0x3f40
 #define RLC_MC_CNTL                                       0x3f44
 #define RLC_UCODE_CNTL                                    0x3f48
 #define RLC_UCODE_ADDR                                    0x3f2c
 #define   S_0280A0_TILE_MODE(x)                        (((x) & 0x3) << 18)
 #define   G_0280A0_TILE_MODE(x)                        (((x) >> 18) & 0x3)
 #define   C_0280A0_TILE_MODE                           0xFFF3FFFF
+#define     V_0280A0_TILE_DISABLE                      0
+#define     V_0280A0_CLEAR_ENABLE                      1
+#define     V_0280A0_FRAG_ENABLE                       2
 #define   S_0280A0_BLEND_CLAMP(x)                      (((x) & 0x1) << 20)
 #define   G_0280A0_BLEND_CLAMP(x)                      (((x) >> 20) & 0x1)
 #define   C_0280A0_BLEND_CLAMP                         0xFFEFFFFF
index 5431af2924083676e7f017d13d2f32a4b9cc1aca..59a15315ae9fd2551e8745736cb15ff0f5e53280 100644 (file)
@@ -142,21 +142,6 @@ struct radeon_device;
 /*
  * BIOS.
  */
-#define ATRM_BIOS_PAGE 4096
-
-#if defined(CONFIG_VGA_SWITCHEROO)
-bool radeon_atrm_supported(struct pci_dev *pdev);
-int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len);
-#else
-static inline bool radeon_atrm_supported(struct pci_dev *pdev)
-{
-       return false;
-}
-
-static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){
-       return -EINVAL;
-}
-#endif
 bool radeon_get_bios(struct radeon_device *rdev);
 
 /*
@@ -300,6 +285,7 @@ struct radeon_bo_va {
        uint64_t                        soffset;
        uint64_t                        eoffset;
        uint32_t                        flags;
+       struct radeon_fence             *fence;
        bool                            valid;
 };
 
@@ -1533,6 +1519,7 @@ struct radeon_device {
        unsigned                debugfs_count;
        /* virtual memory */
        struct radeon_vm_manager        vm_manager;
+       struct mutex                    gpu_clock_mutex;
 };
 
 int radeon_device_init(struct radeon_device *rdev,
@@ -1733,11 +1720,11 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))
 #define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))
 #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev))
-#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pflip.pre_page_flip((rdev), (crtc))
-#define radeon_page_flip(rdev, crtc, base) rdev->asic->pflip.page_flip((rdev), (crtc), (base))
-#define radeon_post_page_flip(rdev, crtc) rdev->asic->pflip.post_page_flip((rdev), (crtc))
-#define radeon_wait_for_vblank(rdev, crtc) rdev->asic->display.wait_for_vblank((rdev), (crtc))
-#define radeon_mc_wait_for_idle(rdev) rdev->asic->mc_wait_for_idle((rdev))
+#define radeon_pre_page_flip(rdev, crtc) (rdev)->asic->pflip.pre_page_flip((rdev), (crtc))
+#define radeon_page_flip(rdev, crtc, base) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base))
+#define radeon_post_page_flip(rdev, crtc) (rdev)->asic->pflip.post_page_flip((rdev), (crtc))
+#define radeon_wait_for_vblank(rdev, crtc) (rdev)->asic->display.wait_for_vblank((rdev), (crtc))
+#define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
 
 /* Common functions */
 /* AGP */
index f4af243104387b752638b62809c876970b16ce76..18c38d14c8cd88c70499f2eb03d8a282ca3d68b9 100644 (file)
@@ -255,13 +255,10 @@ extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);
  * rv515
  */
 struct rv515_mc_save {
-       u32 d1vga_control;
-       u32 d2vga_control;
        u32 vga_render_control;
        u32 vga_hdp_control;
-       u32 d1crtc_control;
-       u32 d2crtc_control;
 };
+
 int rv515_init(struct radeon_device *rdev);
 void rv515_fini(struct radeon_device *rdev);
 uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
@@ -371,6 +368,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
                        unsigned num_gpu_pages,
                        struct radeon_sa_bo *vb);
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
+uint64_t r600_get_gpu_clock(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -389,11 +387,10 @@ void r700_cp_fini(struct radeon_device *rdev);
  * evergreen
  */
 struct evergreen_mc_save {
-       u32 vga_control[6];
        u32 vga_render_control;
        u32 vga_hdp_control;
-       u32 crtc_control[6];
 };
+
 void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);
 int evergreen_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);
@@ -472,5 +469,6 @@ int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id);
 void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
 void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm);
 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
+uint64_t si_get_gpu_clock(struct radeon_device *rdev);
 
 #endif
index b1e3820df36397e9c2ad7a7798be5412c0853df2..d67d4f3eb6f424d5400a7f01c2d1e3068785f02b 100644 (file)
@@ -452,7 +452,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
        }
 
        /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */
-       if ((dev->pdev->device == 0x9802) &&
+       if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) &&
            (dev->pdev->subsystem_vendor == 0x1734) &&
            (dev->pdev->subsystem_device == 0x11bd)) {
                if (*connector_type == DRM_MODE_CONNECTOR_VGA) {
@@ -1263,6 +1263,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
 union igp_info {
        struct _ATOM_INTEGRATED_SYSTEM_INFO info;
        struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+       struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+       struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
 };
 
 bool radeon_atombios_sideport_present(struct radeon_device *rdev)
@@ -1390,27 +1392,50 @@ static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
        struct radeon_mode_info *mode_info = &rdev->mode_info;
        int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
        u16 data_offset, size;
-       struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *igp_info;
+       union igp_info *igp_info;
        u8 frev, crev;
        u16 percentage = 0, rate = 0;
 
        /* get any igp specific overrides */
        if (atom_parse_data_header(mode_info->atom_context, index, &size,
                                   &frev, &crev, &data_offset)) {
-               igp_info = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *)
+               igp_info = (union igp_info *)
                        (mode_info->atom_context->bios + data_offset);
-               switch (id) {
-               case ASIC_INTERNAL_SS_ON_TMDS:
-                       percentage = le16_to_cpu(igp_info->usDVISSPercentage);
-                       rate = le16_to_cpu(igp_info->usDVISSpreadRateIn10Hz);
+               switch (crev) {
+               case 6:
+                       switch (id) {
+                       case ASIC_INTERNAL_SS_ON_TMDS:
+                               percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_HDMI:
+                               percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_LVDS:
+                               percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
+                               rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
+                               break;
+                       }
                        break;
-               case ASIC_INTERNAL_SS_ON_HDMI:
-                       percentage = le16_to_cpu(igp_info->usHDMISSPercentage);
-                       rate = le16_to_cpu(igp_info->usHDMISSpreadRateIn10Hz);
+               case 7:
+                       switch (id) {
+                       case ASIC_INTERNAL_SS_ON_TMDS:
+                               percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_HDMI:
+                               percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_LVDS:
+                               percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
+                               rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
+                               break;
+                       }
                        break;
-               case ASIC_INTERNAL_SS_ON_LVDS:
-                       percentage = le16_to_cpu(igp_info->usLvdsSSPercentage);
-                       rate = le16_to_cpu(igp_info->usLvdsSSpreadRateIn10Hz);
+               default:
+                       DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
                        break;
                }
                if (percentage)
index 98724fcb00885e8a6ba3e8e88937b209e545a8e8..2a2cf0b88a28b1e7f1c71c4bccbc029adacf63eb 100644 (file)
@@ -30,57 +30,8 @@ static struct radeon_atpx_priv {
        /* handle for device - and atpx */
        acpi_handle dhandle;
        acpi_handle atpx_handle;
-       acpi_handle atrm_handle;
 } radeon_atpx_priv;
 
-/* retrieve the ROM in 4k blocks */
-static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
-                           int offset, int len)
-{
-       acpi_status status;
-       union acpi_object atrm_arg_elements[2], *obj;
-       struct acpi_object_list atrm_arg;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
-
-       atrm_arg.count = 2;
-       atrm_arg.pointer = &atrm_arg_elements[0];
-
-       atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
-       atrm_arg_elements[0].integer.value = offset;
-
-       atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
-       atrm_arg_elements[1].integer.value = len;
-
-       status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
-       if (ACPI_FAILURE(status)) {
-               printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
-               return -ENODEV;
-       }
-
-       obj = (union acpi_object *)buffer.pointer;
-       memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
-       len = obj->buffer.length;
-       kfree(buffer.pointer);
-       return len;
-}
-
-bool radeon_atrm_supported(struct pci_dev *pdev)
-{
-       /* get the discrete ROM only via ATRM */
-       if (!radeon_atpx_priv.atpx_detected)
-               return false;
-
-       if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
-               return false;
-       return true;
-}
-
-
-int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
-{
-       return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len);
-}
-
 static int radeon_atpx_get_version(acpi_handle handle)
 {
        acpi_status status;
@@ -198,7 +149,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
 
 static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
 {
-       acpi_handle dhandle, atpx_handle, atrm_handle;
+       acpi_handle dhandle, atpx_handle;
        acpi_status status;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
        if (ACPI_FAILURE(status))
                return false;
 
-       status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
-       if (ACPI_FAILURE(status))
-               return false;
-
        radeon_atpx_priv.dhandle = dhandle;
        radeon_atpx_priv.atpx_handle = atpx_handle;
-       radeon_atpx_priv.atrm_handle = atrm_handle;
        return true;
 }
 
index 501f4881e5aab4d1f1dcb9b57b4ba1a61743d9a7..d306cc8fdeaa918294cf9576e0ab834d05882e87 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
+#include <linux/acpi.h>
 /*
  * BIOS.
  */
@@ -98,16 +99,81 @@ static bool radeon_read_bios(struct radeon_device *rdev)
        return true;
 }
 
+#ifdef CONFIG_ACPI
 /* ATRM is used to get the BIOS on the discrete cards in
  * dual-gpu systems.
  */
+/* retrieve the ROM in 4k blocks */
+#define ATRM_BIOS_PAGE 4096
+/**
+ * radeon_atrm_call - fetch a chunk of the vbios
+ *
+ * @atrm_handle: acpi ATRM handle
+ * @bios: vbios image pointer
+ * @offset: offset of vbios image data to fetch
+ * @len: length of vbios image data to fetch
+ *
+ * Executes ATRM to fetch a chunk of the discrete
+ * vbios image on PX systems (all asics).
+ * Returns the length of the buffer fetched.
+ */
+static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
+                           int offset, int len)
+{
+       acpi_status status;
+       union acpi_object atrm_arg_elements[2], *obj;
+       struct acpi_object_list atrm_arg;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
+
+       atrm_arg.count = 2;
+       atrm_arg.pointer = &atrm_arg_elements[0];
+
+       atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
+       atrm_arg_elements[0].integer.value = offset;
+
+       atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
+       atrm_arg_elements[1].integer.value = len;
+
+       status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
+       if (ACPI_FAILURE(status)) {
+               printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
+               return -ENODEV;
+       }
+
+       obj = (union acpi_object *)buffer.pointer;
+       memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
+       len = obj->buffer.length;
+       kfree(buffer.pointer);
+       return len;
+}
+
 static bool radeon_atrm_get_bios(struct radeon_device *rdev)
 {
        int ret;
        int size = 256 * 1024;
        int i;
+       struct pci_dev *pdev = NULL;
+       acpi_handle dhandle, atrm_handle;
+       acpi_status status;
+       bool found = false;
+
+       /* ATRM is for the discrete card only */
+       if (rdev->flags & RADEON_IS_IGP)
+               return false;
+
+       while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+               dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+               if (!dhandle)
+                       continue;
+
+               status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
+               if (!ACPI_FAILURE(status)) {
+                       found = true;
+                       break;
+               }
+       }
 
-       if (!radeon_atrm_supported(rdev->pdev))
+       if (!found)
                return false;
 
        rdev->bios = kmalloc(size, GFP_KERNEL);
@@ -117,9 +183,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
        }
 
        for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
-               ret = radeon_atrm_get_bios_chunk(rdev->bios,
-                                                (i * ATRM_BIOS_PAGE),
-                                                ATRM_BIOS_PAGE);
+               ret = radeon_atrm_call(atrm_handle,
+                                      rdev->bios,
+                                      (i * ATRM_BIOS_PAGE),
+                                      ATRM_BIOS_PAGE);
                if (ret < ATRM_BIOS_PAGE)
                        break;
        }
@@ -130,6 +197,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
        }
        return true;
 }
+#else
+static inline bool radeon_atrm_get_bios(struct radeon_device *rdev)
+{
+       return false;
+}
+#endif
 
 static bool ni_read_disabled_bios(struct radeon_device *rdev)
 {
@@ -476,6 +549,61 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
                return legacy_read_disabled_bios(rdev);
 }
 
+#ifdef CONFIG_ACPI
+static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
+{
+       bool ret = false;
+       struct acpi_table_header *hdr;
+       acpi_size tbl_size;
+       UEFI_ACPI_VFCT *vfct;
+       GOP_VBIOS_CONTENT *vbios;
+       VFCT_IMAGE_HEADER *vhdr;
+
+       if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size)))
+               return false;
+       if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
+               DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
+               goto out_unmap;
+       }
+
+       vfct = (UEFI_ACPI_VFCT *)hdr;
+       if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
+               DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
+               goto out_unmap;
+       }
+
+       vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
+       vhdr = &vbios->VbiosHeader;
+       DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
+                       vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
+                       vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
+
+       if (vhdr->PCIBus != rdev->pdev->bus->number ||
+           vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) ||
+           vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) ||
+           vhdr->VendorID != rdev->pdev->vendor ||
+           vhdr->DeviceID != rdev->pdev->device) {
+               DRM_INFO("ACPI VFCT table is not for this card\n");
+               goto out_unmap;
+       };
+
+       if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
+               DRM_ERROR("ACPI VFCT image truncated\n");
+               goto out_unmap;
+       }
+
+       rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
+       ret = !!rdev->bios;
+
+out_unmap:
+       return ret;
+}
+#else
+static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
+{
+       return false;
+}
+#endif
 
 bool radeon_get_bios(struct radeon_device *rdev)
 {
@@ -483,6 +611,8 @@ bool radeon_get_bios(struct radeon_device *rdev)
        uint16_t tmp;
 
        r = radeon_atrm_get_bios(rdev);
+       if (r == false)
+               r = radeon_acpi_vfct_bios(rdev);
        if (r == false)
                r = igp_read_bios_from_vram(rdev);
        if (r == false)
index 576f4f6919f28d075ba0e77365d0a0cc52814f25..f75247d42ffdca3bd62e778f51bba1c6b6d6ab78 100644 (file)
@@ -719,6 +719,34 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
        return i2c;
 }
 
+static struct radeon_i2c_bus_rec radeon_combios_get_i2c_info_from_table(struct radeon_device *rdev)
+{
+       struct drm_device *dev = rdev->ddev;
+       struct radeon_i2c_bus_rec i2c;
+       u16 offset;
+       u8 id, blocks, clk, data;
+       int i;
+
+       i2c.valid = false;
+
+       offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
+       if (offset) {
+               blocks = RBIOS8(offset + 2);
+               for (i = 0; i < blocks; i++) {
+                       id = RBIOS8(offset + 3 + (i * 5) + 0);
+                       if (id == 136) {
+                               clk = RBIOS8(offset + 3 + (i * 5) + 3);
+                               data = RBIOS8(offset + 3 + (i * 5) + 4);
+                               /* gpiopad */
+                               i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
+                                                           (1 << clk), (1 << data));
+                               break;
+                       }
+               }
+       }
+       return i2c;
+}
+
 void radeon_combios_i2c_init(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
@@ -755,30 +783,14 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
        } else if (rdev->family == CHIP_RS300 ||
                   rdev->family == CHIP_RS400 ||
                   rdev->family == CHIP_RS480) {
-               u16 offset;
-               u8 id, blocks, clk, data;
-               int i;
-
                /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
 
-               offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
-               if (offset) {
-                       blocks = RBIOS8(offset + 2);
-                       for (i = 0; i < blocks; i++) {
-                               id = RBIOS8(offset + 3 + (i * 5) + 0);
-                               if (id == 136) {
-                                       clk = RBIOS8(offset + 3 + (i * 5) + 3);
-                                       data = RBIOS8(offset + 3 + (i * 5) + 4);
-                                       /* gpiopad */
-                                       i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
-                                                                   (1 << clk), (1 << data));
-                                       rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
-                                       break;
-                               }
-                       }
-               }
+               /* gpiopad */
+               i2c = radeon_combios_get_i2c_info_from_table(rdev);
+               if (i2c.valid)
+                       rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
        } else if ((rdev->family == CHIP_R200) ||
                   (rdev->family >= CHIP_R300)) {
                /* 0x68 */
@@ -2321,7 +2333,10 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                        connector = (tmp >> 12) & 0xf;
 
                        ddc_type = (tmp >> 8) & 0xf;
-                       ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
+                       if (ddc_type == 5)
+                               ddc_i2c = radeon_combios_get_i2c_info_from_table(rdev);
+                       else
+                               ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
 
                        switch (connector) {
                        case CONNECTOR_PROPRIETARY_LEGACY:
index 8a4c49ef0cc4e40170b3300aa7ad9cffeea2bc72..b4a0db24f4ddc4611028b671499d5062bd713649 100644 (file)
@@ -278,6 +278,30 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        return 0;
 }
 
+static void radeon_bo_vm_fence_va(struct radeon_cs_parser *parser,
+                                 struct radeon_fence *fence)
+{
+       struct radeon_fpriv *fpriv = parser->filp->driver_priv;
+       struct radeon_vm *vm = &fpriv->vm;
+       struct radeon_bo_list *lobj;
+
+       if (parser->chunk_ib_idx == -1) {
+               return;
+       }
+       if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) {
+               return;
+       }
+
+       list_for_each_entry(lobj, &parser->validated, tv.head) {
+               struct radeon_bo_va *bo_va;
+               struct radeon_bo *rbo = lobj->bo;
+
+               bo_va = radeon_bo_va(rbo, vm);
+               radeon_fence_unref(&bo_va->fence);
+               bo_va->fence = radeon_fence_ref(fence);
+       }
+}
+
 /**
  * cs_parser_fini() - clean parser states
  * @parser:    parser structure holding parsing context.
@@ -290,11 +314,14 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
 {
        unsigned i;
 
-       if (!error)
+       if (!error) {
+               /* fence all bo va before ttm_eu_fence_buffer_objects so bo are still reserved */
+               radeon_bo_vm_fence_va(parser, parser->ib.fence);
                ttm_eu_fence_buffer_objects(&parser->validated,
                                            parser->ib.fence);
-       else
+       } else {
                ttm_eu_backoff_reservation(&parser->validated);
+       }
 
        if (parser->relocs != NULL) {
                for (i = 0; i < parser->nrelocs; i++) {
@@ -388,7 +415,6 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
 
        if (parser->chunk_ib_idx == -1)
                return 0;
-
        if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)
                return 0;
 
index 711e95ad39bfd600de1be7f94373dc57512ef820..8794744cdf1a58c1c14cb5c0d59dc595f80d05be 100644 (file)
@@ -67,7 +67,8 @@ static void radeon_hide_cursor(struct drm_crtc *crtc)
 
        if (ASIC_IS_DCE4(rdev)) {
                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
-               WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
+               WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
+                      EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
        } else if (ASIC_IS_AVIVO(rdev)) {
                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
@@ -94,7 +95,8 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
        if (ASIC_IS_DCE4(rdev)) {
                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
-                      EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
+                      EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
+                      EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
        } else if (ASIC_IS_AVIVO(rdev)) {
                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
index 742af8244e898e565aed6bb9fa6dcffe1521dd98..d2e243867ac6f3c9fe4d6c28e25fa421cac6c48b 100644 (file)
@@ -1009,6 +1009,7 @@ int radeon_device_init(struct radeon_device *rdev,
        atomic_set(&rdev->ih.lock, 0);
        mutex_init(&rdev->gem.mutex);
        mutex_init(&rdev->pm.mutex);
+       mutex_init(&rdev->gpu_clock_mutex);
        init_rwsem(&rdev->pm.mclk_lock);
        init_rwsem(&rdev->exclusive_lock);
        init_waitqueue_head(&rdev->irq.vblank_queue);
index dcea6f01ae4e2ec3fe60def4a345c2528d3fedc9..27d22d709c9040561c61e51013d0418ab3625e31 100644 (file)
  *   2.15.0 - add max_pipes query
  *   2.16.0 - fix evergreen 2D tiled surface calculation
  *   2.17.0 - add STRMOUT_BASE_UPDATE for r7xx
+ *   2.18.0 - r600-eg: allow "invalid" DB formats
+ *   2.19.0 - r600-eg: MSAA textures
+ *   2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query
+ *   2.21.0 - r600-r700: FMASK and CMASK
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       17
+#define KMS_DRIVER_MINOR       21
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index b3720054614db5199684ad1d86924a1fd5c8f34d..bb3b7fe05ccdfe2905b9dc6650e854e6361dec8c 100644 (file)
@@ -814,7 +814,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
                return -EINVAL;
        }
 
-       if (bo_va->valid)
+       if (bo_va->valid && mem)
                return 0;
 
        ngpu_pages = radeon_bo_ngpu_pages(bo);
@@ -859,11 +859,27 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
                     struct radeon_bo *bo)
 {
        struct radeon_bo_va *bo_va;
+       int r;
 
        bo_va = radeon_bo_va(bo, vm);
        if (bo_va == NULL)
                return 0;
 
+       /* wait for va use to end */
+       while (bo_va->fence) {
+               r = radeon_fence_wait(bo_va->fence, false);
+               if (r) {
+                       DRM_ERROR("error while waiting for fence: %d\n", r);
+               }
+               if (r == -EDEADLK) {
+                       r = radeon_gpu_reset(rdev);
+                       if (!r)
+                               continue;
+               }
+               break;
+       }
+       radeon_fence_unref(&bo_va->fence);
+
        mutex_lock(&rdev->vm_manager.lock);
        mutex_lock(&vm->mutex);
        radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
@@ -934,7 +950,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
 }
 
 /**
- * radeon_vm_init - tear down a vm instance
+ * radeon_vm_fini - tear down a vm instance
  *
  * @rdev: radeon_device pointer
  * @vm: requested vm
@@ -952,12 +968,15 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
        radeon_vm_unbind_locked(rdev, vm);
        mutex_unlock(&rdev->vm_manager.lock);
 
-       /* remove all bo */
+       /* remove all bo at this point non are busy any more because unbind
+        * waited for the last vm fence to signal
+        */
        r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
        if (!r) {
                bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);
                list_del_init(&bo_va->bo_list);
                list_del_init(&bo_va->vm_list);
+               radeon_fence_unref(&bo_va->fence);
                radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
                kfree(bo_va);
        }
@@ -969,6 +988,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
                r = radeon_bo_reserve(bo_va->bo, false);
                if (!r) {
                        list_del_init(&bo_va->bo_list);
+                       radeon_fence_unref(&bo_va->fence);
                        radeon_bo_unreserve(bo_va->bo);
                        kfree(bo_va);
                }
index 84d045245739eb3b049e78f88693d6dc1dd229da..1b57b0058ad642e6d0d610dadbf7af235f517c71 100644 (file)
@@ -134,25 +134,16 @@ void radeon_gem_object_close(struct drm_gem_object *obj,
        struct radeon_device *rdev = rbo->rdev;
        struct radeon_fpriv *fpriv = file_priv->driver_priv;
        struct radeon_vm *vm = &fpriv->vm;
-       struct radeon_bo_va *bo_va, *tmp;
 
        if (rdev->family < CHIP_CAYMAN) {
                return;
        }
 
        if (radeon_bo_reserve(rbo, false)) {
+               dev_err(rdev->dev, "leaking bo va because we fail to reserve bo\n");
                return;
        }
-       list_for_each_entry_safe(bo_va, tmp, &rbo->va, bo_list) {
-               if (bo_va->vm == vm) {
-                       /* remove from this vm address space */
-                       mutex_lock(&vm->mutex);
-                       list_del(&bo_va->vm_list);
-                       mutex_unlock(&vm->mutex);
-                       list_del(&bo_va->bo_list);
-                       kfree(bo_va);
-               }
-       }
+       radeon_vm_bo_rmv(rdev, vm, rbo);
        radeon_bo_unreserve(rbo);
 }
 
index 1d73f16b5d97d4b480d18cf3831e134f66fa5e29..414b4acf69479abdfdcda63f226d112c0e3387da 100644 (file)
@@ -29,6 +29,7 @@
 #include "drm_sarea.h"
 #include "radeon.h"
 #include "radeon_drm.h"
+#include "radeon_asic.h"
 
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
@@ -167,17 +168,39 @@ static void radeon_set_filp_rights(struct drm_device *dev,
 int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 {
        struct radeon_device *rdev = dev->dev_private;
-       struct drm_radeon_info *info;
+       struct drm_radeon_info *info = data;
        struct radeon_mode_info *minfo = &rdev->mode_info;
-       uint32_t *value_ptr;
-       uint32_t value;
+       uint32_t value, *value_ptr;
+       uint64_t value64, *value_ptr64;
        struct drm_crtc *crtc;
        int i, found;
 
-       info = data;
+       /* TIMESTAMP is a 64-bit value, needs special handling. */
+       if (info->request == RADEON_INFO_TIMESTAMP) {
+               if (rdev->family >= CHIP_R600) {
+                       value_ptr64 = (uint64_t*)((unsigned long)info->value);
+                       if (rdev->family >= CHIP_TAHITI) {
+                               value64 = si_get_gpu_clock(rdev);
+                       } else {
+                               value64 = r600_get_gpu_clock(rdev);
+                       }
+
+                       if (DRM_COPY_TO_USER(value_ptr64, &value64, sizeof(value64))) {
+                               DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
+                               return -EFAULT;
+                       }
+                       return 0;
+               } else {
+                       DRM_DEBUG_KMS("timestamp is r6xx+ only!\n");
+                       return -EINVAL;
+               }
+       }
+
        value_ptr = (uint32_t *)((unsigned long)info->value);
-       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
+       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) {
+               DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
+       }
 
        switch (info->request) {
        case RADEON_INFO_DEVICE_ID:
@@ -337,7 +360,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                return -EINVAL;
        }
        if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
-               DRM_ERROR("copy_to_user\n");
+               DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
        }
        return 0;
index d5fd615897ec75ad13d8b1b1e7ddd1e85a1a859b..94b4a1c12893baab8ce72854661ed443fea1cfe0 100644 (file)
@@ -1025,9 +1025,11 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
 
 static void radeon_crtc_prepare(struct drm_crtc *crtc)
 {
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_crtc *crtci;
 
+       radeon_crtc->in_mode_set = true;
        /*
        * The hardware wedges sometimes if you reconfigure one CRTC
        * whilst another is running (see fdo bug #24611).
@@ -1038,6 +1040,7 @@ static void radeon_crtc_prepare(struct drm_crtc *crtc)
 
 static void radeon_crtc_commit(struct drm_crtc *crtc)
 {
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_crtc *crtci;
 
@@ -1048,6 +1051,7 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
                if (crtci->enabled)
                        radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
        }
+       radeon_crtc->in_mode_set = false;
 }
 
 static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
index f380d59c5763425f0fc0bd79a8733d15bcfdca33..d56978949f34927169cf3db6a832361f2139cb4b 100644 (file)
@@ -275,6 +275,7 @@ struct radeon_crtc {
        u16 lut_r[256], lut_g[256], lut_b[256];
        bool enabled;
        bool can_tile;
+       bool in_mode_set;
        uint32_t crtc_offset;
        struct drm_gem_object *cursor_bo;
        uint64_t cursor_addr;
index 1f1a4c803c1dd267158dece882e8fdf5b2d6b871..9024e72228396068208d51e8dbf13fd8a8676307 100644 (file)
@@ -52,11 +52,7 @@ void radeon_bo_clear_va(struct radeon_bo *bo)
 
        list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) {
                /* remove from all vm address space */
-               mutex_lock(&bo_va->vm->mutex);
-               list_del(&bo_va->vm_list);
-               mutex_unlock(&bo_va->vm->mutex);
-               list_del(&bo_va->bo_list);
-               kfree(bo_va);
+               radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo);
        }
 }
 
@@ -136,6 +132,7 @@ int radeon_bo_create(struct radeon_device *rdev,
        acc_size = ttm_bo_dma_acc_size(&rdev->mman.bdev, size,
                                       sizeof(struct radeon_bo));
 
+retry:
        bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
        if (bo == NULL)
                return -ENOMEM;
@@ -149,8 +146,6 @@ int radeon_bo_create(struct radeon_device *rdev,
        bo->surface_reg = -1;
        INIT_LIST_HEAD(&bo->list);
        INIT_LIST_HEAD(&bo->va);
-
-retry:
        radeon_ttm_placement_from_domain(bo, domain);
        /* Kernel allocation are uninterruptible */
        down_read(&rdev->pm.mclk_lock);
index ec79b37504306f2709036bebe6949f7afc2a90cf..43c431a2686db86428059593dc3f853d87688d9c 100644 (file)
@@ -706,6 +706,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
        if (radeon_debugfs_ring_init(rdev, ring)) {
                DRM_ERROR("Failed to register debugfs file for rings !\n");
        }
+       radeon_ring_lockup_update(ring);
        return 0;
 }
 
index 5e659b034d9a379d362327541480b2eeef70bf61..f93e45d869f401225e853d81d2e9ec44baf092e6 100644 (file)
@@ -744,14 +744,6 @@ r600 0x9400
 0x00028C38 CB_CLRCMP_DST
 0x00028C3C CB_CLRCMP_MSK
 0x00028C34 CB_CLRCMP_SRC
-0x00028100 CB_COLOR0_MASK
-0x00028104 CB_COLOR1_MASK
-0x00028108 CB_COLOR2_MASK
-0x0002810C CB_COLOR3_MASK
-0x00028110 CB_COLOR4_MASK
-0x00028114 CB_COLOR5_MASK
-0x00028118 CB_COLOR6_MASK
-0x0002811C CB_COLOR7_MASK
 0x00028808 CB_COLOR_CONTROL
 0x0002842C CB_FOG_BLUE
 0x00028428 CB_FOG_GREEN
index a12fbcc8ccb6834a9fba7b0d5cb08418538b52e9..aa8ef491ef3c17619ee9f1e64dd8262c5e74e103 100644 (file)
@@ -281,12 +281,8 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
 
 void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
 {
-       save->d1vga_control = RREG32(R_000330_D1VGA_CONTROL);
-       save->d2vga_control = RREG32(R_000338_D2VGA_CONTROL);
        save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL);
        save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL);
-       save->d1crtc_control = RREG32(R_006080_D1CRTC_CONTROL);
-       save->d2crtc_control = RREG32(R_006880_D2CRTC_CONTROL);
 
        /* Stop all video */
        WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
@@ -311,15 +307,6 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
        /* Unlock host access */
        WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control);
        mdelay(1);
-       /* Restore video state */
-       WREG32(R_000330_D1VGA_CONTROL, save->d1vga_control);
-       WREG32(R_000338_D2VGA_CONTROL, save->d2vga_control);
-       WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 1);
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 1);
-       WREG32(R_006080_D1CRTC_CONTROL, save->d1crtc_control);
-       WREG32(R_006880_D2CRTC_CONTROL, save->d2crtc_control);
-       WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 0);
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
        WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control);
 }
 
index c053f8193771a1df17cfa092cabf15caaff880db..0139e227e3c7241712c5ed951f38b52f5120c564 100644 (file)
@@ -1639,11 +1639,19 @@ static void si_gpu_init(struct radeon_device *rdev)
                /* XXX what about 12? */
                rdev->config.si.tile_config |= (3 << 0);
                break;
-       }
-       if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-               rdev->config.si.tile_config |= 1 << 4;
-       else
+       }       
+       switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
+       case 0: /* four banks */
                rdev->config.si.tile_config |= 0 << 4;
+               break;
+       case 1: /* eight banks */
+               rdev->config.si.tile_config |= 1 << 4;
+               break;
+       case 2: /* sixteen banks */
+       default:
+               rdev->config.si.tile_config |= 2 << 4;
+               break;
+       }
        rdev->config.si.tile_config |=
                ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
        rdev->config.si.tile_config |=
@@ -3960,3 +3968,22 @@ void si_fini(struct radeon_device *rdev)
        rdev->bios = NULL;
 }
 
+/**
+ * si_get_gpu_clock - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (SI).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t si_get_gpu_clock(struct radeon_device *rdev)
+{
+       uint64_t clock;
+
+       mutex_lock(&rdev->gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&rdev->gpu_clock_mutex);
+       return clock;
+}
index 7869089e87619562663ca96c1c035c74b7dba710..ef4815c27b1c673e50ab9d675382586686b6495d 100644 (file)
 #define RLC_UCODE_ADDR                                    0xC32C
 #define RLC_UCODE_DATA                                    0xC330
 
+#define RLC_GPU_CLOCK_COUNT_LSB                           0xC338
+#define RLC_GPU_CLOCK_COUNT_MSB                           0xC33C
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC340
 #define RLC_MC_CNTL                                       0xC344
 #define RLC_UCODE_CNTL                                    0xC348
 
index 0b5e096d39a6a7b590b55acd63ad30a21f241081..56e0bf31d425a6f90f7ad6cc9f2a9c4cbb993739 100644 (file)
@@ -1,6 +1,7 @@
 config DRM_UDL
        tristate "DisplayLink"
        depends on DRM && EXPERIMENTAL
+       depends on USB_ARCH_HAS_HCD
        select DRM_USB
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
index 7bd65bdd15a8092e955d959c08fd6dd04781d490..291ecc1455850400f6e596cde59dfac1acda83d4 100644 (file)
@@ -308,7 +308,7 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
        /* need to attach */
        attach = dma_buf_attach(dma_buf, dev->dev);
        if (IS_ERR(attach))
-               return ERR_PTR(PTR_ERR(attach));
+               return ERR_CAST(attach);
 
        sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
        if (IS_ERR(sg)) {
index f5dd89e891de0c165541178c2f0c6a7c74964303..9159d48d1dfd570521c43755596466788411beba 100644 (file)
@@ -354,8 +354,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
 
 static void udl_crtc_disable(struct drm_crtc *crtc)
 {
-
-
+       udl_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 static void udl_crtc_destroy(struct drm_crtc *crtc)
index 6b0078ffa7638b163abb2a286e6b8d579daae4a5..c50724bd30f6e052e2f80e6f823379241944ff60 100644 (file)
@@ -1688,15 +1688,19 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
        struct vmw_private *dev_priv = vmw_priv(crtc->dev);
        struct drm_framebuffer *old_fb = crtc->fb;
        struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
-       struct drm_file *file_priv = event->base.file_priv;
+       struct drm_file *file_priv ;
        struct vmw_fence_obj *fence = NULL;
        struct drm_clip_rect clips;
        int ret;
 
+       if (event == NULL)
+               return -EINVAL;
+
        /* require ScreenObject support for page flipping */
        if (!dev_priv->sou_priv)
                return -ENOSYS;
 
+       file_priv = event->base.file_priv;
        if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
                return -EINVAL;
 
index 5b3c7d135dc91c407fc9b2bf19b2e3e912ccfed5..e25cf31faab2b10a027d3f3c860887214ba431d1 100644 (file)
@@ -70,27 +70,12 @@ static struct vgasr_priv vgasr_priv = {
        .clients = LIST_HEAD_INIT(vgasr_priv.clients),
 };
 
-int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
-{
-       mutex_lock(&vgasr_mutex);
-       if (vgasr_priv.handler) {
-               mutex_unlock(&vgasr_mutex);
-               return -EINVAL;
-       }
-
-       vgasr_priv.handler = handler;
-       mutex_unlock(&vgasr_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(vga_switcheroo_register_handler);
-
-void vga_switcheroo_unregister_handler(void)
+static bool vga_switcheroo_ready(void)
 {
-       mutex_lock(&vgasr_mutex);
-       vgasr_priv.handler = NULL;
-       mutex_unlock(&vgasr_mutex);
+       /* we're ready if we get two clients + handler */
+       return !vgasr_priv.active &&
+              vgasr_priv.registered_clients == 2 && vgasr_priv.handler;
 }
-EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
 
 static void vga_switcheroo_enable(void)
 {
@@ -98,7 +83,8 @@ static void vga_switcheroo_enable(void)
        struct vga_switcheroo_client *client;
 
        /* call the handler to init */
-       vgasr_priv.handler->init();
+       if (vgasr_priv.handler->init)
+               vgasr_priv.handler->init();
 
        list_for_each_entry(client, &vgasr_priv.clients, list) {
                if (client->id != -1)
@@ -113,6 +99,37 @@ static void vga_switcheroo_enable(void)
        vgasr_priv.active = true;
 }
 
+int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
+{
+       mutex_lock(&vgasr_mutex);
+       if (vgasr_priv.handler) {
+               mutex_unlock(&vgasr_mutex);
+               return -EINVAL;
+       }
+
+       vgasr_priv.handler = handler;
+       if (vga_switcheroo_ready()) {
+               printk(KERN_INFO "vga_switcheroo: enabled\n");
+               vga_switcheroo_enable();
+       }
+       mutex_unlock(&vgasr_mutex);
+       return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_register_handler);
+
+void vga_switcheroo_unregister_handler(void)
+{
+       mutex_lock(&vgasr_mutex);
+       vgasr_priv.handler = NULL;
+       if (vgasr_priv.active) {
+               pr_info("vga_switcheroo: disabled\n");
+               vga_switcheroo_debugfs_fini(&vgasr_priv);
+               vgasr_priv.active = false;
+       }
+       mutex_unlock(&vgasr_mutex);
+}
+EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
+
 static int register_client(struct pci_dev *pdev,
                           const struct vga_switcheroo_client_ops *ops,
                           int id, bool active)
@@ -134,9 +151,7 @@ static int register_client(struct pci_dev *pdev,
        if (client_is_vga(client))
                vgasr_priv.registered_clients++;
 
-       /* if we get two clients + handler */
-       if (!vgasr_priv.active &&
-           vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
+       if (vga_switcheroo_ready()) {
                printk(KERN_INFO "vga_switcheroo: enabled\n");
                vga_switcheroo_enable();
        }
index faa16f80db9cf652bbc75aaa7e5fd0e73b788ca4..0fa356fe82ccc00fc6a70704627da99bb66fc49a 100644 (file)
@@ -196,7 +196,7 @@ struct tjmax {
        int tjmax;
 };
 
-static struct tjmax __cpuinitconst tjmax_table[] = {
+static const struct tjmax __cpuinitconst tjmax_table[] = {
        { "CPU D410", 100000 },
        { "CPU D425", 100000 },
        { "CPU D510", 100000 },
index ab4825205a9db30436404c64a9ee4d79acc2d535..5b1a6a666441f242ac63f21d9b9359464ced3f97 100644 (file)
@@ -1206,7 +1206,7 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
        int err = -ENODEV;
        u16 val;
 
-       static const __initdata char *names[] = {
+       static __initconst char *const names[] = {
                "W83627HF",
                "W83627THF",
                "W83697HF",
index aedb94f34bf748c1e82846f817264c1f73b2e602..dae3ddfe7619cf69899d974992ea0e7b43264b59 100644 (file)
@@ -405,6 +405,7 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                        }
                }
        }
+       ret = num;
 abort:
        sret = diolan_i2c_stop(dev);
        if (sret < 0 && ret >= 0)
index 5e6f1eed4f83f233da76202c70d7564f773d3e1c..61b00edacb08179894c83b91d1f0cbe39a768b37 100644 (file)
@@ -350,10 +350,6 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
 
        i2c_clk = clk_get_rate(dev->clk);
 
-       /* fallback to std. mode if machine has not provided it */
-       if (dev->cfg.clk_freq == 0)
-               dev->cfg.clk_freq = 100000;
-
        /*
         * The spec says, in case of std. mode the divider is
         * 2 whereas it is 3 for fast and fastplus mode of
@@ -911,20 +907,32 @@ static const struct i2c_algorithm nmk_i2c_algo = {
        .functionality  = nmk_i2c_functionality
 };
 
+static struct nmk_i2c_controller u8500_i2c = {
+       /*
+        * Slave data setup time; 250ns, 100ns, and 10ns, which
+        * is 14, 6 and 2 respectively for a 48Mhz i2c clock.
+        */
+       .slsu           = 0xe,
+       .tft            = 1,      /* Tx FIFO threshold */
+       .rft            = 8,      /* Rx FIFO threshold */
+       .clk_freq       = 400000, /* fast mode operation */
+       .timeout        = 200,    /* Slave response timeout(ms) */
+       .sm             = I2C_FREQ_MODE_FAST,
+};
+
 static atomic_t adapter_id = ATOMIC_INIT(0);
 
 static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
-       struct nmk_i2c_controller *pdata =
-                       adev->dev.platform_data;
+       struct nmk_i2c_controller *pdata = adev->dev.platform_data;
        struct nmk_i2c_dev      *dev;
        struct i2c_adapter *adap;
 
-       if (!pdata) {
-               dev_warn(&adev->dev, "no platform data\n");
-               return -ENODEV;
-       }
+       if (!pdata)
+               /* No i2c configuration found, using the default. */
+               pdata = &u8500_i2c;
+
        dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
        if (!dev) {
                dev_err(&adev->dev, "cannot allocate memory\n");
index 6849635b268a81fe8f85d380d2d80d16ba6ab2b1..5d19a49803c152089c85b5b51c4d83cbb7a91cda 100644 (file)
@@ -584,7 +584,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
        r = pm_runtime_get_sync(dev->dev);
        if (IS_ERR_VALUE(r))
-               return r;
+               goto out;
 
        r = omap_i2c_wait_for_bb(dev);
        if (r < 0)
index 66eb53fac2022363c3cf90fa96d0ad6358234acc..9a08c57bc9369eea10b7419a8d52f6c08812f270 100644 (file)
@@ -712,7 +712,7 @@ static int __devexit tegra_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int tegra_i2c_suspend(struct device *dev)
 {
        struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
index f559088869f6451fc349a808778266b4f77557a9..e8726177d103082021a6549d4ce32d161e2bab2a 100644 (file)
@@ -606,8 +606,9 @@ static int __init intel_idle_init(void)
        intel_idle_cpuidle_driver_init();
        retval = cpuidle_register_driver(&intel_idle_driver);
        if (retval) {
+               struct cpuidle_driver *drv = cpuidle_get_driver();
                printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
-                       cpuidle_get_driver()->name);
+                       drv ? drv->name : "none");
                return retval;
        }
 
index 59fbb3ae40e7f4628b3bc9d545a27c86e379bdbc..e35bb8f6fe7597e8823527772b119cd3b579377d 100644 (file)
@@ -129,7 +129,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
 {
        struct adf4350_platform_data *pdata = st->pdata;
        u64 tmp;
-       u32 div_gcd, prescaler;
+       u32 div_gcd, prescaler, chspc;
        u16 mdiv, r_cnt = 0;
        u8 band_sel_div;
 
@@ -158,14 +158,20 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
        if (pdata->ref_div_factor)
                r_cnt = pdata->ref_div_factor - 1;
 
-       do  {
-               r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+       chspc = st->chspc;
 
-               st->r1_mod = st->fpfd / st->chspc;
-               while (st->r1_mod > ADF4350_MAX_MODULUS) {
-                       r_cnt = adf4350_tune_r_cnt(st, r_cnt);
-                       st->r1_mod = st->fpfd / st->chspc;
-               }
+       do  {
+               do {
+                       do {
+                               r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+                               st->r1_mod = st->fpfd / chspc;
+                               if (r_cnt > ADF4350_MAX_R_CNT) {
+                                       /* try higher spacing values */
+                                       chspc++;
+                                       r_cnt = 0;
+                               }
+                       } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt);
+               } while (r_cnt == 0);
 
                tmp = freq * (u64)st->r1_mod + (st->fpfd > 1);
                do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
@@ -194,7 +200,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
        st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) |
                                 ADF4350_REG0_FRACT(st->r0_fract);
 
-       st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(0) |
+       st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(1) |
                                 ADF4350_REG1_MOD(st->r1_mod) |
                                 prescaler;
 
index 1cbb449b319a8e9399af3b427342fb1702b1b173..9a99f43094f0824dde61203647462a8872faab83 100644 (file)
@@ -271,9 +271,10 @@ static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
        const unsigned long *scan_mask)
 {
        struct adjd_s311_data *data = iio_priv(indio_dev);
-       data->buffer = krealloc(data->buffer, indio_dev->scan_bytes,
-                               GFP_KERNEL);
-       if (!data->buffer)
+
+       kfree(data->buffer);
+       data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+       if (data->buffer == NULL)
                return -ENOMEM;
 
        return 0;
index c3e7bac1312318470f29c805ca2ccdcfb6790402..e45712a921ce600cee7c10aa2d8a4dcbc46fccba 100644 (file)
@@ -404,7 +404,7 @@ out:
        return ret;
 }
 
-static int show_thresh_either_en(struct device *dev,
+static ssize_t show_thresh_either_en(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
@@ -424,7 +424,7 @@ static int show_thresh_either_en(struct device *dev,
        return scnprintf(buf, PAGE_SIZE, "%u\n", enable);
 }
 
-static int store_thresh_either_en(struct device *dev,
+static ssize_t store_thresh_either_en(struct device *dev,
                                        struct device_attribute *attr,
                                        const char *buf, size_t len)
 {
index 6bf8504228957eb8341342c16cfa9b88a234c8bd..055ed59838dca128eef4986a9b3186a1f0588b84 100644 (file)
@@ -267,6 +267,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
        if (!uevent)
                return event->event == RDMA_CM_EVENT_CONNECT_REQUEST;
 
+       mutex_lock(&ctx->file->mut);
        uevent->cm_id = cm_id;
        ucma_set_event_context(ctx, event, uevent);
        uevent->resp.event = event->event;
@@ -277,7 +278,6 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
                ucma_copy_conn_event(&uevent->resp.param.conn,
                                     &event->param.conn);
 
-       mutex_lock(&ctx->file->mut);
        if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
                if (!ctx->backlog) {
                        ret = -ENOMEM;
index 8c81992fa6db26275615d8f7f9e3998dd4223b7a..e4a73158fc7fc0392d9308146f2c695936b80532 100644 (file)
@@ -439,7 +439,7 @@ static int c2_rnic_close(struct c2_dev *c2dev)
 
 /*
  * Called by c2_probe to initialize the RNIC. This principally
- * involves initalizing the various limits and resouce pools that
+ * involves initializing the various limits and resource pools that
  * comprise the RNIC instance.
  */
 int __devinit c2_rnic_init(struct c2_dev *c2dev)
index 77b6b182778ad642b23bb9dc6a8f943cf83a6a10..aaf88ef9409cddfabef4fb90c88347e27887d464 100644 (file)
@@ -1680,7 +1680,7 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
  * T3A does 3 things when a TERM is received:
  * 1) send up a CPL_RDMA_TERMINATE message with the TERM packet
  * 2) generate an async event on the QP with the TERMINATE opcode
- * 3) post a TERMINATE opcde cqe into the associated CQ.
+ * 3) post a TERMINATE opcode cqe into the associated CQ.
  *
  * For (1), we save the message in the qp for later consumer consumption.
  * For (2), we move the QP into TERMINATE, post a QP event and disconnect.
index c27141fef1ab2f6dca170bb07aecd11ecaa3d48b..9c2ae7efd00f4c03db74d67a4b5e8d84b0a87e28 100644 (file)
@@ -125,6 +125,7 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
 {
        struct ib_ah *new_ah;
        struct ib_ah_attr ah_attr;
+       unsigned long flags;
 
        if (!dev->send_agent[port_num - 1][0])
                return;
@@ -139,11 +140,11 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
        if (IS_ERR(new_ah))
                return;
 
-       spin_lock(&dev->sm_lock);
+       spin_lock_irqsave(&dev->sm_lock, flags);
        if (dev->sm_ah[port_num - 1])
                ib_destroy_ah(dev->sm_ah[port_num - 1]);
        dev->sm_ah[port_num - 1] = new_ah;
-       spin_unlock(&dev->sm_lock);
+       spin_unlock_irqrestore(&dev->sm_lock, flags);
 }
 
 /*
@@ -197,13 +198,15 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad,
 static void node_desc_override(struct ib_device *dev,
                               struct ib_mad *mad)
 {
+       unsigned long flags;
+
        if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
             mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
            mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
            mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
-               spin_lock(&to_mdev(dev)->sm_lock);
+               spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags);
                memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
-               spin_unlock(&to_mdev(dev)->sm_lock);
+               spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags);
        }
 }
 
@@ -213,6 +216,7 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
        struct ib_mad_send_buf *send_buf;
        struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
        int ret;
+       unsigned long flags;
 
        if (agent) {
                send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
@@ -225,13 +229,13 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
                 * wrong following the IB spec strictly, but we know
                 * it's OK for our devices).
                 */
-               spin_lock(&dev->sm_lock);
+               spin_lock_irqsave(&dev->sm_lock, flags);
                memcpy(send_buf->mad, mad, sizeof *mad);
                if ((send_buf->ah = dev->sm_ah[port_num - 1]))
                        ret = ib_post_send_mad(send_buf, NULL);
                else
                        ret = -EINVAL;
-               spin_unlock(&dev->sm_lock);
+               spin_unlock_irqrestore(&dev->sm_lock, flags);
 
                if (ret)
                        ib_free_send_mad(send_buf);
index fe2088cfa6eef699f0222b710aeb3de930c1c139..cc05579ebce7fd6b5f5fc9c86b2a1452db0101a7 100644 (file)
@@ -423,6 +423,7 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
                                 struct ib_device_modify *props)
 {
        struct mlx4_cmd_mailbox *mailbox;
+       unsigned long flags;
 
        if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
                return -EOPNOTSUPP;
@@ -430,9 +431,9 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
        if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
                return 0;
 
-       spin_lock(&to_mdev(ibdev)->sm_lock);
+       spin_lock_irqsave(&to_mdev(ibdev)->sm_lock, flags);
        memcpy(ibdev->node_desc, props->node_desc, 64);
-       spin_unlock(&to_mdev(ibdev)->sm_lock);
+       spin_unlock_irqrestore(&to_mdev(ibdev)->sm_lock, flags);
 
        /*
         * If possible, pass node desc to FW, so it can generate
index a6d8ea060ea896ad4f7c7d9a8639a8be8f67fb4e..f585eddef4b7d5c7921575cebaa508eefde4f934 100644 (file)
@@ -1407,6 +1407,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
        struct mlx4_wqe_mlx_seg *mlx = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
        struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       struct net_device *ndev;
        union ib_gid sgid;
        u16 pkey;
        int send_size;
@@ -1483,7 +1484,10 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 
                memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
                /* FIXME: cache smac value? */
-               smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+               ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1];
+               if (!ndev)
+                       return -ENODEV;
+               smac = ndev->dev_addr;
                memcpy(sqp->ud_header.eth.smac_h, smac, 6);
                if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
                        mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
index 5a044526e4f4c379bf52e05f9b15c00953453df7..c4e0131f1b578fec8fa62d029ff380b3d976b13b 100644 (file)
@@ -161,7 +161,7 @@ static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)
        ocrdma_get_guid(dev, &sgid->raw[8]);
 }
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
 static void ocrdma_add_vlan_sgids(struct ocrdma_dev *dev)
 {
        struct net_device *netdev, *tmp;
@@ -202,14 +202,13 @@ static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_VLAN_8021Q)
+#if IS_ENABLED(CONFIG_IPV6)
 
 static int ocrdma_inet6addr_event(struct notifier_block *notifier,
                                  unsigned long event, void *ptr)
 {
        struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
-       struct net_device *event_netdev = ifa->idev->dev;
-       struct net_device *netdev = NULL;
+       struct net_device *netdev = ifa->idev->dev;
        struct ib_event gid_event;
        struct ocrdma_dev *dev;
        bool found = false;
@@ -217,11 +216,12 @@ static int ocrdma_inet6addr_event(struct notifier_block *notifier,
        bool is_vlan = false;
        u16 vid = 0;
 
-       netdev = vlan_dev_real_dev(event_netdev);
-       if (netdev != event_netdev) {
-               is_vlan = true;
-               vid = vlan_dev_vlan_id(event_netdev);
+       is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN;
+       if (is_vlan) {
+               vid = vlan_dev_vlan_id(netdev);
+               netdev = vlan_dev_real_dev(netdev);
        }
+
        rcu_read_lock();
        list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
                if (dev->nic_info.netdev == netdev) {
index 0d7280af99bc81084d1977d5bfe8480450c85c77..3f6b21e9dc110513c0522b099adcfa0f131ef6b4 100644 (file)
@@ -6346,8 +6346,10 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
                        dd->piobcnt4k * dd->align4k;
                dd->piovl15base = ioremap_nocache(vl15off,
                                                  NUM_VL15_BUFS * dd->align4k);
-               if (!dd->piovl15base)
+               if (!dd->piovl15base) {
+                       ret = -ENOMEM;
                        goto bail;
+               }
        }
        qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
 
index a322d5171a2c793d0ec3cb5e08632a0264fd2ab5..50a8a0d4fe676f5467c677d66a4985170900059d 100644 (file)
@@ -372,7 +372,7 @@ static void qib_sd_trimdone_monitor(struct qib_devdata *dd,
                /* Read CTRL reg for each channel to check TRIMDONE */
                if (baduns & (1 << chn)) {
                        qib_dev_err(dd,
-                               "Reseting TRIMDONE on chn %d (%s)\n",
+                               "Resetting TRIMDONE on chn %d (%s)\n",
                                chn, where);
                        ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                                IB_CTRL2(chn), 0x10, 0x10);
index 95ecf4eadf5f75949f6a7e14acfa01a50fbdc0cd..24683fda8e21cdbaca2973cc69454013a2bbb995 100644 (file)
@@ -1271,12 +1271,15 @@ struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path
 void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
 {
        struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
+       unsigned long flags;
        if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
+               spin_lock_irqsave(&priv->lock, flags);
                list_move(&tx->list, &priv->cm.reap_list);
                queue_work(ipoib_workqueue, &priv->cm.reap_task);
                ipoib_dbg(priv, "Reap connection for gid %pI6\n",
                          tx->neigh->daddr + 4);
                tx->neigh = NULL;
+               spin_unlock_irqrestore(&priv->lock, flags);
        }
 }
 
index 97920b77a5d0abe2f378ed060aa8243a2c5c33e7..3e2085a3ee474fc0111c7034ca013bfda7d63d7e 100644 (file)
@@ -1052,7 +1052,7 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh)
        for (n = rcu_dereference_protected(*np,
                                            lockdep_is_held(&ntbl->rwlock));
             n != NULL;
-            n = rcu_dereference_protected(neigh->hnext,
+            n = rcu_dereference_protected(*np,
                                        lockdep_is_held(&ntbl->rwlock))) {
                if (n == neigh) {
                        /* found */
index bcbf22ee0aa77d3b99ae3fcceabd3ebce1302ee9..1b5b0c7300549cefee683b3d5745b39a446b5bca 100644 (file)
@@ -586,24 +586,62 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
                        scmnd->sc_data_direction);
 }
 
-static void srp_remove_req(struct srp_target_port *target,
-                          struct srp_request *req, s32 req_lim_delta)
+/**
+ * srp_claim_req - Take ownership of the scmnd associated with a request.
+ * @target: SRP target port.
+ * @req: SRP request.
+ * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
+ *         ownership of @req->scmnd if it equals @scmnd.
+ *
+ * Return value:
+ * Either NULL or a pointer to the SCSI command the caller became owner of.
+ */
+static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target,
+                                      struct srp_request *req,
+                                      struct scsi_cmnd *scmnd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&target->lock, flags);
+       if (!scmnd) {
+               scmnd = req->scmnd;
+               req->scmnd = NULL;
+       } else if (req->scmnd == scmnd) {
+               req->scmnd = NULL;
+       } else {
+               scmnd = NULL;
+       }
+       spin_unlock_irqrestore(&target->lock, flags);
+
+       return scmnd;
+}
+
+/**
+ * srp_free_req() - Unmap data and add request to the free request list.
+ */
+static void srp_free_req(struct srp_target_port *target,
+                        struct srp_request *req, struct scsi_cmnd *scmnd,
+                        s32 req_lim_delta)
 {
        unsigned long flags;
 
-       srp_unmap_data(req->scmnd, target, req);
+       srp_unmap_data(scmnd, target, req);
+
        spin_lock_irqsave(&target->lock, flags);
        target->req_lim += req_lim_delta;
-       req->scmnd = NULL;
        list_add_tail(&req->list, &target->free_reqs);
        spin_unlock_irqrestore(&target->lock, flags);
 }
 
 static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
 {
-       req->scmnd->result = DID_RESET << 16;
-       req->scmnd->scsi_done(req->scmnd);
-       srp_remove_req(target, req, 0);
+       struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL);
+
+       if (scmnd) {
+               scmnd->result = DID_RESET << 16;
+               scmnd->scsi_done(scmnd);
+               srp_free_req(target, req, scmnd, 0);
+       }
 }
 
 static int srp_reconnect_target(struct srp_target_port *target)
@@ -1073,11 +1111,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
                complete(&target->tsk_mgmt_done);
        } else {
                req = &target->req_ring[rsp->tag];
-               scmnd = req->scmnd;
-               if (!scmnd)
+               scmnd = srp_claim_req(target, req, NULL);
+               if (!scmnd) {
                        shost_printk(KERN_ERR, target->scsi_host,
                                     "Null scmnd for RSP w/tag %016llx\n",
                                     (unsigned long long) rsp->tag);
+
+                       spin_lock_irqsave(&target->lock, flags);
+                       target->req_lim += be32_to_cpu(rsp->req_lim_delta);
+                       spin_unlock_irqrestore(&target->lock, flags);
+
+                       return;
+               }
                scmnd->result = rsp->status;
 
                if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
@@ -1092,7 +1137,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
                else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
                        scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
 
-               srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta));
+               srp_free_req(target, req, scmnd,
+                            be32_to_cpu(rsp->req_lim_delta));
+
                scmnd->host_scribble = NULL;
                scmnd->scsi_done(scmnd);
        }
@@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 {
        struct srp_target_port *target = host_to_target(scmnd->device->host);
        struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
-       int ret = SUCCESS;
 
        shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
-       if (!req || target->qp_in_error)
+       if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd))
                return FAILED;
-       if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
-                             SRP_TSK_ABORT_TASK))
-               return FAILED;
-
-       if (req->scmnd) {
-               if (!target->tsk_mgmt_status) {
-                       srp_remove_req(target, req, 0);
-                       scmnd->result = DID_ABORT << 16;
-               } else
-                       ret = FAILED;
-       }
+       srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+                         SRP_TSK_ABORT_TASK);
+       srp_free_req(target, req, scmnd, 0);
+       scmnd->result = DID_ABORT << 16;
 
-       return ret;
+       return SUCCESS;
 }
 
 static int srp_reset_device(struct scsi_cmnd *scmnd)
index 7a0ce8d42887e225e81d20702892d8ed0d056f39..9e1449f8c6a26ea62349352de3f8178db2faa6fe 100644 (file)
@@ -1469,7 +1469,7 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
  *
  * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping
  * the data that has been transferred via IB RDMA had to be postponed until the
- * check_stop_free() callback.  None of this is nessecary anymore and needs to
+ * check_stop_free() callback.  None of this is necessary anymore and needs to
  * be cleaned up.
  */
 static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
index 503c7096ed36263aac57c0165e846cb2d46fae49..908407efc672be69bcc0a13c5603b38b45d50440 100644 (file)
@@ -48,7 +48,7 @@ struct eeti_ts_priv {
        struct input_dev *input;
        struct work_struct work;
        struct mutex mutex;
-       int irq, irq_active_high;
+       int irq_gpio, irq, irq_active_high;
 };
 
 #define EETI_TS_BITDEPTH       (11)
@@ -62,7 +62,7 @@ struct eeti_ts_priv {
 
 static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
 {
-       return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;
+       return gpio_get_value(priv->irq_gpio) == priv->irq_active_high;
 }
 
 static void eeti_ts_read(struct work_struct *work)
@@ -157,7 +157,7 @@ static void eeti_ts_close(struct input_dev *dev)
 static int __devinit eeti_ts_probe(struct i2c_client *client,
                                   const struct i2c_device_id *idp)
 {
-       struct eeti_ts_platform_data *pdata;
+       struct eeti_ts_platform_data *pdata = client->dev.platform_data;
        struct eeti_ts_priv *priv;
        struct input_dev *input;
        unsigned int irq_flags;
@@ -199,9 +199,12 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
 
        priv->client = client;
        priv->input = input;
-       priv->irq = client->irq;
+       priv->irq_gpio = pdata->irq_gpio;
+       priv->irq = gpio_to_irq(pdata->irq_gpio);
 
-       pdata = client->dev.platform_data;
+       err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
+       if (err < 0)
+               goto err1;
 
        if (pdata)
                priv->irq_active_high = pdata->irq_active_high;
@@ -215,13 +218,13 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
 
        err = input_register_device(input);
        if (err)
-               goto err1;
+               goto err2;
 
        err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
                          client->name, priv);
        if (err) {
                dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-               goto err2;
+               goto err3;
        }
 
        /*
@@ -233,9 +236,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
        device_init_wakeup(&client->dev, 0);
        return 0;
 
-err2:
+err3:
        input_unregister_device(input);
        input = NULL; /* so we dont try to free it below */
+err2:
+       gpio_free(pdata->irq_gpio);
 err1:
        input_free_device(input);
        kfree(priv);
index 6d1cbdfc9b2a1af4a583460e8c4a5e5c80aabdfc..b64502dfa9f4567ca028bcb9b7913d4b38696019 100644 (file)
@@ -296,8 +296,13 @@ static int iommu_init_device(struct device *dev)
        } else
                dma_pdev = pci_dev_get(pdev);
 
+       /* Account for quirked devices */
        swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
 
+       /*
+        * If it's a multifunction device that does not support our
+        * required ACS flags, add to the same group as function 0.
+        */
        if (dma_pdev->multifunction &&
            !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
                swap_pci_ref(&dma_pdev,
@@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev)
                                          PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
                                          0)));
 
+       /*
+        * Devices on the root bus go through the iommu.  If that's not us,
+        * find the next upstream device and test ACS up to the root bus.
+        * Finding the next device may require skipping virtual buses.
+        */
        while (!pci_is_root_bus(dma_pdev->bus)) {
-               if (pci_acs_path_enabled(dma_pdev->bus->self,
-                                        NULL, REQ_ACS_FLAGS))
+               struct pci_bus *bus = dma_pdev->bus;
+
+               while (!bus->self) {
+                       if (!pci_is_root_bus(bus))
+                               bus = bus->parent;
+                       else
+                               goto root_bus;
+               }
+
+               if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
                        break;
 
-               swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
+               swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
        }
 
+root_bus:
        group = iommu_group_get(&dma_pdev->dev);
        pci_dev_put(dma_pdev);
        if (!group) {
index 500e7f15f5c266043d5d2bdc27a04f489595be79..18a89b760aaa3d78940021f0637e7f090116bb23 100644 (file)
@@ -1111,7 +1111,7 @@ static void print_iommu_info(void)
 
                if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
                        pr_info("AMD-Vi:  Extended features: ");
-                       for (i = 0; ARRAY_SIZE(feat_str); ++i) {
+                       for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
                                if (iommu_feature(iommu, (1ULL << i)))
                                        pr_cont(" %s", feat_str[i]);
                        }
@@ -1131,9 +1131,6 @@ static int __init amd_iommu_init_pci(void)
                        break;
        }
 
-       /* Make sure ACS will be enabled */
-       pci_request_acs();
-
        ret = amd_iommu_init_devices();
 
        print_iommu_info();
@@ -1652,6 +1649,9 @@ static bool detect_ivrs(void)
 
        early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
 
+       /* Make sure ACS will be enabled during PCI probe */
+       pci_request_acs();
+
        return true;
 }
 
index 45350ff5e93c9cbe58c1f73c49e932c5f57eb376..80bad32aa46394443ad5a0aaa4a241c4e0e4b2c0 100644 (file)
@@ -732,9 +732,9 @@ static int exynos_iommu_domain_init(struct iommu_domain *domain)
        spin_lock_init(&priv->pgtablelock);
        INIT_LIST_HEAD(&priv->clients);
 
-       dom->geometry.aperture_start = 0;
-       dom->geometry.aperture_end   = ~0UL;
-       dom->geometry.force_aperture = true;
+       domain->geometry.aperture_start = 0;
+       domain->geometry.aperture_end   = ~0UL;
+       domain->geometry.force_aperture = true;
 
        domain->priv = priv;
        return 0;
index 7469b5346643595fe1788b04d76135ed30075cfd..2297ec193eb4b645812c85519c335361e935f296 100644 (file)
@@ -2008,6 +2008,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
        if (!drhd) {
                printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
                        pci_name(pdev));
+               free_domain_mem(domain);
                return NULL;
        }
        iommu = drhd->iommu;
@@ -4124,8 +4125,13 @@ static int intel_iommu_add_device(struct device *dev)
        } else
                dma_pdev = pci_dev_get(pdev);
 
+       /* Account for quirked devices */
        swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
 
+       /*
+        * If it's a multifunction device that does not support our
+        * required ACS flags, add to the same group as function 0.
+        */
        if (dma_pdev->multifunction &&
            !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
                swap_pci_ref(&dma_pdev,
@@ -4133,14 +4139,28 @@ static int intel_iommu_add_device(struct device *dev)
                                          PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
                                          0)));
 
+       /*
+        * Devices on the root bus go through the iommu.  If that's not us,
+        * find the next upstream device and test ACS up to the root bus.
+        * Finding the next device may require skipping virtual buses.
+        */
        while (!pci_is_root_bus(dma_pdev->bus)) {
-               if (pci_acs_path_enabled(dma_pdev->bus->self,
-                                        NULL, REQ_ACS_FLAGS))
+               struct pci_bus *bus = dma_pdev->bus;
+
+               while (!bus->self) {
+                       if (!pci_is_root_bus(bus))
+                               bus = bus->parent;
+                       else
+                               goto root_bus;
+               }
+
+               if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
                        break;
 
-               swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
+               swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
        }
 
+root_bus:
        group = iommu_group_get(&dma_pdev->dev);
        pci_dev_put(dma_pdev);
        if (!group) {
index e0b18f3ae9a862a22a8bc2ebe2eccc224c456252..af8904de1d44e63ca35be4a58320889b2bab7a8b 100644 (file)
@@ -736,6 +736,7 @@ int __init parse_ioapics_under_ir(void)
 {
        struct dmar_drhd_unit *drhd;
        int ir_supported = 0;
+       int ioapic_idx;
 
        for_each_drhd_unit(drhd) {
                struct intel_iommu *iommu = drhd->iommu;
@@ -748,13 +749,20 @@ int __init parse_ioapics_under_ir(void)
                }
        }
 
-       if (ir_supported && ir_ioapic_num != nr_ioapics) {
-               printk(KERN_WARNING
-                      "Not all IO-APIC's listed under remapping hardware\n");
-               return -1;
+       if (!ir_supported)
+               return 0;
+
+       for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
+               int ioapic_id = mpc_ioapic_id(ioapic_idx);
+               if (!map_ioapic_to_ir(ioapic_id)) {
+                       pr_err(FW_BUG "ioapic %d has no mapping iommu, "
+                              "interrupt remapping will be disabled\n",
+                              ioapic_id);
+                       return -1;
+               }
        }
 
-       return ir_supported;
+       return 1;
 }
 
 int __init ir_dev_scope_init(void)
index 4ba325ab626249c2aa2aee1271a6d0c68ec20d9a..2a4bb36bc6888a9c91aee304df7c19bad1e42f83 100644 (file)
@@ -799,14 +799,14 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
                        goto out;
                }
        }
-       dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev));
+       dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev));
 out:
        spin_unlock(&as->client_lock);
 }
 
 static int smmu_iommu_domain_init(struct iommu_domain *domain)
 {
-       int i, err = -ENODEV;
+       int i, err = -EAGAIN;
        unsigned long flags;
        struct smmu_as *as;
        struct smmu_device *smmu = smmu_handle;
@@ -814,11 +814,14 @@ static int smmu_iommu_domain_init(struct iommu_domain *domain)
        /* Look for a free AS with lock held */
        for  (i = 0; i < smmu->num_as; i++) {
                as = &smmu->as[i];
-               if (!as->pdir_page) {
-                       err = alloc_pdir(as);
-                       if (!err)
-                               goto found;
-               }
+
+               if (as->pdir_page)
+                       continue;
+
+               err = alloc_pdir(as);
+               if (!err)
+                       goto found;
+
                if (err != -EAGAIN)
                        break;
        }
index 5405ec644db3ee910df3765499300f11f7d1832c..baf2686aa8eb0cb027044e815dafa8b2aa6afae4 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include "isdnloop.h"
 
-static char *revision = "$Revision: 1.11.6.7 $";
 static char *isdnloop_id = "loop0";
 
 MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
@@ -1494,17 +1493,6 @@ isdnloop_addcard(char *id1)
 static int __init
 isdnloop_init(void)
 {
-       char *p;
-       char rev[10];
-
-       if ((p = strchr(revision, ':'))) {
-               strcpy(rev, p + 1);
-               p = strchr(rev, '$');
-               *p = 0;
-       } else
-               strcpy(rev, " ??? ");
-       printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
-
        if (isdnloop_id)
                return (isdnloop_addcard(isdnloop_id));
 
index 0dc8abca14079223c868effc3258e4b5f36590fe..949cabb88f1c113c9606d26ff72627f6cf9db108 100644 (file)
@@ -2222,7 +2222,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
        InitWin(l2);
        l2->l2m.fsm = &l2fsm;
        if (test_bit(FLG_LAPB, &l2->flag) ||
-           test_bit(FLG_PTP, &l2->flag) ||
+           test_bit(FLG_FIXED_TEI, &l2->flag) ||
            test_bit(FLG_LAPD_NET, &l2->flag))
                l2->l2m.state = ST_L2_4;
        else
index 6157cbbf41131cb1f2fdf7b4f02e96f48771a8b1..363975b3c925989badc13117d7a5309a5860a1b8 100644 (file)
@@ -224,7 +224,7 @@ void led_trigger_event(struct led_trigger *trig,
                struct led_classdev *led_cdev;
 
                led_cdev = list_entry(entry, struct led_classdev, trig_list);
-               led_set_brightness(led_cdev, brightness);
+               __led_set_brightness(led_cdev, brightness);
        }
        read_unlock(&trig->leddev_list_lock);
 }
index 53bd136f1ef070a1e045b97f8dbc6b55e30c0ca6..0ade6ebfc914dba6e6809b46a428fc9ee219b83e 100644 (file)
@@ -63,7 +63,7 @@ static int lp8788_led_init_device(struct lp8788_led *led,
        /* scale configuration */
        addr = LP8788_ISINK_CTRL;
        mask = 1 << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
-       val = cfg->scale << cfg->num;
+       val = cfg->scale << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
        ret = lp8788_update_bits(led->lp, addr, mask, val);
        if (ret)
                return ret;
index 9ee12c28059a0a8e60bc879dd083db2b90ae2fdc..771ea067e680f8b64e9cd54672007a5d66091d9c 100644 (file)
@@ -247,7 +247,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
 
        if (!cfg) {
                dev_err(&pdev->dev, "missing platform data\n");
-               goto err0;
+               return -ENODEV;
        }
 
        p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
index fcd098794d37d16c7b48b12c54b5ba6f5e6ba60e..3f6203a4c7ea0dd730b80a6b441b99e8a4da3216 100644 (file)
@@ -1108,8 +1108,11 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
                        ret = 0;
        }
        rdev->sectors = rdev->sb_start;
-       /* Limit to 4TB as metadata cannot record more than that */
-       if (rdev->sectors >= (2ULL << 32))
+       /* Limit to 4TB as metadata cannot record more than that.
+        * (not needed for Linear and RAID0 as metadata doesn't
+        * record this size)
+        */
+       if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
                rdev->sectors = (2ULL << 32) - 2;
 
        if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
@@ -1400,7 +1403,7 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
        /* Limit to 4TB as metadata cannot record more than that.
         * 4TB == 2^32 KB, or 2*2^32 sectors.
         */
-       if (num_sectors >= (2ULL << 32))
+       if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
                num_sectors = (2ULL << 32) - 2;
        md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
                       rdev->sb_page);
index de5ed6fd8806c3c3db39bbd894fabb04734b4523..1c2eb38f3c51a6dcc93148ca34b1a6a1de7aa465 100644 (file)
@@ -659,7 +659,11 @@ static int raid10_mergeable_bvec(struct request_queue *q,
                max = biovec->bv_len;
 
        if (mddev->merge_check_needed) {
-               struct r10bio r10_bio;
+               struct {
+                       struct r10bio r10_bio;
+                       struct r10dev devs[conf->copies];
+               } on_stack;
+               struct r10bio *r10_bio = &on_stack.r10_bio;
                int s;
                if (conf->reshape_progress != MaxSector) {
                        /* Cannot give any guidance during reshape */
@@ -667,18 +671,18 @@ static int raid10_mergeable_bvec(struct request_queue *q,
                                return biovec->bv_len;
                        return 0;
                }
-               r10_bio.sector = sector;
-               raid10_find_phys(conf, &r10_bio);
+               r10_bio->sector = sector;
+               raid10_find_phys(conf, r10_bio);
                rcu_read_lock();
                for (s = 0; s < conf->copies; s++) {
-                       int disk = r10_bio.devs[s].devnum;
+                       int disk = r10_bio->devs[s].devnum;
                        struct md_rdev *rdev = rcu_dereference(
                                conf->mirrors[disk].rdev);
                        if (rdev && !test_bit(Faulty, &rdev->flags)) {
                                struct request_queue *q =
                                        bdev_get_queue(rdev->bdev);
                                if (q->merge_bvec_fn) {
-                                       bvm->bi_sector = r10_bio.devs[s].addr
+                                       bvm->bi_sector = r10_bio->devs[s].addr
                                                + rdev->data_offset;
                                        bvm->bi_bdev = rdev->bdev;
                                        max = min(max, q->merge_bvec_fn(
@@ -690,7 +694,7 @@ static int raid10_mergeable_bvec(struct request_queue *q,
                                struct request_queue *q =
                                        bdev_get_queue(rdev->bdev);
                                if (q->merge_bvec_fn) {
-                                       bvm->bi_sector = r10_bio.devs[s].addr
+                                       bvm->bi_sector = r10_bio->devs[s].addr
                                                + rdev->data_offset;
                                        bvm->bi_bdev = rdev->bdev;
                                        max = min(max, q->merge_bvec_fn(
@@ -4414,14 +4418,18 @@ static int handle_reshape_read_error(struct mddev *mddev,
 {
        /* Use sync reads to get the blocks from somewhere else */
        int sectors = r10_bio->sectors;
-       struct r10bio r10b;
        struct r10conf *conf = mddev->private;
+       struct {
+               struct r10bio r10_bio;
+               struct r10dev devs[conf->copies];
+       } on_stack;
+       struct r10bio *r10b = &on_stack.r10_bio;
        int slot = 0;
        int idx = 0;
        struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
 
-       r10b.sector = r10_bio->sector;
-       __raid10_find_phys(&conf->prev, &r10b);
+       r10b->sector = r10_bio->sector;
+       __raid10_find_phys(&conf->prev, r10b);
 
        while (sectors) {
                int s = sectors;
@@ -4432,7 +4440,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
                        s = PAGE_SIZE >> 9;
 
                while (!success) {
-                       int d = r10b.devs[slot].devnum;
+                       int d = r10b->devs[slot].devnum;
                        struct md_rdev *rdev = conf->mirrors[d].rdev;
                        sector_t addr;
                        if (rdev == NULL ||
@@ -4440,7 +4448,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
                            !test_bit(In_sync, &rdev->flags))
                                goto failed;
 
-                       addr = r10b.devs[slot].addr + idx * PAGE_SIZE;
+                       addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
                        success = sync_page_io(rdev,
                                               addr,
                                               s << 9,
index 007c2c68dd8369f2acbcd9ae8d3c155399d13674..1054cf602345250f059ef81fae8bf9ef330cccd1 100644 (file)
@@ -110,7 +110,7 @@ struct r10bio {
         * We choose the number when they are allocated.
         * We sometimes need an extra bio to write to the replacement.
         */
-       struct {
+       struct r10dev {
                struct bio      *bio;
                union {
                        struct bio      *repl_bio; /* used for resync and
index 664e460f247b5a7d1d53629959da7705fb259aa1..aac622200e99a9e244523b8ead9994d510cac891 100644 (file)
@@ -481,7 +481,7 @@ static int smsusb_resume(struct usb_interface *intf)
        return 0;
 }
 
-static const struct usb_device_id smsusb_id_table[] __devinitconst = {
+static const struct usb_device_id smsusb_id_table[] = {
        { USB_DEVICE(0x187f, 0x0010),
                .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
        { USB_DEVICE(0x187f, 0x0100),
index d0b6bb507634a5756e7c5d6335a42f8da2b0d90f..72ded29728bbb2cbf459184095be31cf45a81270 100644 (file)
 #include <media/v4l2-device.h>
 #include <sound/tea575x-tuner.h>
 
+#if defined(CONFIG_LEDS_CLASS) || \
+    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE))
+#define SHARK_USE_LEDS 1
+#endif
+
 /*
  * Version Information
  */
@@ -56,44 +61,18 @@ MODULE_LICENSE("GPL");
 
 enum { BLUE_LED, BLUE_PULSE_LED, RED_LED, NO_LEDS };
 
-static void shark_led_set_blue(struct led_classdev *led_cdev,
-                              enum led_brightness value);
-static void shark_led_set_blue_pulse(struct led_classdev *led_cdev,
-                                    enum led_brightness value);
-static void shark_led_set_red(struct led_classdev *led_cdev,
-                             enum led_brightness value);
-
-static const struct led_classdev shark_led_templates[NO_LEDS] = {
-       [BLUE_LED] = {
-               .name           = "%s:blue:",
-               .brightness     = LED_OFF,
-               .max_brightness = 127,
-               .brightness_set = shark_led_set_blue,
-       },
-       [BLUE_PULSE_LED] = {
-               .name           = "%s:blue-pulse:",
-               .brightness     = LED_OFF,
-               .max_brightness = 255,
-               .brightness_set = shark_led_set_blue_pulse,
-       },
-       [RED_LED] = {
-               .name           = "%s:red:",
-               .brightness     = LED_OFF,
-               .max_brightness = 1,
-               .brightness_set = shark_led_set_red,
-       },
-};
-
 struct shark_device {
        struct usb_device *usbdev;
        struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
 
+#ifdef SHARK_USE_LEDS
        struct work_struct led_work;
        struct led_classdev leds[NO_LEDS];
        char led_names[NO_LEDS][32];
        atomic_t brightness[NO_LEDS];
        unsigned long brightness_new;
+#endif
 
        u8 *transfer_buffer;
        u32 last_val;
@@ -175,20 +154,13 @@ static struct snd_tea575x_ops shark_tea_ops = {
        .read_val  = shark_read_val,
 };
 
+#ifdef SHARK_USE_LEDS
 static void shark_led_work(struct work_struct *work)
 {
        struct shark_device *shark =
                container_of(work, struct shark_device, led_work);
        int i, res, brightness, actual_len;
 
-       /*
-        * We use the v4l2_dev lock and registered bit to ensure the device
-        * does not get unplugged and unreffed while we're running.
-        */
-       mutex_lock(&shark->tea.mutex);
-       if (!video_is_registered(&shark->tea.vd))
-               goto leave;
-
        for (i = 0; i < 3; i++) {
                if (!test_and_clear_bit(i, &shark->brightness_new))
                        continue;
@@ -208,8 +180,6 @@ static void shark_led_work(struct work_struct *work)
                        v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
                                 shark->led_names[i], res);
        }
-leave:
-       mutex_unlock(&shark->tea.mutex);
 }
 
 static void shark_led_set_blue(struct led_classdev *led_cdev,
@@ -245,19 +215,78 @@ static void shark_led_set_red(struct led_classdev *led_cdev,
        schedule_work(&shark->led_work);
 }
 
+static const struct led_classdev shark_led_templates[NO_LEDS] = {
+       [BLUE_LED] = {
+               .name           = "%s:blue:",
+               .brightness     = LED_OFF,
+               .max_brightness = 127,
+               .brightness_set = shark_led_set_blue,
+       },
+       [BLUE_PULSE_LED] = {
+               .name           = "%s:blue-pulse:",
+               .brightness     = LED_OFF,
+               .max_brightness = 255,
+               .brightness_set = shark_led_set_blue_pulse,
+       },
+       [RED_LED] = {
+               .name           = "%s:red:",
+               .brightness     = LED_OFF,
+               .max_brightness = 1,
+               .brightness_set = shark_led_set_red,
+       },
+};
+
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       int i, retval;
+
+       INIT_WORK(&shark->led_work, shark_led_work);
+       for (i = 0; i < NO_LEDS; i++) {
+               shark->leds[i] = shark_led_templates[i];
+               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
+                        shark->leds[i].name, shark->v4l2_dev.name);
+               shark->leds[i].name = shark->led_names[i];
+               retval = led_classdev_register(dev, &shark->leds[i]);
+               if (retval) {
+                       v4l2_err(&shark->v4l2_dev,
+                                "couldn't register led: %s\n",
+                                shark->led_names[i]);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static void shark_unregister_leds(struct shark_device *shark)
+{
+       int i;
+
+       for (i = 0; i < NO_LEDS; i++)
+               led_classdev_unregister(&shark->leds[i]);
+
+       cancel_work_sync(&shark->led_work);
+}
+#else
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       v4l2_warn(&shark->v4l2_dev,
+                 "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+       return 0;
+}
+static inline void shark_unregister_leds(struct shark_device *shark) { }
+#endif
+
 static void usb_shark_disconnect(struct usb_interface *intf)
 {
        struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
-       int i;
 
        mutex_lock(&shark->tea.mutex);
        v4l2_device_disconnect(&shark->v4l2_dev);
        snd_tea575x_exit(&shark->tea);
        mutex_unlock(&shark->tea.mutex);
 
-       for (i = 0; i < NO_LEDS; i++)
-               led_classdev_unregister(&shark->leds[i]);
+       shark_unregister_leds(shark);
 
        v4l2_device_put(&shark->v4l2_dev);
 }
@@ -266,7 +295,6 @@ static void usb_shark_release(struct v4l2_device *v4l2_dev)
 {
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 
-       cancel_work_sync(&shark->led_work);
        v4l2_device_unregister(&shark->v4l2_dev);
        kfree(shark->transfer_buffer);
        kfree(shark);
@@ -276,7 +304,7 @@ static int usb_shark_probe(struct usb_interface *intf,
                           const struct usb_device_id *id)
 {
        struct shark_device *shark;
-       int i, retval = -ENOMEM;
+       int retval = -ENOMEM;
 
        shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
        if (!shark)
@@ -286,17 +314,13 @@ static int usb_shark_probe(struct usb_interface *intf,
        if (!shark->transfer_buffer)
                goto err_alloc_buffer;
 
-       /*
-        * Work around a bug in usbhid/hid-core.c, where it leaves a dangling
-        * pointer in intfdata causing v4l2-device.c to not set it. Which
-        * results in usb_shark_disconnect() referencing the dangling pointer
-        *
-        * REMOVE (as soon as the above bug is fixed, patch submitted)
-        */
-       usb_set_intfdata(intf, NULL);
+       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
+
+       retval = shark_register_leds(shark, &intf->dev);
+       if (retval)
+               goto err_reg_leds;
 
        shark->v4l2_dev.release = usb_shark_release;
-       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
        retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
        if (retval) {
                v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
@@ -320,32 +344,13 @@ static int usb_shark_probe(struct usb_interface *intf,
                goto err_init_tea;
        }
 
-       INIT_WORK(&shark->led_work, shark_led_work);
-       for (i = 0; i < NO_LEDS; i++) {
-               shark->leds[i] = shark_led_templates[i];
-               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
-                        shark->leds[i].name, shark->v4l2_dev.name);
-               shark->leds[i].name = shark->led_names[i];
-               /*
-                * We don't fail the probe if we fail to register the leds,
-                * because once we've called snd_tea575x_init, the /dev/radio0
-                * node may be opened from userspace holding a reference to us!
-                *
-                * Note we cannot register the leds first instead as
-                * shark_led_work depends on the v4l2 mutex and registered bit.
-                */
-               retval = led_classdev_register(&intf->dev, &shark->leds[i]);
-               if (retval)
-                       v4l2_err(&shark->v4l2_dev,
-                                "couldn't register led: %s\n",
-                                shark->led_names[i]);
-       }
-
        return 0;
 
 err_init_tea:
        v4l2_device_unregister(&shark->v4l2_dev);
 err_reg_dev:
+       shark_unregister_leds(shark);
+err_reg_leds:
        kfree(shark->transfer_buffer);
 err_alloc_buffer:
        kfree(shark);
index b9575de3e7e8306d5f9cdf6fa6efbd2b74c0984d..7b4efdfaae283748edea0dc359ae647667add6b6 100644 (file)
 #include <media/v4l2-device.h>
 #include "radio-tea5777.h"
 
+#if defined(CONFIG_LEDS_CLASS) || \
+    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK2_MODULE))
+#define SHARK_USE_LEDS 1
+#endif
+
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Griffin radioSHARK2, USB radio receiver driver");
 MODULE_LICENSE("GPL");
@@ -43,7 +48,6 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-
 #define SHARK_IN_EP            0x83
 #define SHARK_OUT_EP           0x05
 
@@ -54,36 +58,18 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 enum { BLUE_LED, RED_LED, NO_LEDS };
 
-static void shark_led_set_blue(struct led_classdev *led_cdev,
-                              enum led_brightness value);
-static void shark_led_set_red(struct led_classdev *led_cdev,
-                             enum led_brightness value);
-
-static const struct led_classdev shark_led_templates[NO_LEDS] = {
-       [BLUE_LED] = {
-               .name           = "%s:blue:",
-               .brightness     = LED_OFF,
-               .max_brightness = 127,
-               .brightness_set = shark_led_set_blue,
-       },
-       [RED_LED] = {
-               .name           = "%s:red:",
-               .brightness     = LED_OFF,
-               .max_brightness = 1,
-               .brightness_set = shark_led_set_red,
-       },
-};
-
 struct shark_device {
        struct usb_device *usbdev;
        struct v4l2_device v4l2_dev;
        struct radio_tea5777 tea;
 
+#ifdef SHARK_USE_LEDS
        struct work_struct led_work;
        struct led_classdev leds[NO_LEDS];
        char led_names[NO_LEDS][32];
        atomic_t brightness[NO_LEDS];
        unsigned long brightness_new;
+#endif
 
        u8 *transfer_buffer;
 };
@@ -161,18 +147,12 @@ static struct radio_tea5777_ops shark_tea_ops = {
        .read_reg  = shark_read_reg,
 };
 
+#ifdef SHARK_USE_LEDS
 static void shark_led_work(struct work_struct *work)
 {
        struct shark_device *shark =
                container_of(work, struct shark_device, led_work);
        int i, res, brightness, actual_len;
-       /*
-        * We use the v4l2_dev lock and registered bit to ensure the device
-        * does not get unplugged and unreffed while we're running.
-        */
-       mutex_lock(&shark->tea.mutex);
-       if (!video_is_registered(&shark->tea.vd))
-               goto leave;
 
        for (i = 0; i < 2; i++) {
                if (!test_and_clear_bit(i, &shark->brightness_new))
@@ -191,8 +171,6 @@ static void shark_led_work(struct work_struct *work)
                        v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
                                 shark->led_names[i], res);
        }
-leave:
-       mutex_unlock(&shark->tea.mutex);
 }
 
 static void shark_led_set_blue(struct led_classdev *led_cdev,
@@ -217,19 +195,72 @@ static void shark_led_set_red(struct led_classdev *led_cdev,
        schedule_work(&shark->led_work);
 }
 
+static const struct led_classdev shark_led_templates[NO_LEDS] = {
+       [BLUE_LED] = {
+               .name           = "%s:blue:",
+               .brightness     = LED_OFF,
+               .max_brightness = 127,
+               .brightness_set = shark_led_set_blue,
+       },
+       [RED_LED] = {
+               .name           = "%s:red:",
+               .brightness     = LED_OFF,
+               .max_brightness = 1,
+               .brightness_set = shark_led_set_red,
+       },
+};
+
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       int i, retval;
+
+       INIT_WORK(&shark->led_work, shark_led_work);
+       for (i = 0; i < NO_LEDS; i++) {
+               shark->leds[i] = shark_led_templates[i];
+               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
+                        shark->leds[i].name, shark->v4l2_dev.name);
+               shark->leds[i].name = shark->led_names[i];
+               retval = led_classdev_register(dev, &shark->leds[i]);
+               if (retval) {
+                       v4l2_err(&shark->v4l2_dev,
+                                "couldn't register led: %s\n",
+                                shark->led_names[i]);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static void shark_unregister_leds(struct shark_device *shark)
+{
+       int i;
+
+       for (i = 0; i < NO_LEDS; i++)
+               led_classdev_unregister(&shark->leds[i]);
+
+       cancel_work_sync(&shark->led_work);
+}
+#else
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       v4l2_warn(&shark->v4l2_dev,
+                 "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+       return 0;
+}
+static inline void shark_unregister_leds(struct shark_device *shark) { }
+#endif
+
 static void usb_shark_disconnect(struct usb_interface *intf)
 {
        struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
-       int i;
 
        mutex_lock(&shark->tea.mutex);
        v4l2_device_disconnect(&shark->v4l2_dev);
        radio_tea5777_exit(&shark->tea);
        mutex_unlock(&shark->tea.mutex);
 
-       for (i = 0; i < NO_LEDS; i++)
-               led_classdev_unregister(&shark->leds[i]);
+       shark_unregister_leds(shark);
 
        v4l2_device_put(&shark->v4l2_dev);
 }
@@ -238,7 +269,6 @@ static void usb_shark_release(struct v4l2_device *v4l2_dev)
 {
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 
-       cancel_work_sync(&shark->led_work);
        v4l2_device_unregister(&shark->v4l2_dev);
        kfree(shark->transfer_buffer);
        kfree(shark);
@@ -248,7 +278,7 @@ static int usb_shark_probe(struct usb_interface *intf,
                           const struct usb_device_id *id)
 {
        struct shark_device *shark;
-       int i, retval = -ENOMEM;
+       int retval = -ENOMEM;
 
        shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
        if (!shark)
@@ -258,17 +288,13 @@ static int usb_shark_probe(struct usb_interface *intf,
        if (!shark->transfer_buffer)
                goto err_alloc_buffer;
 
-       /*
-        * Work around a bug in usbhid/hid-core.c, where it leaves a dangling
-        * pointer in intfdata causing v4l2-device.c to not set it. Which
-        * results in usb_shark_disconnect() referencing the dangling pointer
-        *
-        * REMOVE (as soon as the above bug is fixed, patch submitted)
-        */
-       usb_set_intfdata(intf, NULL);
+       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
+
+       retval = shark_register_leds(shark, &intf->dev);
+       if (retval)
+               goto err_reg_leds;
 
        shark->v4l2_dev.release = usb_shark_release;
-       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
        retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
        if (retval) {
                v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
@@ -292,32 +318,13 @@ static int usb_shark_probe(struct usb_interface *intf,
                goto err_init_tea;
        }
 
-       INIT_WORK(&shark->led_work, shark_led_work);
-       for (i = 0; i < NO_LEDS; i++) {
-               shark->leds[i] = shark_led_templates[i];
-               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
-                        shark->leds[i].name, shark->v4l2_dev.name);
-               shark->leds[i].name = shark->led_names[i];
-               /*
-                * We don't fail the probe if we fail to register the leds,
-                * because once we've called radio_tea5777_init, the /dev/radio0
-                * node may be opened from userspace holding a reference to us!
-                *
-                * Note we cannot register the leds first instead as
-                * shark_led_work depends on the v4l2 mutex and registered bit.
-                */
-               retval = led_classdev_register(&intf->dev, &shark->leds[i]);
-               if (retval)
-                       v4l2_err(&shark->v4l2_dev,
-                                "couldn't register led: %s\n",
-                                shark->led_names[i]);
-       }
-
        return 0;
 
 err_init_tea:
        v4l2_device_unregister(&shark->v4l2_dev);
 err_reg_dev:
+       shark_unregister_leds(shark);
+err_reg_leds:
        kfree(shark->transfer_buffer);
 err_alloc_buffer:
        kfree(shark);
index 9e38132afec66488299ebd4227a94e9a2e5d3a11..9bb65e170d99bd87455107083379931c6bda40a6 100644 (file)
@@ -151,6 +151,7 @@ static const struct v4l2_frequency_band bands[] = {
                .index = 0,
                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_FREQ_BANDS |
                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
                            V4L2_TUNER_CAP_HWSEEK_WRAP,
                .rangelow   =  87500 * 16,
@@ -162,6 +163,7 @@ static const struct v4l2_frequency_band bands[] = {
                .index = 1,
                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_FREQ_BANDS |
                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
                            V4L2_TUNER_CAP_HWSEEK_WRAP,
                .rangelow   =  76000 * 16,
@@ -173,6 +175,7 @@ static const struct v4l2_frequency_band bands[] = {
                .index = 2,
                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_FREQ_BANDS |
                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
                            V4L2_TUNER_CAP_HWSEEK_WRAP,
                .rangelow   =  76000 * 16,
index 643a6ff7c5d0e629e70112c0c4e67fe0459c580b..f867f04cccc99626bb7fc5dee97d34f2adaed9fa 100644 (file)
@@ -225,8 +225,9 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-       capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
-               V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
+               V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
+       capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
index 146be4263ea17d92ab072d13ae4d12fa610b9276..be076f7181e728b1ab177ca340290a2c1ae29dc4 100644 (file)
@@ -531,7 +531,7 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
        usb_make_path(radio->usbdev, capability->bus_info,
                        sizeof(capability->bus_info));
-       capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
+       capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
                V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
        capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
index 5180390be7ab0915ffa24189269ce4707e1e3baf..8be57634ba60f23e09fc5840a6bb6837920549e2 100644 (file)
@@ -261,6 +261,7 @@ config IR_WINBOND_CIR
 
 config IR_IGUANA
        tristate "IguanaWorks USB IR Transceiver"
+       depends on USB_ARCH_HAS_HCD
        depends on RC_CORE
        select USB
        ---help---
index cf9d9fca5b84005cd37e24cba853c9d132e504be..234777116e5fc5e8cc25a6f4e1940feca8a31412 100644 (file)
@@ -512,7 +512,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0979, 0x0227)},
        {}
 };
index 969bb5a4cd9307812cc45f2224f3be5bd1fa5617..bab01c86c3154933c819d941bbcfe3c6ffea60ef 100644 (file)
@@ -579,7 +579,7 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x06e1, 0xa190)},
 /*fixme: may be IntelPCCameraPro BRIDGE_SPCA505
        {USB_DEVICE(0x0733, 0x0430)}, */
index 7efe9ad7acc7f90f0942644ee4d909b8b9705618..0b91a5cd38ebaaba2e940b7cf93244e9e5476f3c 100644 (file)
@@ -431,7 +431,7 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
        strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
-       cap->capabilities = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
        cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
index d2e6f82ecfac080cc951d1aa59014f58dbb35487..560a65aa7038dd3cded8d08395958c70e3c537bb 100644 (file)
@@ -403,7 +403,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 
        dev_dbg(pcdev->icd->parent, "Activate device\n");
 
-       clk_enable(pcdev->clk);
+       clk_prepare_enable(pcdev->clk);
 
        /* enable CSI before doing anything else */
        __raw_writel(csicr1, pcdev->base + CSICR1);
@@ -422,7 +422,7 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
        /* Disable all CSI interface */
        __raw_writel(0x00, pcdev->base + CSICR1);
 
-       clk_disable(pcdev->clk);
+       clk_disable_unprepare(pcdev->clk);
 }
 
 /*
index 637bde8aca28e25c2799cd85aded6eedafa3075c..ac175406e582a0c12c2d62fe8de713f89a5353cc 100644 (file)
@@ -272,7 +272,7 @@ struct mx2_camera_dev {
        struct device           *dev;
        struct soc_camera_host  soc_host;
        struct soc_camera_device *icd;
-       struct clk              *clk_csi, *clk_emma;
+       struct clk              *clk_csi, *clk_emma_ahb, *clk_emma_ipg;
 
        unsigned int            irq_csi, irq_emma;
        void __iomem            *base_csi, *base_emma;
@@ -407,7 +407,7 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
 {
        unsigned long flags;
 
-       clk_disable(pcdev->clk_csi);
+       clk_disable_unprepare(pcdev->clk_csi);
        writel(0, pcdev->base_csi + CSICR1);
        if (cpu_is_mx27()) {
                writel(0, pcdev->base_emma + PRP_CNTL);
@@ -435,7 +435,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
        if (pcdev->icd)
                return -EBUSY;
 
-       ret = clk_enable(pcdev->clk_csi);
+       ret = clk_prepare_enable(pcdev->clk_csi);
        if (ret < 0)
                return ret;
 
@@ -1633,23 +1633,34 @@ static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
                goto exit_iounmap;
        }
 
-       pcdev->clk_emma = clk_get(NULL, "emma");
-       if (IS_ERR(pcdev->clk_emma)) {
-               err = PTR_ERR(pcdev->clk_emma);
+       pcdev->clk_emma_ipg = clk_get(pcdev->dev, "emma-ipg");
+       if (IS_ERR(pcdev->clk_emma_ipg)) {
+               err = PTR_ERR(pcdev->clk_emma_ipg);
                goto exit_free_irq;
        }
 
-       clk_enable(pcdev->clk_emma);
+       clk_prepare_enable(pcdev->clk_emma_ipg);
+
+       pcdev->clk_emma_ahb = clk_get(pcdev->dev, "emma-ahb");
+       if (IS_ERR(pcdev->clk_emma_ahb)) {
+               err = PTR_ERR(pcdev->clk_emma_ahb);
+               goto exit_clk_emma_ipg_put;
+       }
+
+       clk_prepare_enable(pcdev->clk_emma_ahb);
 
        err = mx27_camera_emma_prp_reset(pcdev);
        if (err)
-               goto exit_clk_emma_put;
+               goto exit_clk_emma_ahb_put;
 
        return err;
 
-exit_clk_emma_put:
-       clk_disable(pcdev->clk_emma);
-       clk_put(pcdev->clk_emma);
+exit_clk_emma_ahb_put:
+       clk_disable_unprepare(pcdev->clk_emma_ahb);
+       clk_put(pcdev->clk_emma_ahb);
+exit_clk_emma_ipg_put:
+       clk_disable_unprepare(pcdev->clk_emma_ipg);
+       clk_put(pcdev->clk_emma_ipg);
 exit_free_irq:
        free_irq(pcdev->irq_emma, pcdev);
 exit_iounmap:
@@ -1685,7 +1696,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
                goto exit;
        }
 
-       pcdev->clk_csi = clk_get(&pdev->dev, NULL);
+       pcdev->clk_csi = clk_get(&pdev->dev, "ahb");
        if (IS_ERR(pcdev->clk_csi)) {
                dev_err(&pdev->dev, "Could not get csi clock\n");
                err = PTR_ERR(pcdev->clk_csi);
@@ -1785,8 +1796,10 @@ exit_free_emma:
 eallocctx:
        if (cpu_is_mx27()) {
                free_irq(pcdev->irq_emma, pcdev);
-               clk_disable(pcdev->clk_emma);
-               clk_put(pcdev->clk_emma);
+               clk_disable_unprepare(pcdev->clk_emma_ipg);
+               clk_put(pcdev->clk_emma_ipg);
+               clk_disable_unprepare(pcdev->clk_emma_ahb);
+               clk_put(pcdev->clk_emma_ahb);
                iounmap(pcdev->base_emma);
                release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
        }
@@ -1825,8 +1838,10 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev)
        iounmap(pcdev->base_csi);
 
        if (cpu_is_mx27()) {
-               clk_disable(pcdev->clk_emma);
-               clk_put(pcdev->clk_emma);
+               clk_disable_unprepare(pcdev->clk_emma_ipg);
+               clk_put(pcdev->clk_emma_ipg);
+               clk_disable_unprepare(pcdev->clk_emma_ahb);
+               clk_put(pcdev->clk_emma_ahb);
                iounmap(pcdev->base_emma);
                res = pcdev->res_emma;
                release_mem_region(res->start, resource_size(res));
index f13643d313531d16b59f98b532df328762c23b41..af2297dd49c8d7277000a03c2c4083ca0598aaa4 100644 (file)
 
 #define MAX_VIDEO_MEM 16
 
-enum csi_buffer_state {
-       CSI_BUF_NEEDS_INIT,
-       CSI_BUF_PREPARED,
-};
-
 struct mx3_camera_buffer {
        /* common v4l buffer stuff -- must be first */
        struct vb2_buffer                       vb;
-       enum csi_buffer_state                   state;
        struct list_head                        queue;
 
        /* One descriptot per scatterlist (per frame) */
@@ -285,7 +279,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
                goto error;
        }
 
-       if (buf->state == CSI_BUF_NEEDS_INIT) {
+       if (!buf->txd) {
                sg_dma_address(sg)      = vb2_dma_contig_plane_dma_addr(vb, 0);
                sg_dma_len(sg)          = new_size;
 
@@ -298,7 +292,6 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
                txd->callback_param     = txd;
                txd->callback           = mx3_cam_dma_done;
 
-               buf->state              = CSI_BUF_PREPARED;
                buf->txd                = txd;
        } else {
                txd = buf->txd;
@@ -385,7 +378,6 @@ static void mx3_videobuf_release(struct vb2_buffer *vb)
 
        /* Doesn't hurt also if the list is empty */
        list_del_init(&buf->queue);
-       buf->state = CSI_BUF_NEEDS_INIT;
 
        if (txd) {
                buf->txd = NULL;
@@ -405,13 +397,13 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct mx3_camera_buffer *buf = to_mx3_vb(vb);
 
-       /* This is for locking debugging only */
-       INIT_LIST_HEAD(&buf->queue);
-       sg_init_table(&buf->sg, 1);
+       if (!buf->txd) {
+               /* This is for locking debugging only */
+               INIT_LIST_HEAD(&buf->queue);
+               sg_init_table(&buf->sg, 1);
 
-       buf->state = CSI_BUF_NEEDS_INIT;
-
-       mx3_cam->buf_total += vb2_plane_size(vb, 0);
+               mx3_cam->buf_total += vb2_plane_size(vb, 0);
+       }
 
        return 0;
 }
index b03ffecb7438002ee5aad631453d0fa9030c2edc..1bde255e45dfcd4554594e6fd5f844d130fa5d16 100644 (file)
@@ -171,7 +171,8 @@ static int soc_camera_try_fmt(struct soc_camera_device *icd,
        dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
                pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
-       if (!(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
+       if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
+           !(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
                pix->bytesperline = 0;
                pix->sizeimage = 0;
        }
index 89dce097a827a57d918702b0a4cd415b48ee409e..a397812635d6a6a05d2a0ba4606794f2566a8786 100644 (file)
@@ -378,6 +378,9 @@ EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
 
 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
 {
+       if (mf->fourcc == V4L2_PIX_FMT_JPEG)
+               return 0;
+
        if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
                return width * mf->bits_per_sample / 8;
 
@@ -400,6 +403,9 @@ EXPORT_SYMBOL(soc_mbus_bytes_per_line);
 s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
                        u32 bytes_per_line, u32 height)
 {
+       if (mf->fourcc == V4L2_PIX_FMT_JPEG)
+               return 0;
+
        if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
                return bytes_per_line * height;
 
index 9288fbd5001b26e8bcf3210ffbfc0da7891f1182..5577381b5bf057357c6c4f591e4eb09269c2eb38 100644 (file)
@@ -338,6 +338,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
        if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
                buf->error = 0;
                buf->state = UVC_BUF_STATE_QUEUED;
+               buf->bytesused = 0;
                vb2_set_plane_payload(&buf->buf, 0, 0);
                return buf;
        }
index c3b7b5f59b328a8beea170977261e4d650da88b7..6bc47fc82fe2f799bfff8a3f885fae27bf1a0aa0 100644 (file)
@@ -402,8 +402,10 @@ static void v4l_print_hw_freq_seek(const void *arg, bool write_only)
 {
        const struct v4l2_hw_freq_seek *p = arg;
 
-       pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n",
-               p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing);
+       pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u, "
+               "rangelow=%u, rangehigh=%u\n",
+               p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing,
+               p->rangelow, p->rangehigh);
 }
 
 static void v4l_print_requestbuffers(const void *arg, bool write_only)
@@ -1853,6 +1855,8 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
                        .type = type,
                };
 
+               if (p->index)
+                       return -EINVAL;
                err = ops->vidioc_g_tuner(file, fh, &t);
                if (err)
                        return err;
@@ -1870,6 +1874,8 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
 
                if (type != V4L2_TUNER_RADIO)
                        return -EINVAL;
+               if (p->index)
+                       return -EINVAL;
                err = ops->vidioc_g_modulator(file, fh, &m);
                if (err)
                        return err;
index d1facef28a60d77bc4f3eb8264e7fffeab1fc445..b1a146205c0862587aa81a4a6b32dd7b19322152 100644 (file)
@@ -395,7 +395,8 @@ config MFD_TC6387XB
 
 config MFD_TC6393XB
        bool "Support Toshiba TC6393XB"
-       depends on GPIOLIB && ARM && HAVE_CLK
+       depends on ARM && HAVE_CLK
+       select GPIOLIB
        select MFD_CORE
        select MFD_TMIO
        help
index 383421bf57609a994b7f8d537f97c269d2ab6302..683e18a23329802875d03f92d53e354a6474ad9d 100644 (file)
@@ -925,6 +925,7 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
                        goto out;
        }
 
+       ret = 0;
        if (pdata->leds) {
                int i;
 
index 43a76c41cfcc9fe39084dd2967eaba23a4e87a52..db662e2dcfa5ba3cae4cd07694dc0caa95e72d80 100644 (file)
@@ -202,7 +202,7 @@ static void pcap_isr_work(struct work_struct *work)
                }
                local_irq_enable();
                ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr);
-       } while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
+       } while (gpio_get_value(pdata->gpio));
 }
 
 static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
index c6ffbbe5a6c014b11ee05855795c1c941d0f0abe..d78c05e693f7d45c8cf8ca0971ef2184a73c0597 100644 (file)
@@ -1253,7 +1253,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
                        if (dev->wd_timeout)
                                *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
                        else
-                               *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
+                               *slots -= mei_data2slots(MEI_WD_PARAMS_SIZE);
                }
        }
        if (dev->stop)
index 092330208869640a1e474abfd781bce41a5c6043..7422c76528458134f450eb496d52b1a297e18f8a 100644 (file)
@@ -924,6 +924,27 @@ static struct miscdevice  mei_misc_device = {
                .minor = MISC_DYNAMIC_MINOR,
 };
 
+/**
+ * mei_quirk_probe - probe for devices that doesn't valid ME interface
+ * @pdev: PCI device structure
+ * @ent: entry into pci_device_table
+ *
+ * returns true if ME Interface is valid, false otherwise
+ */
+static bool __devinit mei_quirk_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       u32 reg;
+       if (ent->device == MEI_DEV_ID_PBG_1) {
+               pci_read_config_dword(pdev, 0x48, &reg);
+               /* make sure that bit 9 is up and bit 10 is down */
+               if ((reg & 0x600) == 0x200) {
+                       dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
+                       return false;
+               }
+       }
+       return true;
+}
 /**
  * mei_probe - Device Initialization Routine
  *
@@ -939,6 +960,12 @@ static int __devinit mei_probe(struct pci_dev *pdev,
        int err;
 
        mutex_lock(&mei_mutex);
+
+       if (!mei_quirk_probe(pdev, ent)) {
+               err = -ENODEV;
+               goto end;
+       }
+
        if (mei_device) {
                err = -EEXIST;
                goto end;
index 87b251ab6ec582f2c8177687d0b330d97110fb50..b9e2000969f025894be4bcae2c6950d699ded3a9 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <asm/uv/uv_hub.h>
@@ -59,6 +61,8 @@ static struct xpc_heartbeat_uv *xpc_heartbeat_uv;
                                         XPC_NOTIFY_MSG_SIZE_UV)
 #define XPC_NOTIFY_IRQ_NAME            "xpc_notify"
 
+static int xpc_mq_node = -1;
+
 static struct xpc_gru_mq_uv *xpc_activate_mq_uv;
 static struct xpc_gru_mq_uv *xpc_notify_mq_uv;
 
@@ -109,11 +113,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
 #if defined CONFIG_X86_64
        mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset,
                        UV_AFFINITY_CPU);
-       if (mq->irq < 0) {
-               dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
-                       -mq->irq);
+       if (mq->irq < 0)
                return mq->irq;
-       }
 
        mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset);
 
@@ -238,8 +239,9 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        mq->mmr_blade = uv_cpu_to_blade_id(cpu);
 
        nid = cpu_to_node(cpu);
-       page = alloc_pages_exact_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
-                               pg_order);
+       page = alloc_pages_exact_node(nid,
+                                     GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                                     pg_order);
        if (page == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
                        "bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
@@ -1731,9 +1733,50 @@ static struct xpc_arch_operations xpc_arch_ops_uv = {
        .notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_uv,
 };
 
+static int
+xpc_init_mq_node(int nid)
+{
+       int cpu;
+
+       get_online_cpus();
+
+       for_each_cpu(cpu, cpumask_of_node(nid)) {
+               xpc_activate_mq_uv =
+                       xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, nid,
+                                            XPC_ACTIVATE_IRQ_NAME,
+                                            xpc_handle_activate_IRQ_uv);
+               if (!IS_ERR(xpc_activate_mq_uv))
+                       break;
+       }
+       if (IS_ERR(xpc_activate_mq_uv)) {
+               put_online_cpus();
+               return PTR_ERR(xpc_activate_mq_uv);
+       }
+
+       for_each_cpu(cpu, cpumask_of_node(nid)) {
+               xpc_notify_mq_uv =
+                       xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, nid,
+                                            XPC_NOTIFY_IRQ_NAME,
+                                            xpc_handle_notify_IRQ_uv);
+               if (!IS_ERR(xpc_notify_mq_uv))
+                       break;
+       }
+       if (IS_ERR(xpc_notify_mq_uv)) {
+               xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
+               put_online_cpus();
+               return PTR_ERR(xpc_notify_mq_uv);
+       }
+
+       put_online_cpus();
+       return 0;
+}
+
 int
 xpc_init_uv(void)
 {
+       int nid;
+       int ret = 0;
+
        xpc_arch_ops = xpc_arch_ops_uv;
 
        if (sizeof(struct xpc_notify_mq_msghdr_uv) > XPC_MSG_HDR_MAX_SIZE) {
@@ -1742,21 +1785,21 @@ xpc_init_uv(void)
                return -E2BIG;
        }
 
-       xpc_activate_mq_uv = xpc_create_gru_mq_uv(XPC_ACTIVATE_MQ_SIZE_UV, 0,
-                                                 XPC_ACTIVATE_IRQ_NAME,
-                                                 xpc_handle_activate_IRQ_uv);
-       if (IS_ERR(xpc_activate_mq_uv))
-               return PTR_ERR(xpc_activate_mq_uv);
+       if (xpc_mq_node < 0)
+               for_each_online_node(nid) {
+                       ret = xpc_init_mq_node(nid);
 
-       xpc_notify_mq_uv = xpc_create_gru_mq_uv(XPC_NOTIFY_MQ_SIZE_UV, 0,
-                                               XPC_NOTIFY_IRQ_NAME,
-                                               xpc_handle_notify_IRQ_uv);
-       if (IS_ERR(xpc_notify_mq_uv)) {
-               xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
-               return PTR_ERR(xpc_notify_mq_uv);
-       }
+                       if (!ret)
+                               break;
+               }
+       else
+               ret = xpc_init_mq_node(xpc_mq_node);
 
-       return 0;
+       if (ret < 0)
+               dev_err(xpc_part, "xpc_init_mq_node() returned error=%d\n",
+                       -ret);
+
+       return ret;
 }
 
 void
@@ -1765,3 +1808,6 @@ xpc_exit_uv(void)
        xpc_destroy_gru_mq_uv(xpc_notify_mq_uv);
        xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
 }
+
+module_param(xpc_mq_node, int, 0);
+MODULE_PARM_DESC(xpc_mq_node, "Node number on which to allocate message queues.");
index 1ff460a8e9c74f67e584d634016fa25332fd351c..93b4d67cc4a3a6bc30197acf709d4f73faaad070 100644 (file)
@@ -87,7 +87,7 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data)
        /* communicate to platform about chip wakeup */
        kim_data = st_data->kim_data;
        pdata = kim_data->kim_pdev->dev.platform_data;
-       if (pdata->chip_asleep)
+       if (pdata->chip_awake)
                pdata->chip_awake(NULL);
 }
 
index cfff454f628ba73498f0876355e9c1266d67c7fa..c3bb304eca076ffab133b7cd1e6a363a0763dfaa 100644 (file)
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <asm/io.h>
+#include <asm/sections.h>
 
 /****************************************************************************/
 
-extern char _ebss;
-
 struct map_info uclinux_ram_map = {
        .name = "RAM",
-       .phys = (unsigned long)&_ebss,
+       .phys = (unsigned long)__bss_stop,
        .size = 0,
 };
 
index 31bb7e5b504aa8f05e31472787d2dac7aff9659f..8ca417614c5751f12354cff4b11a7aa94aaa4fcf 100644 (file)
@@ -480,7 +480,7 @@ config MTD_NAND_NANDSIM
 
 config MTD_NAND_GPMI_NAND
         bool "GPMI NAND Flash Controller driver"
-        depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q)
+        depends on MTD_NAND && MXS_DMA
         help
         Enables NAND Flash support for IMX23 or IMX28.
         The GPMI controller is very powerful, with the help of BCH
index e9309b3659e746096b08a953fd055e2517babb3d..ac4fd756eda375ab40f873b9f29bcaad0a5aeea0 100644 (file)
@@ -1245,7 +1245,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
                        goto out_release_mem_region;
                } else {
                        struct dma_slave_config cfg;
-                       int rc;
 
                        memset(&cfg, 0, sizeof(cfg));
                        cfg.src_addr = info->phys_base;
@@ -1254,10 +1253,10 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
                        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                        cfg.src_maxburst = 16;
                        cfg.dst_maxburst = 16;
-                       rc = dmaengine_slave_config(info->dma, &cfg);
-                       if (rc) {
+                       err = dmaengine_slave_config(info->dma, &cfg);
+                       if (err) {
                                dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
-                                       rc);
+                                       err);
                                goto out_release_mem_region;
                        }
                        info->nand.read_buf   = omap_read_buf_dma_pref;
index 545c09ed9079baead2abff5ad9b309a5a0856cac..cff6f023c03a2c78e9869375f93b00c3201af802 100644 (file)
@@ -996,9 +996,7 @@ static int __init cops_module_init(void)
                printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
                        cardname);
        cops_dev = cops_probe(-1);
-       if (IS_ERR(cops_dev))
-               return PTR_ERR(cops_dev);
-        return 0;
+       return PTR_RET(cops_dev);
 }
 
 static void __exit cops_module_exit(void)
index 0910dce3996d08a64c5c158056e0430c472962f1..b5782cdf0bcae1b5500b31477c26a54194f67f41 100644 (file)
@@ -1243,9 +1243,7 @@ static int __init ltpc_module_init(void)
                       "ltpc: Autoprobing is not recommended for modules\n");
 
        dev_ltpc = ltpc_probe();
-       if (IS_ERR(dev_ltpc))
-               return PTR_ERR(dev_ltpc);
-       return 0;
+       return PTR_RET(dev_ltpc);
 }
 module_init(ltpc_module_init);
 #endif
index 6fae5f3ec7f6d646e4efc79aac1a0449ca5bde21..d688a8af432c52a8ea3dc5e45607c2801e9fb831 100644 (file)
@@ -398,7 +398,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
                     sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
        skb->queue_mapping = qdisc_skb_cb(skb)->slave_dev_queue_mapping;
 
-       if (unlikely(netpoll_tx_running(slave_dev)))
+       if (unlikely(netpoll_tx_running(bond->dev)))
                bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);
        else
                dev_queue_xmit(skb);
@@ -1235,12 +1235,12 @@ static inline int slave_enable_netpoll(struct slave *slave)
        struct netpoll *np;
        int err = 0;
 
-       np = kzalloc(sizeof(*np), GFP_KERNEL);
+       np = kzalloc(sizeof(*np), GFP_ATOMIC);
        err = -ENOMEM;
        if (!np)
                goto out;
 
-       err = __netpoll_setup(np, slave->dev);
+       err = __netpoll_setup(np, slave->dev, GFP_ATOMIC);
        if (err) {
                kfree(np);
                goto out;
@@ -1257,9 +1257,7 @@ static inline void slave_disable_netpoll(struct slave *slave)
                return;
 
        slave->np = NULL;
-       synchronize_rcu_bh();
-       __netpoll_cleanup(np);
-       kfree(np);
+       __netpoll_free_rcu(np);
 }
 static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
 {
@@ -1292,7 +1290,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
        read_unlock(&bond->lock);
 }
 
-static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
+static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
 {
        struct bonding *bond = netdev_priv(dev);
        struct slave *slave;
index f0c8bd54ce2930d87a5c6479fef7e9f39e4ca37d..021d69c5d9bc951797ede8e72dde15bad706613b 100644 (file)
@@ -1712,7 +1712,7 @@ e100_set_network_leds(int active)
 static void
 e100_netpoll(struct net_device* netdev)
 {
-       e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
+       e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev);
 }
 #endif
 
index 77bcd4cb4ffb945a8c696cc3f6bab1e363733c48..463b9ec57d8077c8a1599457974ab15dc1210536 100644 (file)
@@ -1278,7 +1278,7 @@ struct bnx2x {
 #define BNX2X_FW_RX_ALIGN_START        (1UL << BNX2X_RX_ALIGN_SHIFT)
 
 #define BNX2X_FW_RX_ALIGN_END                                  \
-       max(1UL << BNX2X_RX_ALIGN_SHIFT,                        \
+       max_t(u64, 1UL << BNX2X_RX_ALIGN_SHIFT,                 \
            SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
 #define BNX2X_PXP_DRAM_ALIGN           (BNX2X_RX_ALIGN_SHIFT - 5)
index dd451c3dd83d1d614a13070e85ffc9a3e8c458e8..02b5a343b19506a2edc60be5dd6b41d781aadb85 100644 (file)
@@ -4041,20 +4041,6 @@ static bool bnx2x_get_load_status(struct bnx2x *bp, int engine)
        return val != 0;
 }
 
-/*
- * Reset the load status for the current engine.
- */
-static void bnx2x_clear_load_status(struct bnx2x *bp)
-{
-       u32 val;
-       u32 mask = (BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK :
-                   BNX2X_PATH0_LOAD_CNT_MASK);
-       bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG);
-       val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
-       REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~mask));
-       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG);
-}
-
 static void _print_next_block(int idx, const char *blk)
 {
        pr_cont("%s%s", idx ? ", " : "", blk);
@@ -9384,32 +9370,24 @@ static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp)
        return rc;
 }
 
-static bool __devinit bnx2x_can_flr(struct bnx2x *bp)
-{
-       int pos;
-       u32 cap;
-       struct pci_dev *dev = bp->pdev;
-
-       pos = pci_pcie_cap(dev);
-       if (!pos)
-               return false;
-
-       pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap);
-       if (!(cap & PCI_EXP_DEVCAP_FLR))
-               return false;
-
-       return true;
-}
-
 static int __devinit bnx2x_do_flr(struct bnx2x *bp)
 {
        int i, pos;
        u16 status;
        struct pci_dev *dev = bp->pdev;
 
-       /* probe the capability first */
-       if (bnx2x_can_flr(bp))
-               return -ENOTTY;
+
+       if (CHIP_IS_E1x(bp)) {
+               BNX2X_DEV_INFO("FLR not supported in E1/E1H\n");
+               return -EINVAL;
+       }
+
+       /* only bootcode REQ_BC_VER_4_INITIATE_FLR and onwards support flr */
+       if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) {
+               BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n",
+                         bp->common.bc_ver);
+               return -EINVAL;
+       }
 
        pos = pci_pcie_cap(dev);
        if (!pos)
@@ -9429,12 +9407,8 @@ static int __devinit bnx2x_do_flr(struct bnx2x *bp)
                "transaction is not cleared; proceeding with reset anyway\n");
 
 clear:
-       if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) {
-               BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n",
-                         bp->common.bc_ver);
-               return -EINVAL;
-       }
 
+       BNX2X_DEV_INFO("Initiating FLR\n");
        bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0);
 
        return 0;
@@ -9454,8 +9428,21 @@ static int __devinit bnx2x_prev_unload_uncommon(struct bnx2x *bp)
         * the one required, then FLR will be sufficient to clean any residue
         * left by previous driver
         */
-       if (bnx2x_test_firmware_version(bp, false) && bnx2x_can_flr(bp))
-               return bnx2x_do_flr(bp);
+       rc = bnx2x_test_firmware_version(bp, false);
+
+       if (!rc) {
+               /* fw version is good */
+               BNX2X_DEV_INFO("FW version matches our own. Attempting FLR\n");
+               rc = bnx2x_do_flr(bp);
+       }
+
+       if (!rc) {
+               /* FLR was performed */
+               BNX2X_DEV_INFO("FLR successful\n");
+               return 0;
+       }
+
+       BNX2X_DEV_INFO("Could not FLR\n");
 
        /* Close the MCP request, return failure*/
        rc = bnx2x_prev_mcp_done(bp);
@@ -11427,9 +11414,6 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        if (!chip_is_e1x)
                REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
 
-       /* Reset the load counter */
-       bnx2x_clear_load_status(bp);
-
        dev->watchdog_timeo = TX_TIMEOUT;
 
        dev->netdev_ops = &bnx2x_netdev_ops;
index 734fd87cd99093e0d30899006cb12cacd10a027c..62f754bd0dfe65704a1af826a754a720dc8cfd43 100644 (file)
@@ -2485,6 +2485,7 @@ static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
                break;
 
        default:
+               kfree(new_cmd);
                BNX2X_ERR("Unknown command: %d\n", cmd);
                return -EINVAL;
        }
index c60de89b66696759a453ff4d69650c1905209c58..90a903d83d8747ca26d711b7b3a188f81a554611 100644 (file)
@@ -1948,7 +1948,7 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
 
        if (adapter->num_rx_qs != MAX_RX_QS)
                dev_info(&adapter->pdev->dev,
-                       "Created only %d receive queues", adapter->num_rx_qs);
+                       "Created only %d receive queues\n", adapter->num_rx_qs);
 
        return 0;
 }
index 0f2d1a710909e5044b3c2c402bf2aba0b950ff88..151453309401694360f311ccb09e0caea8480b01 100644 (file)
@@ -174,8 +174,10 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
 
        new_bus->phy_mask = ~0;
        new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-       if (!new_bus->irq)
+       if (!new_bus->irq) {
+               ret = -ENOMEM;
                goto out_unmap_regs;
+       }
 
        new_bus->parent = &ofdev->dev;
        dev_set_drvdata(&ofdev->dev, new_bus);
index 55bb867258e6aa1d2baa1dbf4da546c705a2e83f..cdf702a594858146fd4f04ab02966d941edeeea5 100644 (file)
@@ -137,8 +137,10 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
        snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start);
 
        fec->fecp = ioremap(res.start, resource_size(&res));
-       if (!fec->fecp)
+       if (!fec->fecp) {
+               ret = -ENOMEM;
                goto out_fec;
+       }
 
        if (get_bus_freq) {
                clock = get_bus_freq(ofdev->dev.of_node);
@@ -172,8 +174,10 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
 
        new_bus->phy_mask = ~0;
        new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-       if (!new_bus->irq)
+       if (!new_bus->irq) {
+               ret = -ENOMEM;
                goto out_unmap_regs;
+       }
 
        new_bus->parent = &ofdev->dev;
        dev_set_drvdata(&ofdev->dev, new_bus);
index 0b3bade957fd8424f59f16ff6e5e27a7c0b6058e..080c89093feb5df6393c6d8f58421ff254f2b05d 100644 (file)
@@ -999,7 +999,7 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
  **/
 static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 {
-       u32 ctrl, ctrl_ext, eecd;
+       u32 ctrl, ctrl_ext, eecd, tctl;
        s32 ret_val;
 
        /*
@@ -1014,7 +1014,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
        ew32(IMC, 0xffffffff);
 
        ew32(RCTL, 0);
-       ew32(TCTL, E1000_TCTL_PSP);
+       tctl = er32(TCTL);
+       tctl &= ~E1000_TCTL_EN;
+       ew32(TCTL, tctl);
        e1e_flush();
 
        usleep_range(10000, 20000);
@@ -1601,10 +1603,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
                         * auto-negotiation in the TXCW register and disable
                         * forced link in the Device Control register in an
                         * attempt to auto-negotiate with our link partner.
-                        * If the partner code word is null, stop forcing
-                        * and restart auto negotiation.
                         */
-                       if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW))  {
+                       if (rxcw & E1000_RXCW_C) {
                                /* Enable autoneg, and unforce link up */
                                ew32(TXCW, mac->txcw);
                                ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
index 95b245310f1761fa4f9b06de319cea48fdc28c92..46c3b1f9ff8997af685836bb82fb0e1bd5e599cf 100644 (file)
@@ -178,6 +178,24 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
        pr_info("%-15s %08x %08x\n", rname, regs[0], regs[1]);
 }
 
+static void e1000e_dump_ps_pages(struct e1000_adapter *adapter,
+                                struct e1000_buffer *bi)
+{
+       int i;
+       struct e1000_ps_page *ps_page;
+
+       for (i = 0; i < adapter->rx_ps_pages; i++) {
+               ps_page = &bi->ps_pages[i];
+
+               if (ps_page->page) {
+                       pr_info("packet dump for ps_page %d:\n", i);
+                       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
+                                      16, 1, page_address(ps_page->page),
+                                      PAGE_SIZE, true);
+               }
+       }
+}
+
 /*
  * e1000e_dump - Print registers, Tx-ring and Rx-ring
  */
@@ -299,10 +317,10 @@ static void e1000e_dump(struct e1000_adapter *adapter)
                        (unsigned long long)buffer_info->time_stamp,
                        buffer_info->skb, next_desc);
 
-               if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+               if (netif_msg_pktdata(adapter) && buffer_info->skb)
                        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
-                                      16, 1, phys_to_virt(buffer_info->dma),
-                                      buffer_info->length, true);
+                                      16, 1, buffer_info->skb->data,
+                                      buffer_info->skb->len, true);
        }
 
        /* Print Rx Ring Summary */
@@ -381,10 +399,8 @@ rx_ring_summary:
                                        buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter))
-                                       print_hex_dump(KERN_INFO, "",
-                                               DUMP_PREFIX_ADDRESS, 16, 1,
-                                               phys_to_virt(buffer_info->dma),
-                                               adapter->rx_ps_bsize0, true);
+                                       e1000e_dump_ps_pages(adapter,
+                                                            buffer_info);
                        }
                }
                break;
@@ -444,12 +460,12 @@ rx_ring_summary:
                                        (unsigned long long)buffer_info->dma,
                                        buffer_info->skb, next_desc);
 
-                               if (netif_msg_pktdata(adapter))
+                               if (netif_msg_pktdata(adapter) &&
+                                   buffer_info->skb)
                                        print_hex_dump(KERN_INFO, "",
                                                       DUMP_PREFIX_ADDRESS, 16,
                                                       1,
-                                                      phys_to_virt
-                                                      (buffer_info->dma),
+                                                      buffer_info->skb->data,
                                                       adapter->rx_buffer_len,
                                                       true);
                        }
index 5e84eaac48c191727d9ac733c80ffbb13ce1473f..ba994fb4cec69bc60baaff7c9407faf9553d40be 100644 (file)
@@ -254,6 +254,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
         */
        size += NVM_WORD_SIZE_BASE_SHIFT;
 
+       /*
+        * Check for invalid size
+        */
+       if ((hw->mac.type == e1000_82576) && (size > 15)) {
+               pr_notice("The NVM size is not valid, defaulting to 32K\n");
+               size = 15;
+       }
+
        nvm->word_size = 1 << size;
        if (hw->mac.type < e1000_i210) {
                nvm->opcode_bits        = 8;
@@ -281,14 +289,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
        } else
                nvm->type = e1000_nvm_flash_hw;
 
-       /*
-        * Check for invalid size
-        */
-       if ((hw->mac.type == e1000_82576) && (size > 15)) {
-               pr_notice("The NVM size is not valid, defaulting to 32K\n");
-               size = 15;
-       }
-
        /* NVM Function Pointers */
        switch (hw->mac.type) {
        case e1000_82580:
index 10efcd88dca00c81ef2539914851d25536447c78..28394bea5253fc280e1aba973b20958ed1b9662f 100644 (file)
                                    : (0x0E018 + ((_n) * 0x40)))
 #define E1000_TXDCTL(_n)  ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) \
                                    : (0x0E028 + ((_n) * 0x40)))
-#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
-#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
+#define E1000_RXCTL(_n)          ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
+                                     (0x0C014 + ((_n) * 0x40)))
+#define E1000_DCA_RXCTRL(_n)   E1000_RXCTL(_n)
+#define E1000_TXCTL(_n)   ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
+                                     (0x0E014 + ((_n) * 0x40)))
+#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
 #define E1000_TDWBAL(_n)  ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) \
                                    : (0x0E038 + ((_n) * 0x40)))
 #define E1000_TDWBAH(_n)  ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) \
index a19c84cad0e991fc429b846b913f704e9cc41f30..70591117051bf2faa446af5a3b81055f091d491d 100644 (file)
@@ -209,8 +209,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
        /* When SoL/IDER sessions are active, autoneg/speed/duplex
         * cannot be changed */
        if (igb_check_reset_block(hw)) {
-               dev_err(&adapter->pdev->dev, "Cannot change link "
-                       "characteristics when SoL/IDER is active.\n");
+               dev_err(&adapter->pdev->dev,
+                       "Cannot change link characteristics when SoL/IDER is active.\n");
                return -EINVAL;
        }
 
@@ -1089,8 +1089,8 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
                wr32(reg, (_test[pat] & write));
                val = rd32(reg) & mask;
                if (val != (_test[pat] & write & mask)) {
-                       dev_err(&adapter->pdev->dev, "pattern test reg %04X "
-                               "failed: got 0x%08X expected 0x%08X\n",
+                       dev_err(&adapter->pdev->dev,
+                               "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
                                reg, val, (_test[pat] & write & mask));
                        *data = reg;
                        return 1;
@@ -1108,8 +1108,8 @@ static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
        wr32(reg, write & mask);
        val = rd32(reg);
        if ((write & mask) != (val & mask)) {
-               dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:"
-                       " got 0x%08X expected 0x%08X\n", reg,
+               dev_err(&adapter->pdev->dev,
+                       "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", reg,
                        (val & mask), (write & mask));
                *data = reg;
                return 1;
@@ -1171,8 +1171,9 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
        wr32(E1000_STATUS, toggle);
        after = rd32(E1000_STATUS) & toggle;
        if (value != after) {
-               dev_err(&adapter->pdev->dev, "failed STATUS register test "
-                       "got: 0x%08X expected: 0x%08X\n", after, value);
+               dev_err(&adapter->pdev->dev,
+                       "failed STATUS register test got: 0x%08X expected: 0x%08X\n",
+                       after, value);
                *data = 1;
                return 1;
        }
@@ -1497,6 +1498,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
                break;
        }
 
+       /* add small delay to avoid loopback test failure */
+       msleep(50);
+
        /* force 1000, set loopback */
        igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
 
@@ -1777,16 +1781,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
         * sessions are active */
        if (igb_check_reset_block(&adapter->hw)) {
                dev_err(&adapter->pdev->dev,
-                       "Cannot do PHY loopback test "
-                       "when SoL/IDER is active.\n");
+                       "Cannot do PHY loopback test when SoL/IDER is active.\n");
                *data = 0;
                goto out;
        }
        if ((adapter->hw.mac.type == e1000_i210)
-               || (adapter->hw.mac.type == e1000_i210)) {
+               || (adapter->hw.mac.type == e1000_i211)) {
                dev_err(&adapter->pdev->dev,
-                       "Loopback test not supported "
-                       "on this part at this time.\n");
+                       "Loopback test not supported on this part at this time.\n");
                *data = 0;
                goto out;
        }
index b7c2d5050572828c8d07e228b2e44235e9f01801..48cc4fb1a307f0d7c2821cc9f57c4c67d0ffc31b 100644 (file)
@@ -462,10 +462,10 @@ static void igb_dump(struct igb_adapter *adapter)
                                (u64)buffer_info->time_stamp,
                                buffer_info->skb, next_desc);
 
-                       if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+                       if (netif_msg_pktdata(adapter) && buffer_info->skb)
                                print_hex_dump(KERN_INFO, "",
                                        DUMP_PREFIX_ADDRESS,
-                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       16, 1, buffer_info->skb->data,
                                        buffer_info->length, true);
                }
        }
@@ -547,18 +547,17 @@ rx_ring_summary:
                                        (u64)buffer_info->dma,
                                        buffer_info->skb, next_desc);
 
-                               if (netif_msg_pktdata(adapter)) {
+                               if (netif_msg_pktdata(adapter) &&
+                                   buffer_info->dma && buffer_info->skb) {
                                        print_hex_dump(KERN_INFO, "",
-                                               DUMP_PREFIX_ADDRESS,
-                                               16, 1,
-                                               phys_to_virt(buffer_info->dma),
-                                               IGB_RX_HDR_LEN, true);
+                                                 DUMP_PREFIX_ADDRESS,
+                                                 16, 1, buffer_info->skb->data,
+                                                 IGB_RX_HDR_LEN, true);
                                        print_hex_dump(KERN_INFO, "",
                                          DUMP_PREFIX_ADDRESS,
                                          16, 1,
-                                         phys_to_virt(
-                                           buffer_info->page_dma +
-                                           buffer_info->page_offset),
+                                         page_address(buffer_info->page) +
+                                                     buffer_info->page_offset,
                                          PAGE_SIZE/2, true);
                                }
                        }
index 50fc137501da087d9cb73c1c924a0e9f85562c79..18bf08c9d7a4428e3a82f9f29a5837fddc3f6860 100644 (file)
@@ -804,12 +804,13 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
            link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
                /* Set KX4/KX/KR support according to speed requested */
                autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP);
-               if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+               if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
                        if (orig_autoc & IXGBE_AUTOC_KX4_SUPP)
                                autoc |= IXGBE_AUTOC_KX4_SUPP;
                        if ((orig_autoc & IXGBE_AUTOC_KR_SUPP) &&
                            (hw->phy.smart_speed_active == false))
                                autoc |= IXGBE_AUTOC_KR_SUPP;
+               }
                if (speed & IXGBE_LINK_SPEED_1GB_FULL)
                        autoc |= IXGBE_AUTOC_KX_SUPP;
        } else if ((pma_pmd_1g == IXGBE_AUTOC_1G_SFI) &&
index f32e703007702ba0652bca4bce23f7ac44287c14..5aba5ecdf1e28157fadf44072c87a4a98511d249 100644 (file)
@@ -614,8 +614,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                /* If source MAC is equal to our own MAC and not performing
                 * the selftest or flb disabled - drop the packet */
                if (s_mac == priv->mac &&
-                       (!(dev->features & NETIF_F_LOOPBACK) ||
-                        !priv->validate_loopback))
+                   !((dev->features & NETIF_F_LOOPBACK) ||
+                     priv->validate_loopback))
                        goto next;
 
                /*
index 019d856b1334fc4e7b389eb00d16da872d63ee4a..10bba09c44ea508d047123aeafb5e001b6bbd1be 100644 (file)
@@ -164,7 +164,6 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
        ring->cons = 0xffffffff;
        ring->last_nr_txbb = 1;
        ring->poll_cnt = 0;
-       ring->blocked = 0;
        memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
        memset(ring->buf, 0, ring->buf_size);
 
@@ -365,14 +364,13 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        ring->cons += txbbs_skipped;
        netdev_tx_completed_queue(ring->tx_queue, packets, bytes);
 
-       /* Wakeup Tx queue if this ring stopped it */
-       if (unlikely(ring->blocked)) {
-               if ((u32) (ring->prod - ring->cons) <=
-                    ring->size - HEADROOM - MAX_DESC_TXBBS) {
-                       ring->blocked = 0;
-                       netif_tx_wake_queue(ring->tx_queue);
-                       priv->port_stats.wake_queue++;
-               }
+       /*
+        * Wakeup Tx queue if this stopped, and at least 1 packet
+        * was completed
+        */
+       if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) {
+               netif_tx_wake_queue(ring->tx_queue);
+               priv->port_stats.wake_queue++;
        }
 }
 
@@ -592,7 +590,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
                /* every full Tx ring stops queue */
                netif_tx_stop_queue(ring->tx_queue);
-               ring->blocked = 1;
                priv->port_stats.queue_stopped++;
 
                return NETDEV_TX_BUSY;
index 88b7b3e75ab197706b3a1f0c7fa953e1f5f9da0b..daf41792366147c7381e9f8f7f1017489c55a57e 100644 (file)
@@ -358,13 +358,14 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 }
 
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-                       u64 virt, int obj_size, int nobj, int reserved,
+                       u64 virt, int obj_size, u32 nobj, int reserved,
                        int use_lowmem, int use_coherent)
 {
        int obj_per_chunk;
        int num_icm;
        unsigned chunk_size;
        int i;
+       u64 size;
 
        obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size;
        num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk;
@@ -380,10 +381,12 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
        table->coherent = use_coherent;
        mutex_init(&table->mutex);
 
+       size = (u64) nobj * obj_size;
        for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
                chunk_size = MLX4_TABLE_CHUNK_SIZE;
-               if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > nobj * obj_size)
-                       chunk_size = PAGE_ALIGN(nobj * obj_size - i * MLX4_TABLE_CHUNK_SIZE);
+               if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > size)
+                       chunk_size = PAGE_ALIGN(size -
+                                       i * MLX4_TABLE_CHUNK_SIZE);
 
                table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
                                               (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
index 19e4efc0b3429adb982b69c5366321385c8d3e05..a67744f53506af7f86c0de581445e1e67568de7f 100644 (file)
@@ -78,7 +78,7 @@ int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
                          int start, int end);
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-                       u64 virt, int obj_size, int nobj, int reserved,
+                       u64 virt, int obj_size, u32 nobj, int reserved,
                        int use_lowmem, int use_coherent);
 void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
 void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle);
index 48d0e90194cb19d2a322990425b478f9e178b623..827b72dfce99690093f0fe81ee3ccf804d59db85 100644 (file)
@@ -157,9 +157,6 @@ int mlx4_check_port_params(struct mlx4_dev *dev,
                                         "on this HCA, aborting.\n");
                                return -EINVAL;
                        }
-                       if (port_type[i] == MLX4_PORT_TYPE_ETH &&
-                           port_type[i + 1] == MLX4_PORT_TYPE_IB)
-                               return -EINVAL;
                }
        }
 
index 4ec3835e1bc2cb8dd88958ce7a1276150898e86f..a018ea2a43deb9c67e773032e62d8a83f54bb3d9 100644 (file)
@@ -432,8 +432,10 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port,
                        if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
                                /* Entry already exists, add to duplicates */
                                dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
-                               if (!dqp)
+                               if (!dqp) {
+                                       err = -ENOMEM;
                                        goto out_mailbox;
+                               }
                                dqp->qpn = qpn;
                                list_add_tail(&dqp->list, &entry->duplicates);
                                found = true;
index 59ebc0339638a3c760f8b540d2066a7aaa7fa9cb..4d9df8f2a12617047355fc9988d5187af80a95f5 100644 (file)
@@ -249,7 +249,7 @@ struct mlx4_bitmap {
 struct mlx4_buddy {
        unsigned long         **bits;
        unsigned int           *num_free;
-       int                     max_order;
+       u32                     max_order;
        spinlock_t              lock;
 };
 
@@ -258,7 +258,7 @@ struct mlx4_icm;
 struct mlx4_icm_table {
        u64                     virt;
        int                     num_icm;
-       int                     num_obj;
+       u32                     num_obj;
        int                     obj_size;
        int                     lowmem;
        int                     coherent;
index 5f1ab105debc28b4b8ba7bdaca3f0bcb2f1cdb66..9d27e42264e2b64aea3827d760c409ab3de0c301 100644 (file)
@@ -248,7 +248,6 @@ struct mlx4_en_tx_ring {
        u32 doorbell_qpn;
        void *buf;
        u16 poll_cnt;
-       int blocked;
        struct mlx4_en_tx_info *tx_info;
        u8 *bounce_buf;
        u32 last_nr_txbb;
index af55b7ce53413cc27273b9102e609c0ae97d6169..c202d3ad2a0efbb6a852b18874414ba1036a1129 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/vmalloc.h>
 
 #include <linux/mlx4/cmd.h>
 
@@ -120,7 +121,7 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
        buddy->max_order = max_order;
        spin_lock_init(&buddy->lock);
 
-       buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *),
+       buddy->bits = kcalloc(buddy->max_order + 1, sizeof (long *),
                              GFP_KERNEL);
        buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free,
                                  GFP_KERNEL);
@@ -129,10 +130,12 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 
        for (i = 0; i <= buddy->max_order; ++i) {
                s = BITS_TO_LONGS(1 << (buddy->max_order - i));
-               buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
-               if (!buddy->bits[i])
-                       goto err_out_free;
-               bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i));
+               buddy->bits[i] = kcalloc(s, sizeof (long), GFP_KERNEL | __GFP_NOWARN);
+               if (!buddy->bits[i]) {
+                       buddy->bits[i] = vzalloc(s * sizeof(long));
+                       if (!buddy->bits[i])
+                               goto err_out_free;
+               }
        }
 
        set_bit(0, buddy->bits[buddy->max_order]);
@@ -142,7 +145,10 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 
 err_out_free:
        for (i = 0; i <= buddy->max_order; ++i)
-               kfree(buddy->bits[i]);
+               if (buddy->bits[i] && is_vmalloc_addr(buddy->bits[i]))
+                       vfree(buddy->bits[i]);
+               else
+                       kfree(buddy->bits[i]);
 
 err_out:
        kfree(buddy->bits);
@@ -156,7 +162,10 @@ static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy)
        int i;
 
        for (i = 0; i <= buddy->max_order; ++i)
-               kfree(buddy->bits[i]);
+               if (is_vmalloc_addr(buddy->bits[i]))
+                       vfree(buddy->bits[i]);
+               else
+                       kfree(buddy->bits[i]);
 
        kfree(buddy->bits);
        kfree(buddy->num_free);
@@ -668,7 +677,7 @@ int mlx4_init_mr_table(struct mlx4_dev *dev)
                return err;
 
        err = mlx4_buddy_init(&mr_table->mtt_buddy,
-                             ilog2(dev->caps.num_mtts /
+                             ilog2((u32)dev->caps.num_mtts /
                              (1 << log_mtts_per_seg)));
        if (err)
                goto err_buddy;
@@ -678,7 +687,7 @@ int mlx4_init_mr_table(struct mlx4_dev *dev)
                        mlx4_alloc_mtt_range(dev,
                                             fls(dev->caps.reserved_mtts - 1));
                if (priv->reserved_mtts < 0) {
-                       mlx4_warn(dev, "MTT table of order %d is too small.\n",
+                       mlx4_warn(dev, "MTT table of order %u is too small.\n",
                                  mr_table->mtt_buddy.max_order);
                        err = -ENOMEM;
                        goto err_reserve_mtts;
index 9ee4725363d5d25d88135d2bbffb4d67a67023ab..8e0c3cc2a1ec786739de7298fc450c483d8fe37a 100644 (file)
@@ -76,7 +76,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
                u64 size;
                u64 start;
                int type;
-               int num;
+               u32 num;
                int log_num;
        };
 
@@ -105,7 +105,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
        si_meminfo(&si);
        request->num_mtt =
                roundup_pow_of_two(max_t(unsigned, request->num_mtt,
-                                        min(1UL << 31,
+                                        min(1UL << (31 - log_mtts_per_seg),
                                             si.totalram >> (log_mtts_per_seg - 1))));
 
        profile[MLX4_RES_QP].size     = dev_cap->qpc_entry_sz;
index 802498293528307b5c2e123eae089f84929759ea..34ee09bae36e98dcb28c8ff9b4c8d12a2da97292 100644 (file)
@@ -80,20 +80,6 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev,
                        stype[i - 1] = defaults[i - 1];
        }
 
-       /*
-        * Adjust port configuration:
-        * If port 1 sensed nothing and port 2 is IB, set both as IB
-        * If port 2 sensed nothing and port 1 is Eth, set both as Eth
-        */
-       if (stype[0] == MLX4_PORT_TYPE_ETH) {
-               for (i = 1; i < dev->caps.num_ports; i++)
-                       stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH;
-       }
-       if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) {
-               for (i = 0; i < dev->caps.num_ports - 1; i++)
-                       stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB;
-       }
-
        /*
         * If sensed nothing, remain in current configuration.
         */
index 4069edab229e9a53cfc3bdec5256cf4cdbc573ae..53743f7a2ca9604d6f264de3a2e3c727556a0619 100644 (file)
@@ -346,28 +346,15 @@ static phy_interface_t lpc_phy_interface_mode(struct device *dev)
                                                   "phy-mode", NULL);
                if (mode && !strcmp(mode, "mii"))
                        return PHY_INTERFACE_MODE_MII;
-               return PHY_INTERFACE_MODE_RMII;
        }
-
-       /* non-DT */
-#ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT
-       return PHY_INTERFACE_MODE_MII;
-#else
        return PHY_INTERFACE_MODE_RMII;
-#endif
 }
 
 static bool use_iram_for_net(struct device *dev)
 {
        if (dev && dev->of_node)
                return of_property_read_bool(dev->of_node, "use-iram");
-
-       /* non-DT */
-#ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET
-       return true;
-#else
        return false;
-#endif
 }
 
 /* Receive Status information word */
index 46df3a04030c20af3a3288d7a27423b095694dfc..24c2305d7948455ca52ada710893599067533104 100644 (file)
@@ -8,7 +8,7 @@ config SH_ETH
                (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
                 CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
                 CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \
-                CPU_SUBTYPE_SH7757 || ARCH_R8A7740)
+                CPU_SUBTYPE_SH7757 || ARCH_R8A7740 || ARCH_R8A7779)
        select CRC32
        select NET_CORE
        select MII
@@ -18,4 +18,4 @@ config SH_ETH
          Renesas SuperH Ethernet device driver.
          This driver supporting CPUs are:
                - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757,
-                 and R8A7740.
+                 R8A7740 and R8A7779.
index af0b867a6cf6247ccf4f002af29d5832c03f368b..bad8f2eec9b46f652298a3d9f0b48edbef1ac6b8 100644 (file)
@@ -78,7 +78,7 @@ static void sh_eth_select_mii(struct net_device *ndev)
 #endif
 
 /* There is CPU dependent code */
-#if defined(CONFIG_CPU_SUBTYPE_SH7724)
+#if defined(CONFIG_CPU_SUBTYPE_SH7724) || defined(CONFIG_ARCH_R8A7779)
 #define SH_ETH_RESET_DEFAULT   1
 static void sh_eth_set_duplex(struct net_device *ndev)
 {
@@ -93,13 +93,18 @@ static void sh_eth_set_duplex(struct net_device *ndev)
 static void sh_eth_set_rate(struct net_device *ndev)
 {
        struct sh_eth_private *mdp = netdev_priv(ndev);
+       unsigned int bits = ECMR_RTM;
+
+#if defined(CONFIG_ARCH_R8A7779)
+       bits |= ECMR_ELB;
+#endif
 
        switch (mdp->speed) {
        case 10: /* 10BASE */
-               sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_RTM, ECMR);
+               sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~bits, ECMR);
                break;
        case 100:/* 100BASE */
-               sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_RTM, ECMR);
+               sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | bits, ECMR);
                break;
        default:
                break;
index 70554a1b2b02dd37440db75ba06ec9eed8c84fe9..65a8d49106a4c63c6a7faf04c8e3334421ce6472 100644 (file)
@@ -1503,6 +1503,11 @@ static int efx_probe_all(struct efx_nic *efx)
                goto fail2;
        }
 
+       BUILD_BUG_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_RXQ_MIN_ENT);
+       if (WARN_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_TXQ_MIN_ENT(efx))) {
+               rc = -EINVAL;
+               goto fail3;
+       }
        efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
 
        rc = efx_probe_filters(efx);
@@ -2070,6 +2075,7 @@ static int efx_register_netdev(struct efx_nic *efx)
        net_dev->irq = efx->pci_dev->irq;
        net_dev->netdev_ops = &efx_netdev_ops;
        SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
+       net_dev->gso_max_segs = EFX_TSO_MAX_SEGS;
 
        rtnl_lock();
 
index be8f9158a7149388b5e4edfeb41ee2c848319a28..70755c97251aaab4e9cafe969b0a8b95821a1cbb 100644 (file)
@@ -30,6 +30,7 @@ extern netdev_tx_t
 efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
 extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
 extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc);
+extern unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
 
 /* RX */
 extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
@@ -52,10 +53,15 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
 #define EFX_MAX_EVQ_SIZE 16384UL
 #define EFX_MIN_EVQ_SIZE 512UL
 
-/* The smallest [rt]xq_entries that the driver supports. Callers of
- * efx_wake_queue() assume that they can subsequently send at least one
- * skb. Falcon/A1 may require up to three descriptors per skb_frag. */
-#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS))
+/* Maximum number of TCP segments we support for soft-TSO */
+#define EFX_TSO_MAX_SEGS       100
+
+/* The smallest [rt]xq_entries that the driver supports.  RX minimum
+ * is a bit arbitrary.  For TX, we must have space for at least 2
+ * TSO skbs.
+ */
+#define EFX_RXQ_MIN_ENT                128U
+#define EFX_TXQ_MIN_ENT(efx)   (2 * efx_tx_max_skb_descs(efx))
 
 /* Filters */
 extern int efx_probe_filters(struct efx_nic *efx);
index 10536f93b5611d15a22a56b3ca280e0f107ea828..8cba2df82b18b9f2dfa1ff82eee3b22ef9eeb0c9 100644 (file)
@@ -680,21 +680,27 @@ static int efx_ethtool_set_ringparam(struct net_device *net_dev,
                                     struct ethtool_ringparam *ring)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
+       u32 txq_entries;
 
        if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
            ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
            ring->tx_pending > EFX_MAX_DMAQ_SIZE)
                return -EINVAL;
 
-       if (ring->rx_pending < EFX_MIN_RING_SIZE ||
-           ring->tx_pending < EFX_MIN_RING_SIZE) {
+       if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
                netif_err(efx, drv, efx->net_dev,
-                         "TX and RX queues cannot be smaller than %ld\n",
-                         EFX_MIN_RING_SIZE);
+                         "RX queues cannot be smaller than %u\n",
+                         EFX_RXQ_MIN_ENT);
                return -EINVAL;
        }
 
-       return efx_realloc_channels(efx, ring->rx_pending, ring->tx_pending);
+       txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
+       if (txq_entries != ring->tx_pending)
+               netif_warn(efx, drv, efx->net_dev,
+                          "increasing TX queue size to minimum of %u\n",
+                          txq_entries);
+
+       return efx_realloc_channels(efx, ring->rx_pending, txq_entries);
 }
 
 static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
index 9b225a7769f765a1f1bf3ef024ae3b73a18a66c2..18713436b44345a110ed263d54c5411d1e93c6fa 100644 (file)
@@ -119,6 +119,25 @@ efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
        return len;
 }
 
+unsigned int efx_tx_max_skb_descs(struct efx_nic *efx)
+{
+       /* Header and payload descriptor for each output segment, plus
+        * one for every input fragment boundary within a segment
+        */
+       unsigned int max_descs = EFX_TSO_MAX_SEGS * 2 + MAX_SKB_FRAGS;
+
+       /* Possibly one more per segment for the alignment workaround */
+       if (EFX_WORKAROUND_5391(efx))
+               max_descs += EFX_TSO_MAX_SEGS;
+
+       /* Possibly more for PCIe page boundaries within input fragments */
+       if (PAGE_SIZE > EFX_PAGE_SIZE)
+               max_descs += max_t(unsigned int, MAX_SKB_FRAGS,
+                                  DIV_ROUND_UP(GSO_MAX_SIZE, EFX_PAGE_SIZE));
+
+       return max_descs;
+}
+
 /*
  * Add a socket buffer to a TX queue
  *
index fd8882f9602afc43b6fe6ecd79a14defb5ac8dbe..c136162e6473e1746b48f50a0c7cc0adc57986d6 100644 (file)
@@ -2077,7 +2077,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
                goto error_netdev_register;
        }
 
-       priv->stmmac_clk = clk_get(priv->device, NULL);
+       priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME);
        if (IS_ERR(priv->stmmac_clk)) {
                pr_warning("%s: warning: cannot get CSR clock\n", __func__);
                goto error_clk_get;
index cd01ee7ecef19339c90765747a57b2d621765806..b93245c11995bc15329321e6879be78d4c1b44dc 100644 (file)
@@ -74,7 +74,7 @@ static int __devinit stmmac_probe_config_dt(struct platform_device *pdev,
  * the necessary resources and invokes the main to init
  * the net device, register the mdio bus etc.
  */
-static int stmmac_pltfr_probe(struct platform_device *pdev)
+static int __devinit stmmac_pltfr_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct resource *res;
index 3b5c4571b55e3c922a4b6e5a94a0a4a8adcb2fce..d15c888e9df8a15b02d104ace349c1926ad81107 100644 (file)
@@ -538,11 +538,12 @@ EXPORT_SYMBOL_GPL(cpdma_chan_create);
 
 int cpdma_chan_destroy(struct cpdma_chan *chan)
 {
-       struct cpdma_ctlr *ctlr = chan->ctlr;
+       struct cpdma_ctlr *ctlr;
        unsigned long flags;
 
        if (!chan)
                return -EINVAL;
+       ctlr = chan->ctlr;
 
        spin_lock_irqsave(&ctlr->lock, flags);
        if (chan->state != CPDMA_STATE_IDLE)
index 482648fcf0b6327bb9c482c1c36880ece1627caa..98934bdf6acffc053fcd317721e8d92cf649ba14 100644 (file)
@@ -1003,6 +1003,7 @@ static int ixp4xx_nway_reset(struct net_device *dev)
 }
 
 int ixp46x_phc_index = -1;
+EXPORT_SYMBOL_GPL(ixp46x_phc_index);
 
 static int ixp4xx_get_ts_info(struct net_device *dev,
                              struct ethtool_ts_info *info)
index 6cee2917eb0276369e6933ebf933c386167fa9a4..4a1a5f58fa73ffd7899429bcaf28062e29f83dc3 100644 (file)
@@ -383,13 +383,6 @@ int netvsc_device_remove(struct hv_device *device)
        unsigned long flags;
 
        net_device = hv_get_drvdata(device);
-       spin_lock_irqsave(&device->channel->inbound_lock, flags);
-       net_device->destroy = true;
-       spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
-
-       /* Wait for all send completions */
-       wait_event(net_device->wait_drain,
-                  atomic_read(&net_device->num_outstanding_sends) == 0);
 
        netvsc_disconnect_vsp(net_device);
 
index e5d6146937fa0aade2476662ce87084b7337187c..1e88a1095934a6d7b62c84cf1fff0e083f088881 100644 (file)
@@ -718,6 +718,9 @@ static void rndis_filter_halt_device(struct rndis_device *dev)
 {
        struct rndis_request *request;
        struct rndis_halt_request *halt;
+       struct netvsc_device *nvdev = dev->net_dev;
+       struct hv_device *hdev = nvdev->dev;
+       ulong flags;
 
        /* Attempt to do a rndis device halt */
        request = get_rndis_request(dev, RNDIS_MSG_HALT,
@@ -735,6 +738,14 @@ static void rndis_filter_halt_device(struct rndis_device *dev)
        dev->state = RNDIS_DEV_UNINITIALIZED;
 
 cleanup:
+       spin_lock_irqsave(&hdev->channel->inbound_lock, flags);
+       nvdev->destroy = true;
+       spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags);
+
+       /* Wait for all send completions */
+       wait_event(nvdev->wait_drain,
+               atomic_read(&nvdev->num_outstanding_sends) == 0);
+
        if (request)
                put_rndis_request(dev, request);
        return;
index a561ae44a9ac1c982b1d5390a6f288abe0094523..c6a0299aa9f912241e6b544727df47913b01db1d 100644 (file)
@@ -158,7 +158,7 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
        /* If not add the 'RPOLC', we can't catch the receive interrupt.
         * It's related with the HW layout and the IR transiver.
         */
-       val |= IREN | RPOLC;
+       val |= UMOD_IRDA | RPOLC;
        UART_PUT_GCTL(port, val);
        return ret;
 }
@@ -432,7 +432,7 @@ static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev
        bfin_sir_stop_rx(port);
 
        val = UART_GET_GCTL(port);
-       val &= ~(UCEN | IREN | RPOLC);
+       val &= ~(UCEN | UMOD_MASK | RPOLC);
        UART_PUT_GCTL(port, val);
 
 #ifdef CONFIG_SIR_BFIN_DMA
@@ -518,10 +518,10 @@ static void bfin_sir_send_work(struct work_struct *work)
         * reset all the UART.
         */
        val = UART_GET_GCTL(port);
-       val &= ~(IREN | RPOLC);
+       val &= ~(UMOD_MASK | RPOLC);
        UART_PUT_GCTL(port, val);
        SSYNC();
-       val |= IREN | RPOLC;
+       val |= UMOD_IRDA | RPOLC;
        UART_PUT_GCTL(port, val);
        SSYNC();
        /* bfin_sir_set_speed(port, self->speed); */
index 824e2a93fe8a68d0228897828a51a010e9a8306b..5f3aeac3f86df57e297b1559a5bda2b7669145a9 100644 (file)
@@ -542,6 +542,7 @@ static int ks959_net_open(struct net_device *netdev)
        sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
        kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
        if (!kingsun->irlap) {
+               err = -ENOMEM;
                dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
                goto free_mem;
        }
index 5a278ab83c2f040e3ac0f8427f6744b15e42de26..2d4b6a1ab2029b0d2267cf967931e47c84796123 100644 (file)
@@ -436,6 +436,7 @@ static int ksdazzle_net_open(struct net_device *netdev)
        sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
        kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
        if (!kingsun->irlap) {
+               err = -ENOMEM;
                dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
                goto free_mem;
        }
index 0737bd4d16696e4a90475a124f17568f87eb2c14..0f0f9ce3a7769ec552cc9f01f1915b44e44958fe 100644 (file)
@@ -94,7 +94,8 @@ static int get_slot(struct macvlan_dev *vlan, struct macvtap_queue *q)
        int i;
 
        for (i = 0; i < MAX_MACVTAP_QUEUES; i++) {
-               if (rcu_dereference(vlan->taps[i]) == q)
+               if (rcu_dereference_protected(vlan->taps[i],
+                                             lockdep_is_held(&macvtap_lock)) == q)
                        return i;
        }
 
index f9347ea3d381e113d20c6a13ec32f0f51c5fc04c..b3321129a83c6dc33180fbbb07aadad296f14554 100644 (file)
@@ -640,15 +640,9 @@ static int netconsole_netdev_event(struct notifier_block *this,
                                 * rtnl_lock already held
                                 */
                                if (nt->np.dev) {
-                                       spin_unlock_irqrestore(
-                                                             &target_list_lock,
-                                                             flags);
                                        __netpoll_cleanup(&nt->np);
-                                       spin_lock_irqsave(&target_list_lock,
-                                                         flags);
                                        dev_put(nt->np.dev);
                                        nt->np.dev = NULL;
-                                       netconsole_target_put(nt);
                                }
                                nt->enabled = 0;
                                stopped = true;
index e0cc4ef33dee2b035ee576ecbb17196984925d74..eefe49e8713ca633c8383b1c388826f45e5c9e0c 100644 (file)
@@ -101,7 +101,6 @@ err:
                n--;
                gpio_free(s->gpio[n]);
        }
-       devm_kfree(&pdev->dev, s);
        return r;
 }
 
index 5c120189ec86d419866b7320c36f4d618dc5df64..4d4d25efc1e10a2b87e3c8ab993ae3ba6167a7dd 100644 (file)
@@ -132,7 +132,7 @@ int mdio_mux_init(struct device *dev,
        pb->mii_bus = parent_bus;
 
        ret_val = -ENODEV;
-       for_each_child_of_node(dev->of_node, child_bus_node) {
+       for_each_available_child_of_node(dev->of_node, child_bus_node) {
                u32 v;
 
                r = of_property_read_u32(child_bus_node, "reg", &v);
index 1c98321b56cc1547eb105b39758d2663e54de3ae..162464fe86bf7634fb9ac6c21ecd76e25beb10b6 100644 (file)
@@ -189,7 +189,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        if (sk_pppox(po)->sk_state & PPPOX_DEAD)
                goto tx_error;
 
-       rt = ip_route_output_ports(&init_net, &fl4, NULL,
+       rt = ip_route_output_ports(sock_net(sk), &fl4, NULL,
                                   opt->dst_addr.sin_addr.s_addr,
                                   opt->src_addr.sin_addr.s_addr,
                                   0, 0, IPPROTO_GRE,
@@ -468,7 +468,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
        po->chan.private = sk;
        po->chan.ops = &pptp_chan_ops;
 
-       rt = ip_route_output_ports(&init_net, &fl4, sk,
+       rt = ip_route_output_ports(sock_net(sk), &fl4, sk,
                                   opt->dst_addr.sin_addr.s_addr,
                                   opt->src_addr.sin_addr.s_addr,
                                   0, 0,
index 87707ab3943084821e1b7e5c5b9a201d51a944ba..341b65dbbcd324d9512f957fc7b663481a073aea 100644 (file)
@@ -795,16 +795,17 @@ static void team_port_leave(struct team *team, struct team_port *port)
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port,
+                                   gfp_t gfp)
 {
        struct netpoll *np;
        int err;
 
-       np = kzalloc(sizeof(*np), GFP_KERNEL);
+       np = kzalloc(sizeof(*np), gfp);
        if (!np)
                return -ENOMEM;
 
-       err = __netpoll_setup(np, port->dev);
+       err = __netpoll_setup(np, port->dev, gfp);
        if (err) {
                kfree(np);
                return err;
@@ -833,7 +834,8 @@ static struct netpoll_info *team_netpoll_info(struct team *team)
 }
 
 #else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port,
+                                   gfp_t gfp)
 {
        return 0;
 }
@@ -913,7 +915,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
        }
 
        if (team_netpoll_info(team)) {
-               err = team_port_enable_netpoll(team, port);
+               err = team_port_enable_netpoll(team, port, GFP_KERNEL);
                if (err) {
                        netdev_err(dev, "Failed to enable netpoll on device %s\n",
                                   portname);
@@ -1443,7 +1445,7 @@ static void team_netpoll_cleanup(struct net_device *dev)
 }
 
 static int team_netpoll_setup(struct net_device *dev,
-                             struct netpoll_info *npifo)
+                             struct netpoll_info *npifo, gfp_t gfp)
 {
        struct team *team = netdev_priv(dev);
        struct team_port *port;
@@ -1451,7 +1453,7 @@ static int team_netpoll_setup(struct net_device *dev,
 
        mutex_lock(&team->lock);
        list_for_each_entry(port, &team->port_list, list) {
-               err = team_port_enable_netpoll(team, port);
+               err = team_port_enable_netpoll(team, port, gfp);
                if (err) {
                        __team_netpoll_cleanup(team);
                        break;
index 926d4db5cb384f2de6df5ae871d0ec6171c6fe7d..3a16d4fdaa052817135c885b23cb28d90d872ec6 100644 (file)
@@ -187,7 +187,6 @@ static void __tun_detach(struct tun_struct *tun)
        netif_tx_lock_bh(tun->dev);
        netif_carrier_off(tun->dev);
        tun->tfile = NULL;
-       tun->socket.file = NULL;
        netif_tx_unlock_bh(tun->dev);
 
        /* Drop read queue */
index 64610048ce87c178770059b163395a285cb69e77..7d78669000d704d8448aea5e24a8a73c312badfc 100644 (file)
@@ -232,6 +232,7 @@ static int usbpn_open(struct net_device *dev)
                struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
 
                if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) {
+                       usb_free_urb(req);
                        usbpn_close(dev);
                        return -ENOMEM;
                }
index f4ce5957df326bb94131031fabdb1daf6dcabf42..4cd582a4f625d55d5edd8c2cd3952d5571074921 100644 (file)
@@ -1225,6 +1225,26 @@ static const struct usb_device_id cdc_devs[] = {
          .driver_info = (unsigned long) &wwan_info,
        },
 
+       /* Dell branded MBM devices like DW5550 */
+       { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+               | USB_DEVICE_ID_MATCH_VENDOR,
+         .idVendor = 0x413c,
+         .bInterfaceClass = USB_CLASS_COMM,
+         .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
+         .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+         .driver_info = (unsigned long) &wwan_info,
+       },
+
+       /* Toshiba branded MBM devices */
+       { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+               | USB_DEVICE_ID_MATCH_VENDOR,
+         .idVendor = 0x0930,
+         .bInterfaceClass = USB_CLASS_COMM,
+         .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
+         .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+         .driver_info = (unsigned long) &wwan_info,
+       },
+
        /* Generic CDC-NCM devices */
        { USB_INTERFACE_INFO(USB_CLASS_COMM,
                USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
index 2ea126a16d79add1f5271e8848942ffc2a755b37..328397c66730cae37a9c1cdc02cdb7dde523e2b3 100644 (file)
@@ -247,30 +247,12 @@ err:
  */
 static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
 {
-       int rv;
        struct qmi_wwan_state *info = (void *)&dev->data;
 
-       /* ZTE makes devices where the interface descriptors and endpoint
-        * configurations of two or more interfaces are identical, even
-        * though the functions are completely different.  If set, then
-        * driver_info->data is a bitmap of acceptable interface numbers
-        * allowing us to bind to one such interface without binding to
-        * all of them
-        */
-       if (dev->driver_info->data &&
-           !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) {
-               dev_info(&intf->dev, "not on our whitelist - ignored");
-               rv = -ENODEV;
-               goto err;
-       }
-
        /*  control and data is shared */
        info->control = intf;
        info->data = intf;
-       rv = qmi_wwan_register_subdriver(dev);
-
-err:
-       return rv;
+       return qmi_wwan_register_subdriver(dev);
 }
 
 static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -356,214 +338,64 @@ static const struct driver_info  qmi_wwan_shared = {
        .manage_power   = qmi_wwan_manage_power,
 };
 
-static const struct driver_info        qmi_wwan_force_int0 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(0), /* interface whitelist bitmap */
-};
-
-static const struct driver_info        qmi_wwan_force_int1 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(1), /* interface whitelist bitmap */
-};
-
-static const struct driver_info qmi_wwan_force_int2 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(2), /* interface whitelist bitmap */
-};
-
-static const struct driver_info        qmi_wwan_force_int3 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(3), /* interface whitelist bitmap */
-};
-
-static const struct driver_info        qmi_wwan_force_int4 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(4), /* interface whitelist bitmap */
-};
-
-/* Sierra Wireless provide equally useless interface descriptors
- * Devices in QMI mode can be switched between two different
- * configurations:
- *   a) USB interface #8 is QMI/wwan
- *   b) USB interfaces #8, #19 and #20 are QMI/wwan
- *
- * Both configurations provide a number of other interfaces (serial++),
- * some of which have the same endpoint configuration as we expect, so
- * a whitelist or blacklist is necessary.
- *
- * FIXME: The below whitelist should include BIT(20).  It does not
- * because I cannot get it to work...
- */
-static const struct driver_info        qmi_wwan_sierra = {
-       .description    = "Sierra Wireless wwan/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(8) | BIT(19), /* interface whitelist bitmap */
-};
-
 #define HUAWEI_VENDOR_ID       0x12D1
 
+/* map QMI/wwan function by a fixed interface number */
+#define QMI_FIXED_INTF(vend, prod, num) \
+       USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
+       .driver_info = (unsigned long)&qmi_wwan_shared
+
 /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
 #define QMI_GOBI1K_DEVICE(vend, prod) \
-       USB_DEVICE(vend, prod), \
-       .driver_info = (unsigned long)&qmi_wwan_force_int3
+       QMI_FIXED_INTF(vend, prod, 3)
 
-/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */
+/* Gobi 2000/3000 QMI/wwan interface number is 0 according to qcserial */
 #define QMI_GOBI_DEVICE(vend, prod) \
-       USB_DEVICE(vend, prod), \
-       .driver_info = (unsigned long)&qmi_wwan_force_int0
+       QMI_FIXED_INTF(vend, prod, 0)
 
 static const struct usb_device_id products[] = {
+       /* 1. CDC ECM like devices match on the control interface */
        {       /* Huawei E392, E398 and possibly others sharing both device id and more... */
-               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = HUAWEI_VENDOR_ID,
-               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-               .bInterfaceSubClass = 1,
-               .bInterfaceProtocol = 9, /* CDC Ethernet *control* interface */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 9),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
        {       /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
-               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = HUAWEI_VENDOR_ID,
-               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-               .bInterfaceSubClass = 1,
-               .bInterfaceProtocol = 57, /* CDC Ethernet *control* interface */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 57),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
-       {       /* Huawei E392, E398 and possibly others in "Windows mode"
-                * using a combined control and data interface without any CDC
-                * functional descriptors
-                */
-               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = HUAWEI_VENDOR_ID,
-               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-               .bInterfaceSubClass = 1,
-               .bInterfaceProtocol = 17,
+
+       /* 2. Combined interface devices matching on class+protocol */
+       {       /* Huawei E392, E398 and possibly others in "Windows mode" */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
                .driver_info        = (unsigned long)&qmi_wwan_shared,
        },
        {       /* Pantech UML290 */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x106c,
-               .idProduct          = 0x3718,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xf0,
-               .bInterfaceProtocol = 0xff,
+               USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
                .driver_info        = (unsigned long)&qmi_wwan_shared,
        },
-       {       /* ZTE MF820D */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0167,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE MF821D */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0326,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3520-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0055,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int1,
-       },
-       {       /* ZTE (Vodafone) K3565-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0063,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3570-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x1008,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3571-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x1010,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3765-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x2002,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K4505-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0104,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE MF60 */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x1402,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int2,
-       },
-       {       /* Sierra Wireless MC77xx in QMI mode */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x1199,
-               .idProduct          = 0x68a2,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_sierra,
+       {       /* Pantech UML290 - newer firmware */
+               USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff),
+               .driver_info        = (unsigned long)&qmi_wwan_shared,
        },
 
-       /* Gobi 1000 devices */
+       /* 3. Combined interface devices matching on interface number */
+       {QMI_FIXED_INTF(0x19d2, 0x0055, 1)},    /* ZTE (Vodafone) K3520-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x0063, 4)},    /* ZTE (Vodafone) K3565-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x0104, 4)},    /* ZTE (Vodafone) K4505-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x0167, 4)},    /* ZTE MF820D */
+       {QMI_FIXED_INTF(0x19d2, 0x0326, 4)},    /* ZTE MF821D */
+       {QMI_FIXED_INTF(0x19d2, 0x1008, 4)},    /* ZTE (Vodafone) K3570-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x1010, 4)},    /* ZTE (Vodafone) K3571-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x1018, 3)},    /* ZTE (Vodafone) K5006-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x1402, 2)},    /* ZTE MF60 */
+       {QMI_FIXED_INTF(0x19d2, 0x2002, 4)},    /* ZTE (Vodafone) K3765-Z */
+       {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
+       {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
+       {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
+       {QMI_FIXED_INTF(0x1199, 0x68a2, 19)},   /* Sierra Wireless MC7710 in QMI mode */
+       {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
+
+       /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
        {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)},    /* HP un2400 Gobi Modem Device */
        {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)},    /* HP un2430 Mobile Broadband Module */
@@ -579,7 +411,7 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)},    /* Generic Gobi Modem device */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)},    /* Generic Gobi Modem device */
 
-       /* Gobi 2000 and 3000 devices */
+       /* 5. Gobi 2000 and 3000 devices */
        {QMI_GOBI_DEVICE(0x413c, 0x8186)},      /* Dell Gobi 2000 Modem device (N0218, VU936) */
        {QMI_GOBI_DEVICE(0x05c6, 0x920b)},      /* Generic Gobi 2000 Modem device */
        {QMI_GOBI_DEVICE(0x05c6, 0x9225)},      /* Sony Gobi 2000 Modem device (N0279, VU730) */
@@ -589,6 +421,8 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI_DEVICE(0x05c6, 0x9265)},      /* Asus Gobi 2000 Modem device (VR305) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9235)},      /* Top Global Gobi 2000 Modem device (VR306) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9275)},      /* iRex Technologies Gobi 2000 Modem device (VR307) */
+       {QMI_GOBI_DEVICE(0x1199, 0x68a5)},      /* Sierra Wireless Modem */
+       {QMI_GOBI_DEVICE(0x1199, 0x68a9)},      /* Sierra Wireless Modem */
        {QMI_GOBI_DEVICE(0x1199, 0x9001)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x9002)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x9003)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
@@ -600,11 +434,14 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI_DEVICE(0x1199, 0x9009)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x900a)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x9011)},      /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
+       {QMI_FIXED_INTF(0x1199, 0x9011, 5)},    /* alternate interface number!? */
        {QMI_GOBI_DEVICE(0x16d8, 0x8002)},      /* CMDTech Gobi 2000 Modem device (VU922) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9205)},      /* Gobi 2000 Modem device */
        {QMI_GOBI_DEVICE(0x1199, 0x9013)},      /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
        {QMI_GOBI_DEVICE(0x1199, 0x9015)},      /* Sierra Wireless Gobi 3000 Modem device */
        {QMI_GOBI_DEVICE(0x1199, 0x9019)},      /* Sierra Wireless Gobi 3000 Modem device */
+       {QMI_GOBI_DEVICE(0x1199, 0x901b)},      /* Sierra Wireless MC7770 */
+
        { }                                     /* END */
 };
 MODULE_DEVICE_TABLE(usb, products);
index d75d1f56becff95ae9cf7b8f8dc08990d142d06c..7be49ea60b6d8f9353720d757f47c2c61b16fc60 100644 (file)
@@ -68,15 +68,8 @@ static       atomic_t iface_counter = ATOMIC_INIT(0);
  */
 #define SIERRA_NET_USBCTL_BUF_LEN      1024
 
-/* list of interface numbers - used for constructing interface lists */
-struct sierra_net_iface_info {
-       const u32 infolen;      /* number of interface numbers on list */
-       const u8  *ifaceinfo;   /* pointer to the array holding the numbers */
-};
-
 struct sierra_net_info_data {
        u16 rx_urb_size;
-       struct sierra_net_iface_info whitelist;
 };
 
 /* Private data structure */
@@ -637,21 +630,6 @@ static int sierra_net_change_mtu(struct net_device *net, int new_mtu)
        return usbnet_change_mtu(net, new_mtu);
 }
 
-static int is_whitelisted(const u8 ifnum,
-                       const struct sierra_net_iface_info *whitelist)
-{
-       if (whitelist) {
-               const u8 *list = whitelist->ifaceinfo;
-               int i;
-
-               for (i = 0; i < whitelist->infolen; i++) {
-                       if (list[i] == ifnum)
-                               return 1;
-               }
-       }
-       return 0;
-}
-
 static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
 {
        int result = 0;
@@ -706,11 +684,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
        dev_dbg(&dev->udev->dev, "%s", __func__);
 
        ifacenum = intf->cur_altsetting->desc.bInterfaceNumber;
-       /* We only accept certain interfaces */
-       if (!is_whitelisted(ifacenum, &data->whitelist)) {
-               dev_dbg(&dev->udev->dev, "Ignoring interface: %d", ifacenum);
-               return -ENODEV;
-       }
        numendpoints = intf->cur_altsetting->desc.bNumEndpoints;
        /* We have three endpoints, bulk in and out, and a status */
        if (numendpoints != 3) {
@@ -945,13 +918,8 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
        return NULL;
 }
 
-static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 };
 static const struct sierra_net_info_data sierra_net_info_data_direct_ip = {
        .rx_urb_size = 8 * 1024,
-       .whitelist = {
-               .infolen = ARRAY_SIZE(sierra_net_ifnum_list),
-               .ifaceinfo = sierra_net_ifnum_list
-       }
 };
 
 static const struct driver_info sierra_net_info_direct_ip = {
@@ -965,15 +933,19 @@ static const struct driver_info sierra_net_info_direct_ip = {
        .data = (unsigned long)&sierra_net_info_data_direct_ip,
 };
 
+#define DIRECT_IP_DEVICE(vend, prod) \
+       {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 7), \
+       .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \
+       {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 10), \
+       .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \
+       {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 11), \
+       .driver_info = (unsigned long)&sierra_net_info_direct_ip}
+
 static const struct usb_device_id products[] = {
-       {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
-       {USB_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
-       {USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
-       {USB_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
+       DIRECT_IP_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
+       DIRECT_IP_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */
+       DIRECT_IP_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */
+       DIRECT_IP_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */
 
        {}, /* last item */
 };
index 93e0cfb739b89b3f53964e6596c5b36e804b4a1b..ce9d4f2c9776e08d1b543f18de8cb7100fe43a86 100644 (file)
@@ -3019,6 +3019,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        netdev->watchdog_timeo = 5 * HZ;
 
        INIT_WORK(&adapter->work, vmxnet3_reset_work);
+       set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
 
        if (adapter->intr.type == VMXNET3_IT_MSIX) {
                int i;
@@ -3043,7 +3044,6 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                goto err_register;
        }
 
-       set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
        vmxnet3_check_link(adapter, false);
        atomic_inc(&devices_found);
        return 0;
index 9eb6479306d699dba13c63124a41a64f07b616ec..ef36cafd44b72138436ce3175dd5dfca7d184082 100644 (file)
@@ -774,14 +774,15 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
        }
        /* Global interrupt queue */
        writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1);
+
+       rc = -ENOMEM;
+
        priv->iqcfg = (__le32 *) pci_alloc_consistent(pdev,
                IRQ_RING_SIZE*sizeof(__le32), &priv->iqcfg_dma);
        if (!priv->iqcfg)
                goto err_free_irq_5;
        writel(priv->iqcfg_dma, ioaddr + IQCFG);
 
-       rc = -ENOMEM;
-
        /*
         * SCC 0-3 private rx/tx irq structures
         * IQRX/TXi needs to be set soon. Learned it the hard way...
index 283237f6f074a775b5ce82d6db1a64459168cfaf..def12b38cbf7002d27b83253c3be238e7e7f0802 100644 (file)
@@ -326,8 +326,10 @@ int i2400m_barker_db_init(const char *_options)
                unsigned barker;
 
                options_orig = kstrdup(_options, GFP_KERNEL);
-               if (options_orig == NULL)
+               if (options_orig == NULL) {
+                       result = -ENOMEM;
                        goto error_parse;
+               }
                options = options_orig;
 
                while ((token = strsep(&options, ",")) != NULL) {
index efc162e0b511c6d67ecdd4d011caa84c84708b8b..88b8d64c90f1b49a302deaca3af07788ee4b27c1 100644 (file)
@@ -342,7 +342,7 @@ static int at76_dfu_get_status(struct usb_device *udev,
        return ret;
 }
 
-static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
+static int at76_dfu_get_state(struct usb_device *udev, u8 *state)
 {
        int ret;
 
index 8c4c040a47b8cf69e75b4f022dafc3542f2ae908..2aab20ee9f387f8c89289ca409e6ead0fa83722c 100644 (file)
@@ -2056,9 +2056,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf)
 void
 ath5k_beacon_config(struct ath5k_hw *ah)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ah->block, flags);
+       spin_lock_bh(&ah->block);
        ah->bmisscount = 0;
        ah->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
 
@@ -2085,7 +2083,7 @@ ath5k_beacon_config(struct ath5k_hw *ah)
 
        ath5k_hw_set_imr(ah, ah->imask);
        mmiowb();
-       spin_unlock_irqrestore(&ah->block, flags);
+       spin_unlock_bh(&ah->block);
 }
 
 static void ath5k_tasklet_beacon(unsigned long data)
index 260e7dc7f7512af8442f957e2b4e6b2985355237..d56453e43d7e353e0890d3962e264448d7185771 100644 (file)
@@ -254,7 +254,6 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct ath5k_vif *avf = (void *)vif->drv_priv;
        struct ath5k_hw *ah = hw->priv;
        struct ath_common *common = ath5k_hw_common(ah);
-       unsigned long flags;
 
        mutex_lock(&ah->lock);
 
@@ -300,9 +299,9 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        }
 
        if (changes & BSS_CHANGED_BEACON) {
-               spin_lock_irqsave(&ah->block, flags);
+               spin_lock_bh(&ah->block);
                ath5k_beacon_update(hw, vif);
-               spin_unlock_irqrestore(&ah->block, flags);
+               spin_unlock_bh(&ah->block);
        }
 
        if (changes & BSS_CHANGED_BEACON_ENABLED)
index cfa91ab7acf8b1fd7c4b29fab82cb812f6423d5d..60b6a9daff7e21cde68fb6eda800e4ca065c62aa 100644 (file)
@@ -730,6 +730,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        case AR9300_DEVID_QCA955X:
        case AR9300_DEVID_AR9580:
        case AR9300_DEVID_AR9462:
+       case AR9485_DEVID_AR1111:
                break;
        default:
                if (common->bus_ops->ath_bus_type == ATH_USB)
index dd0c146d81dccd77d1d735db888884be6227c782..ce7332c64efb2c5b417cd40fec2428522186142a 100644 (file)
@@ -49,6 +49,7 @@
 #define AR9300_DEVID_AR9462    0x0034
 #define AR9300_DEVID_AR9330    0x0035
 #define AR9300_DEVID_QCA955X   0x0038
+#define AR9485_DEVID_AR1111    0x0037
 
 #define AR5416_AR9100_DEVID    0x000b
 
index 7990cd55599cd319a51537ed0ad1981b6edf9a4b..b42be910a83dc94845fa6be33370357b18416e2f 100644 (file)
@@ -773,15 +773,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_intrpend);
 
-void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+void ath9k_hw_kill_interrupts(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
 
-       if (!(ah->imask & ATH9K_INT_GLOBAL))
-               atomic_set(&ah->intr_ref_cnt, -1);
-       else
-               atomic_dec(&ah->intr_ref_cnt);
-
        ath_dbg(common, INTERRUPT, "disable IER\n");
        REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
        (void) REG_READ(ah, AR_IER);
@@ -793,6 +788,17 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
                (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
        }
 }
+EXPORT_SYMBOL(ath9k_hw_kill_interrupts);
+
+void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+{
+       if (!(ah->imask & ATH9K_INT_GLOBAL))
+               atomic_set(&ah->intr_ref_cnt, -1);
+       else
+               atomic_dec(&ah->intr_ref_cnt);
+
+       ath9k_hw_kill_interrupts(ah);
+}
 EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
 
 void ath9k_hw_enable_interrupts(struct ath_hw *ah)
index 0eba36dca6f8fe897dcbbdc56cd0318af46f4fba..4a745e68dd941d9351e4fe911b47d76ec288551d 100644 (file)
@@ -738,6 +738,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah);
 void ath9k_hw_set_interrupts(struct ath_hw *ah);
 void ath9k_hw_enable_interrupts(struct ath_hw *ah);
 void ath9k_hw_disable_interrupts(struct ath_hw *ah);
+void ath9k_hw_kill_interrupts(struct ath_hw *ah);
 
 void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
 
index 6049d8b82855a7542192b247657e58964fc9f496..a22df749b8db3d8641b4ef8cb78ad99b9e34adbb 100644 (file)
@@ -462,8 +462,10 @@ irqreturn_t ath_isr(int irq, void *dev)
        if (!ath9k_hw_intrpend(ah))
                return IRQ_NONE;
 
-       if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+       if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
+               ath9k_hw_kill_interrupts(ah);
                return IRQ_HANDLED;
+       }
 
        /*
         * Figure out the reason(s) for the interrupt.  Note
index 87b89d55e637758febf06629599ebe9e60478b85..a978984d78a53e93b5148ed54271deedf7b1d25c 100644 (file)
@@ -37,6 +37,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
        { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */
        { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E  AR9462 */
+       { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E  AR1111/AR9485 */
        { 0 }
 };
 
@@ -320,6 +321,7 @@ static int ath_pci_suspend(struct device *device)
         * Otherwise the chip never moved to full sleep,
         * when no interface is up.
         */
+       ath9k_stop_btcoex(sc);
        ath9k_hw_disable(sc->sc_ah);
        ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
 
index 12aca02228c22e9c8f5c62db20687c03f5992959..4480c0cc655f6f6ffca73774b2178e748936155e 100644 (file)
@@ -1044,7 +1044,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_hdr *hdr;
        int retval;
-       bool decrypt_error = false;
        struct ath_rx_status rs;
        enum ath9k_rx_qtype qtype;
        bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
@@ -1066,6 +1065,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
        tsf_lower = tsf & 0xffffffff;
 
        do {
+               bool decrypt_error = false;
                /* If handling rx interrupt and flush is in progress => exit */
                if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
                        break;
index b80352b308d54dabbc414c0d765122470f888c47..a140165dfee0515b70263cddf6e7902f4171de48 100644 (file)
@@ -2719,32 +2719,37 @@ static int b43_gpio_init(struct b43_wldev *dev)
        if (dev->dev->chip_id == 0x4301) {
                mask |= 0x0060;
                set |= 0x0060;
+       } else if (dev->dev->chip_id == 0x5354) {
+               /* Don't allow overtaking buttons GPIOs */
+               set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */
        }
-       if (dev->dev->chip_id == 0x5354)
-               set &= 0xff02;
+
        if (0 /* FIXME: conditional unknown */ ) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0100);
-               mask |= 0x0180;
-               set |= 0x0180;
+               /* BT Coexistance Input */
+               mask |= 0x0080;
+               set |= 0x0080;
+               /* BT Coexistance Out */
+               mask |= 0x0100;
+               set |= 0x0100;
        }
        if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) {
+               /* PA is controlled by gpio 9, let ucode handle it */
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
                mask |= 0x0200;
                set |= 0x0200;
        }
-       if (dev->dev->core_rev >= 2)
-               mask |= 0x0010; /* FIXME: This is redundant. */
 
        switch (dev->dev->bus_type) {
 #ifdef CONFIG_B43_BCMA
        case B43_BUS_BCMA:
                bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
                                (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
-                                       BCMA_CC_GPIOCTL) & mask) | set);
+                                       BCMA_CC_GPIOCTL) & ~mask) | set);
                break;
 #endif
 #ifdef CONFIG_B43_SSB
@@ -2753,7 +2758,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
                if (gpiodev)
                        ssb_write32(gpiodev, B43_GPIO_CONTROL,
                                    (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                                   & mask) | set);
+                                   & ~mask) | set);
                break;
 #endif
        }
index 9a4c63f927cb1817ee666cc070f14d1a810083c0..7ed7d7577024628d228a78f6e94433c810295bc2 100644 (file)
@@ -382,9 +382,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
 {
        struct brcms_c_info *wlc = wlc_cm->wlc;
        struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
-       const struct ieee80211_reg_rule *reg_rule;
        struct txpwr_limits txpwr;
-       int ret;
 
        brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
 
@@ -393,8 +391,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
        );
 
        /* set or restore gmode as required by regulatory */
-       ret = freq_reg_info(wlc->wiphy, ch->center_freq, 0, &reg_rule);
-       if (!ret && (reg_rule->flags & NL80211_RRF_NO_OFDM))
+       if (ch->flags & IEEE80211_CHAN_NO_OFDM)
                brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
        else
                brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
index 9e79d47e077f34e8b980dc6a8689c0735bba93bc..192ad5c1fcc8813805702d7b75c4ab89761cfd42 100644 (file)
@@ -121,7 +121,8 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {
                 IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(14, 2484,
                 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+                IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |
+                IEEE80211_CHAN_NO_OFDM)
 };
 
 static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
index 6fddd2785e6e1fc9e846cc7099c1bf6a6414804c..a82f46c10f5ec036ca07ae6bbfa139bb50ab8052 100644 (file)
@@ -707,11 +707,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
  */
 static bool rs_use_green(struct ieee80211_sta *sta)
 {
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
-               !(ctx->ht.non_gf_sta_present);
+       /*
+        * There's a bug somewhere in this code that causes the
+        * scaling to get stuck because GF+SGI can't be combined
+        * in SISO rates. Until we find that bug, disable GF, it
+        * has only limited benefit and we still interoperate with
+        * GF APs since we can always receive GF transmissions.
+        */
+       return false;
 }
 
 /**
index eb5de800ed9038109e9a80bfc9cd15863d3491e4..1c10b542ab231a45e5134a58ceb858c8ab82d331 100644 (file)
@@ -1254,6 +1254,7 @@ static int lbs_associate(struct lbs_private *priv,
                        netif_tx_wake_all_queues(priv->dev);
        }
 
+       kfree(cmd);
 done:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
        return ret;
index 76caebaa43977f722cbd707d666f1f014002792e..e970897f6ab52370a632a64a62cc10bb3c39a3c6 100644 (file)
@@ -1314,6 +1314,7 @@ static void if_sdio_remove(struct sdio_func *func)
                kfree(packet);
        }
 
+       kfree(card);
        lbs_deb_leave(LBS_DEB_SDIO);
 }
 
index 58048189bd24475f3ca18960822b6b18219e637c..fe1ea43c5149ef03e9ed0e2809695773fa2a576d 100644 (file)
@@ -571,7 +571,10 @@ static int lbs_thread(void *data)
                        netdev_info(dev, "Timeout submitting command 0x%04x\n",
                                    le16_to_cpu(cmdnode->cmdbuf->command));
                        lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
-                       if (priv->reset_card)
+
+                       /* Reset card, but only when it isn't in the process
+                        * of being shutdown anyway. */
+                       if (!dev->dismantle && priv->reset_card)
                                priv->reset_card(priv);
                }
                priv->cmd_timed_out = 0;
index 7f207b6e9552c3eb795c62dde4457d30a924fde9..effb044a8a9d5d8169be88744d561c62ac160165 100644 (file)
@@ -42,7 +42,7 @@ MODULE_FIRMWARE("isl3887usb");
  * whenever you add a new device.
  */
 
-static struct usb_device_id p54u_table[] __devinitdata = {
+static struct usb_device_id p54u_table[] = {
        /* Version 1 devices (pci chip + net2280) */
        {USB_DEVICE(0x0411, 0x0050)},   /* Buffalo WLI2-USB2-G54 */
        {USB_DEVICE(0x045e, 0x00c2)},   /* Microsoft MN-710 */
index 241162e8111d2584f0fca6f47819cf924cdf1157..7a4ae9ee1c63057b78d582fd3a94964a6fdea264 100644 (file)
@@ -1803,6 +1803,7 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
                                                struct cfg80211_pmksa *pmksa,
                                                int max_pmkids)
 {
+       struct ndis_80211_pmkid *new_pmkids;
        int i, err, newlen;
        unsigned int count;
 
@@ -1833,11 +1834,12 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
        /* add new pmkid */
        newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]);
 
-       pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
-       if (!pmkids) {
+       new_pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
+       if (!new_pmkids) {
                err = -ENOMEM;
                goto error;
        }
+       pmkids = new_pmkids;
 
        pmkids->length = cpu_to_le32(newlen);
        pmkids->bssid_info_count = cpu_to_le32(count + 1);
index 88455b1b9fe05b299aff2cc667d3d90e7822855a..cb8c2aca54e4dfdac4a7e223a8070f4e4543399e 100644 (file)
@@ -221,6 +221,67 @@ static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev,
        mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
+static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+       int i, count;
+
+       rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+       if (rt2x00_get_field32(reg, WLAN_EN))
+               return 0;
+
+       rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
+       rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
+       rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
+       rt2x00_set_field32(&reg, WLAN_EN, 1);
+       rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+
+       udelay(REGISTER_BUSY_DELAY);
+
+       count = 0;
+       do {
+               /*
+                * Check PLL_LD & XTAL_RDY.
+                */
+               for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+                       rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
+                       if (rt2x00_get_field32(reg, PLL_LD) &&
+                           rt2x00_get_field32(reg, XTAL_RDY))
+                               break;
+                       udelay(REGISTER_BUSY_DELAY);
+               }
+
+               if (i >= REGISTER_BUSY_COUNT) {
+
+                       if (count >= 10)
+                               return -EIO;
+
+                       rt2800_register_write(rt2x00dev, 0x58, 0x018);
+                       udelay(REGISTER_BUSY_DELAY);
+                       rt2800_register_write(rt2x00dev, 0x58, 0x418);
+                       udelay(REGISTER_BUSY_DELAY);
+                       rt2800_register_write(rt2x00dev, 0x58, 0x618);
+                       udelay(REGISTER_BUSY_DELAY);
+                       count++;
+               } else {
+                       count = 0;
+               }
+
+               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+               rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
+               rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
+               rt2x00_set_field32(&reg, WLAN_RESET, 1);
+               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               udelay(10);
+               rt2x00_set_field32(&reg, WLAN_RESET, 0);
+               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               udelay(10);
+               rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
+       } while (count != 0);
+
+       return 0;
+}
+
 void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 command, const u8 token,
                        const u8 arg0, const u8 arg1)
@@ -400,6 +461,13 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
 {
        unsigned int i;
        u32 reg;
+       int retval;
+
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               retval = rt2800_enable_wlan_rt3290(rt2x00dev);
+               if (retval)
+                       return -EBUSY;
+       }
 
        /*
         * If driver doesn't wake up firmware here,
index 235376e9cb04c0066032493f2d86b008d604c14c..98aa426a35649828e3c70c0f2bab0acf24e49381 100644 (file)
@@ -980,66 +980,6 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        return rt2800_validate_eeprom(rt2x00dev);
 }
 
-static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
-{
-       u32 reg;
-       int i, count;
-
-       rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-       if (rt2x00_get_field32(reg, WLAN_EN))
-               return 0;
-
-       rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
-       rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
-       rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
-       rt2x00_set_field32(&reg, WLAN_EN, 1);
-       rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-
-       udelay(REGISTER_BUSY_DELAY);
-
-       count = 0;
-       do {
-               /*
-                * Check PLL_LD & XTAL_RDY.
-                */
-               for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-                       rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
-                       if (rt2x00_get_field32(reg, PLL_LD) &&
-                           rt2x00_get_field32(reg, XTAL_RDY))
-                               break;
-                       udelay(REGISTER_BUSY_DELAY);
-               }
-
-               if (i >= REGISTER_BUSY_COUNT) {
-
-                       if (count >= 10)
-                               return -EIO;
-
-                       rt2800_register_write(rt2x00dev, 0x58, 0x018);
-                       udelay(REGISTER_BUSY_DELAY);
-                       rt2800_register_write(rt2x00dev, 0x58, 0x418);
-                       udelay(REGISTER_BUSY_DELAY);
-                       rt2800_register_write(rt2x00dev, 0x58, 0x618);
-                       udelay(REGISTER_BUSY_DELAY);
-                       count++;
-               } else {
-                       count = 0;
-               }
-
-               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-               rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
-               rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
-               rt2x00_set_field32(&reg, WLAN_RESET, 1);
-               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-               udelay(10);
-               rt2x00_set_field32(&reg, WLAN_RESET, 0);
-               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-               udelay(10);
-               rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
-       } while (count != 0);
-
-       return 0;
-}
 static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
        int retval;
@@ -1062,17 +1002,6 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        if (retval)
                return retval;
 
-       /*
-        * In probe phase call rt2800_enable_wlan_rt3290 to enable wlan
-        * clk for rt3290. That avoid the MCU fail in start phase.
-        */
-       if (rt2x00_rt(rt2x00dev, RT3290)) {
-               retval = rt2800_enable_wlan_rt3290(rt2x00dev);
-
-               if (retval)
-                       return retval;
-       }
-
        /*
         * This device has multiple filters for control frames
         * and has a separate filter for PS Poll frames.
index f32259686b45778b77630328e54e2c1298b18a84..3f7bc5cadf9a8a7a433688e8d480d76de3c1ab82 100644 (file)
@@ -2243,8 +2243,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 
 static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
 {
-       struct ieee80211_conf conf = { .flags = 0 };
-       struct rt2x00lib_conf libconf = { .conf = &conf };
+       struct rt2x00lib_conf libconf = { .conf = &rt2x00dev->hw->conf };
 
        rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
index 71a30b026089eddf6bf08658cf7e3f628992dbc5..533024095c43ad48871868d8522c6953399eb86a 100644 (file)
@@ -44,7 +44,7 @@ MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
 MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
 MODULE_LICENSE("GPL");
 
-static struct usb_device_id rtl8187_table[] __devinitdata = {
+static struct usb_device_id rtl8187_table[] = {
        /* Asus */
        {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187},
        /* Belkin */
index c181b94abc363b64a4a38c2e39625b7564dc2267..d4a1c9a043e12d3572faefe9a9fd11a1683cdd97 100644 (file)
@@ -363,6 +363,33 @@ struct device_node *of_get_next_child(const struct device_node *node,
 }
 EXPORT_SYMBOL(of_get_next_child);
 
+/**
+ *     of_get_next_available_child - Find the next available child node
+ *     @node:  parent node
+ *     @prev:  previous child of the parent node, or NULL to get first
+ *
+ *      This function is like of_get_next_child(), except that it
+ *      automatically skips any disabled nodes (i.e. status = "disabled").
+ */
+struct device_node *of_get_next_available_child(const struct device_node *node,
+       struct device_node *prev)
+{
+       struct device_node *next;
+
+       read_lock(&devtree_lock);
+       next = prev ? prev->sibling : node->child;
+       for (; next; next = next->sibling) {
+               if (!of_device_is_available(next))
+                       continue;
+               if (of_node_get(next))
+                       break;
+       }
+       of_node_put(prev);
+       read_unlock(&devtree_lock);
+       return next;
+}
+EXPORT_SYMBOL(of_get_next_available_child);
+
 /**
  *     of_find_node_by_path - Find a node matching a full OF path
  *     @path:  The full path to match
index fbf7b26c7c8a5119c527c00a15a35539b4aa3a2b..c5792d622dc4528ba572632d39c7c1f1d7ae438d 100644 (file)
@@ -266,8 +266,8 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        }
 
        if (!error)
-               dev_printk(KERN_INFO, &dev->dev,
-                               "power state changed by ACPI to D%d\n", state);
+               dev_info(&dev->dev, "power state changed by ACPI to %s\n",
+                        pci_power_name(state));
 
        return error;
 }
index 185be37033430adf53d8a390fd34a4c9dfd6e446..5270f1a99328d678396739781c7b0d4a87a586ef 100644 (file)
@@ -959,6 +959,13 @@ static int pci_pm_poweroff_noirq(struct device *dev)
        if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
                pci_prepare_to_sleep(pci_dev);
 
+       /*
+        * The reason for doing this here is the same as for the analogous code
+        * in pci_pm_suspend_noirq().
+        */
+       if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
+               pci_write_config_word(pci_dev, PCI_COMMAND, 0);
+
        return 0;
 }
 
index fb7f3bebdc69dadec1451773c596c9b901821265..dc5c126e398a0ac84fc13fa5f564d832ade0831e 100644 (file)
@@ -657,11 +657,7 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev)
        if (p != NULL)
                return ERR_PTR(-EBUSY);
 
-       p = create_pinctrl(dev);
-       if (IS_ERR(p))
-               return p;
-
-       return p;
+       return create_pinctrl(dev);
 }
 
 /**
@@ -738,11 +734,8 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
                        dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
                                name);
                        state = create_state(p, name);
-                       if (IS_ERR(state))
-                               return state;
-               } else {
-                       return ERR_PTR(-ENODEV);
-               }
+               } else
+                       state = ERR_PTR(-ENODEV);
        }
 
        return state;
index 75d3eff94296823e4959e63b6ec8c0531a129440..3674d877ed7c1db935b8e3831d60ea7b3e505c7f 100644 (file)
@@ -292,7 +292,7 @@ static int __init imx23_pinctrl_init(void)
 {
        return platform_driver_register(&imx23_pinctrl_driver);
 }
-arch_initcall(imx23_pinctrl_init);
+postcore_initcall(imx23_pinctrl_init);
 
 static void __exit imx23_pinctrl_exit(void)
 {
index b973026811a269978244a02177238d2f780726cf..0f5b2122b1bae358c8da2c1de90879a57a2a3911 100644 (file)
@@ -408,7 +408,7 @@ static int __init imx28_pinctrl_init(void)
 {
        return platform_driver_register(&imx28_pinctrl_driver);
 }
-arch_initcall(imx28_pinctrl_init);
+postcore_initcall(imx28_pinctrl_init);
 
 static void __exit imx28_pinctrl_exit(void)
 {
index 689b3c88dd2e723be68c5fd83a8bca99e9be78e8..9fd02162a3c21ec1ca810c163ab8c5143e1af41b 100644 (file)
@@ -974,7 +974,7 @@ static struct imx_pin_reg imx51_pin_regs[] = {
        IMX_PIN_REG(MX51_PAD_EIM_DA13, NO_PAD, 0x050, 0, 0x000, 0), /* MX51_PAD_EIM_DA13__EIM_DA13 */
        IMX_PIN_REG(MX51_PAD_EIM_DA14, NO_PAD, 0x054, 0, 0x000, 0), /* MX51_PAD_EIM_DA14__EIM_DA14 */
        IMX_PIN_REG(MX51_PAD_EIM_DA15, NO_PAD, 0x058, 0, 0x000, 0), /* MX51_PAD_EIM_DA15__EIM_DA15 */
-       IMX_PIN_REG(MX51_PAD_SD2_CMD, NO_PAD, 0x3b4, 2, 0x91c, 3), /* MX51_PAD_SD2_CMD__CSPI_MOSI */
+       IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 2, 0x91c, 3), /* MX51_PAD_SD2_CMD__CSPI_MOSI */
        IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 1, 0x9b0, 2), /* MX51_PAD_SD2_CMD__I2C1_SCL */
        IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 0, 0x000, 0), /* MX51_PAD_SD2_CMD__SD2_CMD */
        IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 2, 0x914, 3), /* MX51_PAD_SD2_CLK__CSPI_SCLK */
index 6f99769c6733a946ad3a67311e23b246ad0aae74..a39fb7a6fc5142b86a65630bd5a208c84b94cd9a 100644 (file)
@@ -505,6 +505,8 @@ static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
        DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1,
        DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2,
        DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 };
+static const unsigned kp_b_2_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+       DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_F4, DB8500_PIN_E3};
 static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
        DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
        DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
@@ -662,6 +664,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
        DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B),
+       DB8500_PIN_GROUP(kp_b_2, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(smcs1_b_1, NMK_GPIO_ALT_B),
@@ -751,7 +754,7 @@ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
 DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
 DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
        "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
-DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1");
 DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
 DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
 DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
@@ -766,7 +769,7 @@ DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1",
 DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
 DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
 DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1");
-DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1", "hsit_a_2");
+DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
 DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
 DB8500_FUNC_GROUPS(usb, "usb_a_1");
 DB8500_FUNC_GROUPS(trig, "trig_b_1");
index 53b0d49a7a1c817a7316fc25e57fff3a5c5341bb..3dde6537adb878d7986a96b2dba528d41cf77d1a 100644 (file)
@@ -1292,7 +1292,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
                                                NOMADIK_GPIO_TO_IRQ(pdata->first_gpio),
                                                0, &nmk_gpio_irq_simple_ops, nmk_chip);
        if (!nmk_chip->domain) {
-               pr_err("%s: Failed to create irqdomain\n", np->full_name);
+               dev_err(&dev->dev, "failed to create irqdomain\n");
                ret = -ENOSYS;
                goto out;
        }
@@ -1731,7 +1731,6 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
        for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
                if (!nmk_gpio_chips[i]) {
                        dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
-                       devm_kfree(&pdev->dev, npct);
                        return -EPROBE_DEFER;
                }
                npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
index 2aae8a8978e99b4224ef0f0baff84b5745e913dd..7fca6ce5952b94a0f398bd1bca35795e20ba62e0 100644 (file)
@@ -1217,7 +1217,6 @@ out_no_rsc_remap:
        iounmap(spmx->gpio_virtbase);
 out_no_gpio_remap:
        platform_set_drvdata(pdev, NULL);
-       devm_kfree(&pdev->dev, spmx);
        return ret;
 }
 
index a7ad8c112d91e21c9e0c930082a451d4b4921798..309f5b9a70ec74d4b5e1cca07b6e8e31836f53fa 100644 (file)
@@ -1121,10 +1121,8 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
        upmx->dev = &pdev->dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto out_no_resource;
-       }
+       if (!res)
+               return -ENOENT;
        upmx->phybase = res->start;
        upmx->physize = resource_size(res);
 
@@ -1165,8 +1163,6 @@ out_no_remap:
        platform_set_drvdata(pdev, NULL);
 out_no_memregion:
        release_mem_region(upmx->phybase, upmx->physize);
-out_no_resource:
-       devm_kfree(&pdev->dev, upmx);
        return ret;
 }
 
index 2a262f5c5c0ca5753671f74903a2e49d8e65d382..c86bae828c28258e8c98d4801742af679f277879 100644 (file)
@@ -289,6 +289,7 @@ config IDEAPAD_LAPTOP
        tristate "Lenovo IdeaPad Laptop Extras"
        depends on ACPI
        depends on RFKILL && INPUT
+       depends on SERIO_I8042
        select INPUT_SPARSEKMAP
        help
          This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
@@ -758,8 +759,11 @@ config SAMSUNG_Q10
 
 config APPLE_GMUX
        tristate "Apple Gmux Driver"
+       depends on ACPI
        depends on PNP
-       select BACKLIGHT_CLASS_DEVICE
+       depends on BACKLIGHT_CLASS_DEVICE
+       depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE
+       depends on ACPI_VIDEO=n || ACPI_VIDEO
        ---help---
          This driver provides support for the gmux device found on many
          Apple laptops, which controls the display mux for the hybrid
index 905fa01ac8df7abe86893964fd50c15a96b3b5d6..dfb1a92ce9497cb49e913fa23d8f8819300243e9 100644 (file)
@@ -2,6 +2,7 @@
  *  Gmux driver for Apple laptops
  *
  *  Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
+ *  Copyright (C) 2010-2012 Andreas Heider <andreas@meetr.de>
  *
  *  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
 #include <linux/pnp.h>
 #include <linux/apple_bl.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/vga_switcheroo.h>
 #include <acpi/video.h>
 #include <asm/io.h>
 
 struct apple_gmux_data {
        unsigned long iostart;
        unsigned long iolen;
+       bool indexed;
+       struct mutex index_lock;
 
        struct backlight_device *bdev;
+
+       /* switcheroo data */
+       acpi_handle dhandle;
+       int gpe;
+       enum vga_switcheroo_client_id resume_client_id;
+       enum vga_switcheroo_state power_state;
+       struct completion powerchange_done;
 };
 
+static struct apple_gmux_data *apple_gmux_data;
+
 /*
  * gmux port offsets. Many of these are not yet used, but may be in the
  * future, and it's useful to have them documented here anyhow.
@@ -45,6 +60,9 @@ struct apple_gmux_data {
 #define GMUX_PORT_DISCRETE_POWER       0x50
 #define GMUX_PORT_MAX_BRIGHTNESS       0x70
 #define GMUX_PORT_BRIGHTNESS           0x74
+#define GMUX_PORT_VALUE                        0xc2
+#define GMUX_PORT_READ                 0xd0
+#define GMUX_PORT_WRITE                        0xd4
 
 #define GMUX_MIN_IO_LEN                        (GMUX_PORT_BRIGHTNESS + 4)
 
@@ -59,22 +77,172 @@ struct apple_gmux_data {
 #define GMUX_BRIGHTNESS_MASK           0x00ffffff
 #define GMUX_MAX_BRIGHTNESS            GMUX_BRIGHTNESS_MASK
 
-static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
 {
        return inb(gmux_data->iostart + port);
 }
 
-static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
+static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
                               u8 val)
 {
        outb(val, gmux_data->iostart + port);
 }
 
-static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
 {
        return inl(gmux_data->iostart + port);
 }
 
+static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
+                            u32 val)
+{
+       int i;
+       u8 tmpval;
+
+       for (i = 0; i < 4; i++) {
+               tmpval = (val >> (i * 8)) & 0xff;
+               outb(tmpval, port + i);
+       }
+}
+
+static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
+{
+       int i = 200;
+       u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+
+       while (i && (gwr & 0x01)) {
+               inb(gmux_data->iostart + GMUX_PORT_READ);
+               gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+               udelay(100);
+               i--;
+       }
+
+       return !!i;
+}
+
+static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
+{
+       int i = 200;
+       u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+
+       while (i && !(gwr & 0x01)) {
+               gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+               udelay(100);
+               i--;
+       }
+
+       if (gwr & 0x01)
+               inb(gmux_data->iostart + GMUX_PORT_READ);
+
+       return !!i;
+}
+
+static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
+{
+       u8 val;
+
+       mutex_lock(&gmux_data->index_lock);
+       outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
+       gmux_index_wait_ready(gmux_data);
+       val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
+       mutex_unlock(&gmux_data->index_lock);
+
+       return val;
+}
+
+static void gmux_index_write8(struct apple_gmux_data *gmux_data, int port,
+                             u8 val)
+{
+       mutex_lock(&gmux_data->index_lock);
+       outb(val, gmux_data->iostart + GMUX_PORT_VALUE);
+       gmux_index_wait_ready(gmux_data);
+       outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
+       gmux_index_wait_complete(gmux_data);
+       mutex_unlock(&gmux_data->index_lock);
+}
+
+static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
+{
+       u32 val;
+
+       mutex_lock(&gmux_data->index_lock);
+       outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
+       gmux_index_wait_ready(gmux_data);
+       val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
+       mutex_unlock(&gmux_data->index_lock);
+
+       return val;
+}
+
+static void gmux_index_write32(struct apple_gmux_data *gmux_data, int port,
+                              u32 val)
+{
+       int i;
+       u8 tmpval;
+
+       mutex_lock(&gmux_data->index_lock);
+
+       for (i = 0; i < 4; i++) {
+               tmpval = (val >> (i * 8)) & 0xff;
+               outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i);
+       }
+
+       gmux_index_wait_ready(gmux_data);
+       outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
+       gmux_index_wait_complete(gmux_data);
+       mutex_unlock(&gmux_data->index_lock);
+}
+
+static u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+{
+       if (gmux_data->indexed)
+               return gmux_index_read8(gmux_data, port);
+       else
+               return gmux_pio_read8(gmux_data, port);
+}
+
+static void gmux_write8(struct apple_gmux_data *gmux_data, int port, u8 val)
+{
+       if (gmux_data->indexed)
+               gmux_index_write8(gmux_data, port, val);
+       else
+               gmux_pio_write8(gmux_data, port, val);
+}
+
+static u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+{
+       if (gmux_data->indexed)
+               return gmux_index_read32(gmux_data, port);
+       else
+               return gmux_pio_read32(gmux_data, port);
+}
+
+static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
+                            u32 val)
+{
+       if (gmux_data->indexed)
+               gmux_index_write32(gmux_data, port, val);
+       else
+               gmux_pio_write32(gmux_data, port, val);
+}
+
+static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
+{
+       u16 val;
+
+       outb(0xaa, gmux_data->iostart + 0xcc);
+       outb(0x55, gmux_data->iostart + 0xcd);
+       outb(0x00, gmux_data->iostart + 0xce);
+
+       val = inb(gmux_data->iostart + 0xcc) |
+               (inb(gmux_data->iostart + 0xcd) << 8);
+
+       if (val == 0x55aa)
+               return true;
+
+       return false;
+}
+
 static int gmux_get_brightness(struct backlight_device *bd)
 {
        struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -90,16 +258,7 @@ static int gmux_update_status(struct backlight_device *bd)
        if (bd->props.state & BL_CORE_SUSPENDED)
                return 0;
 
-       /*
-        * Older gmux versions require writing out lower bytes first then
-        * setting the upper byte to 0 to flush the values. Newer versions
-        * accept a single u32 write, but the old method also works, so we
-        * just use the old method for all gmux versions.
-        */
-       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
-       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
-       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
-       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
+       gmux_write32(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
 
        return 0;
 }
@@ -110,6 +269,146 @@ static const struct backlight_ops gmux_bl_ops = {
        .update_status = gmux_update_status,
 };
 
+static int gmux_switchto(enum vga_switcheroo_client_id id)
+{
+       if (id == VGA_SWITCHEROO_IGD) {
+               gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+               gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
+               gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
+       } else {
+               gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+               gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
+               gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
+       }
+
+       return 0;
+}
+
+static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data,
+                                  enum vga_switcheroo_state state)
+{
+       INIT_COMPLETION(gmux_data->powerchange_done);
+
+       if (state == VGA_SWITCHEROO_ON) {
+               gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+               gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 3);
+               pr_debug("Discrete card powered up\n");
+       } else {
+               gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1);
+               gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 0);
+               pr_debug("Discrete card powered down\n");
+       }
+
+       gmux_data->power_state = state;
+
+       if (gmux_data->gpe >= 0 &&
+           !wait_for_completion_interruptible_timeout(&gmux_data->powerchange_done,
+                                                      msecs_to_jiffies(200)))
+               pr_warn("Timeout waiting for gmux switch to complete\n");
+
+       return 0;
+}
+
+static int gmux_set_power_state(enum vga_switcheroo_client_id id,
+                               enum vga_switcheroo_state state)
+{
+       if (id == VGA_SWITCHEROO_IGD)
+               return 0;
+
+       return gmux_set_discrete_state(apple_gmux_data, state);
+}
+
+static int gmux_get_client_id(struct pci_dev *pdev)
+{
+       /*
+        * Early Macbook Pros with switchable graphics use nvidia
+        * integrated graphics. Hardcode that the 9400M is integrated.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+               return VGA_SWITCHEROO_IGD;
+       else if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
+                pdev->device == 0x0863)
+               return VGA_SWITCHEROO_IGD;
+       else
+               return VGA_SWITCHEROO_DIS;
+}
+
+static enum vga_switcheroo_client_id
+gmux_active_client(struct apple_gmux_data *gmux_data)
+{
+       if (gmux_read8(gmux_data, GMUX_PORT_SWITCH_DISPLAY) == 2)
+               return VGA_SWITCHEROO_IGD;
+
+       return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler gmux_handler = {
+       .switchto = gmux_switchto,
+       .power_state = gmux_set_power_state,
+       .get_client_id = gmux_get_client_id,
+};
+
+static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
+{
+       gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+                   GMUX_INTERRUPT_DISABLE);
+}
+
+static inline void gmux_enable_interrupts(struct apple_gmux_data *gmux_data)
+{
+       gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_ENABLE,
+                   GMUX_INTERRUPT_ENABLE);
+}
+
+static inline u8 gmux_interrupt_get_status(struct apple_gmux_data *gmux_data)
+{
+       return gmux_read8(gmux_data, GMUX_PORT_INTERRUPT_STATUS);
+}
+
+static void gmux_clear_interrupts(struct apple_gmux_data *gmux_data)
+{
+       u8 status;
+
+       /* to clear interrupts write back current status */
+       status = gmux_interrupt_get_status(gmux_data);
+       gmux_write8(gmux_data, GMUX_PORT_INTERRUPT_STATUS, status);
+}
+
+static void gmux_notify_handler(acpi_handle device, u32 value, void *context)
+{
+       u8 status;
+       struct pnp_dev *pnp = (struct pnp_dev *)context;
+       struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+
+       status = gmux_interrupt_get_status(gmux_data);
+       gmux_disable_interrupts(gmux_data);
+       pr_debug("Notify handler called: status %d\n", status);
+
+       gmux_clear_interrupts(gmux_data);
+       gmux_enable_interrupts(gmux_data);
+
+       if (status & GMUX_INTERRUPT_STATUS_POWER)
+               complete(&gmux_data->powerchange_done);
+}
+
+static int gmux_suspend(struct pnp_dev *pnp, pm_message_t state)
+{
+       struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+       gmux_data->resume_client_id = gmux_active_client(gmux_data);
+       gmux_disable_interrupts(gmux_data);
+       return 0;
+}
+
+static int gmux_resume(struct pnp_dev *pnp)
+{
+       struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+       gmux_enable_interrupts(gmux_data);
+       gmux_switchto(gmux_data->resume_client_id);
+       if (gmux_data->power_state == VGA_SWITCHEROO_OFF)
+               gmux_set_discrete_state(gmux_data, gmux_data->power_state);
+       return 0;
+}
+
 static int __devinit gmux_probe(struct pnp_dev *pnp,
                                const struct pnp_device_id *id)
 {
@@ -119,6 +418,11 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
        struct backlight_device *bdev;
        u8 ver_major, ver_minor, ver_release;
        int ret = -ENXIO;
+       acpi_status status;
+       unsigned long long gpe;
+
+       if (apple_gmux_data)
+               return -EBUSY;
 
        gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
        if (!gmux_data)
@@ -147,22 +451,29 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
        }
 
        /*
-        * On some machines the gmux is in ACPI even thought the machine
-        * doesn't really have a gmux. Check for invalid version information
-        * to detect this.
+        * Invalid version information may indicate either that the gmux
+        * device isn't present or that it's a new one that uses indexed
+        * io
         */
+
        ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
        ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
        ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
        if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
-               pr_info("gmux device not present\n");
-               ret = -ENODEV;
-               goto err_release;
+               if (gmux_is_indexed(gmux_data)) {
+                       mutex_init(&gmux_data->index_lock);
+                       gmux_data->indexed = true;
+               } else {
+                       pr_info("gmux device not present\n");
+                       ret = -ENODEV;
+                       goto err_release;
+               }
+               pr_info("Found indexed gmux\n");
+       } else {
+               pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
+                       ver_release);
        }
 
-       pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
-               ver_release);
-
        memset(&props, 0, sizeof(props));
        props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
@@ -194,13 +505,67 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
         * Disable the other backlight choices.
         */
        acpi_video_dmi_promote_vendor();
-#ifdef CONFIG_ACPI_VIDEO
+#if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE)
        acpi_video_unregister();
 #endif
        apple_bl_unregister();
 
+       gmux_data->power_state = VGA_SWITCHEROO_ON;
+
+       gmux_data->dhandle = DEVICE_ACPI_HANDLE(&pnp->dev);
+       if (!gmux_data->dhandle) {
+               pr_err("Cannot find acpi handle for pnp device %s\n",
+                      dev_name(&pnp->dev));
+               ret = -ENODEV;
+               goto err_notify;
+       }
+
+       status = acpi_evaluate_integer(gmux_data->dhandle, "GMGP", NULL, &gpe);
+       if (ACPI_SUCCESS(status)) {
+               gmux_data->gpe = (int)gpe;
+
+               status = acpi_install_notify_handler(gmux_data->dhandle,
+                                                    ACPI_DEVICE_NOTIFY,
+                                                    &gmux_notify_handler, pnp);
+               if (ACPI_FAILURE(status)) {
+                       pr_err("Install notify handler failed: %s\n",
+                              acpi_format_exception(status));
+                       ret = -ENODEV;
+                       goto err_notify;
+               }
+
+               status = acpi_enable_gpe(NULL, gmux_data->gpe);
+               if (ACPI_FAILURE(status)) {
+                       pr_err("Cannot enable gpe: %s\n",
+                              acpi_format_exception(status));
+                       goto err_enable_gpe;
+               }
+       } else {
+               pr_warn("No GPE found for gmux\n");
+               gmux_data->gpe = -1;
+       }
+
+       if (vga_switcheroo_register_handler(&gmux_handler)) {
+               ret = -ENODEV;
+               goto err_register_handler;
+       }
+
+       init_completion(&gmux_data->powerchange_done);
+       apple_gmux_data = gmux_data;
+       gmux_enable_interrupts(gmux_data);
+
        return 0;
 
+err_register_handler:
+       if (gmux_data->gpe >= 0)
+               acpi_disable_gpe(NULL, gmux_data->gpe);
+err_enable_gpe:
+       if (gmux_data->gpe >= 0)
+               acpi_remove_notify_handler(gmux_data->dhandle,
+                                          ACPI_DEVICE_NOTIFY,
+                                          &gmux_notify_handler);
+err_notify:
+       backlight_device_unregister(bdev);
 err_release:
        release_region(gmux_data->iostart, gmux_data->iolen);
 err_free:
@@ -212,12 +577,23 @@ static void __devexit gmux_remove(struct pnp_dev *pnp)
 {
        struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
 
+       vga_switcheroo_unregister_handler();
+       gmux_disable_interrupts(gmux_data);
+       if (gmux_data->gpe >= 0) {
+               acpi_disable_gpe(NULL, gmux_data->gpe);
+               acpi_remove_notify_handler(gmux_data->dhandle,
+                                          ACPI_DEVICE_NOTIFY,
+                                          &gmux_notify_handler);
+       }
+
        backlight_device_unregister(gmux_data->bdev);
+
        release_region(gmux_data->iostart, gmux_data->iolen);
+       apple_gmux_data = NULL;
        kfree(gmux_data);
 
        acpi_video_dmi_demote_vendor();
-#ifdef CONFIG_ACPI_VIDEO
+#if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE)
        acpi_video_register();
 #endif
        apple_bl_register();
@@ -233,6 +609,8 @@ static struct pnp_driver gmux_pnp_driver = {
        .probe          = gmux_probe,
        .remove         = __devexit_p(gmux_remove),
        .id_table       = gmux_device_ids,
+       .suspend        = gmux_suspend,
+       .resume         = gmux_resume
 };
 
 static int __init apple_gmux_init(void)
index c7a36f6b058048eb092717eff06a9e413a6a2546..2eb9fe8e8efd038c7bb1d25ad4fbde2961ca8e1a 100644 (file)
@@ -101,6 +101,7 @@ MODULE_LICENSE("GPL");
 #define ASUS_WMI_DEVID_WIRELESS_LED    0x00010002
 #define ASUS_WMI_DEVID_CWAP            0x00010003
 #define ASUS_WMI_DEVID_WLAN            0x00010011
+#define ASUS_WMI_DEVID_WLAN_LED                0x00010012
 #define ASUS_WMI_DEVID_BLUETOOTH       0x00010013
 #define ASUS_WMI_DEVID_GPS             0x00010015
 #define ASUS_WMI_DEVID_WIMAX           0x00010017
@@ -731,8 +732,21 @@ static int asus_rfkill_set(void *data, bool blocked)
 {
        struct asus_rfkill *priv = data;
        u32 ctrl_param = !blocked;
+       u32 dev_id = priv->dev_id;
 
-       return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL);
+       /*
+        * If the user bit is set, BIOS can't set and record the wlan status,
+        * it will report the value read from id ASUS_WMI_DEVID_WLAN_LED
+        * while we query the wlan status through WMI(ASUS_WMI_DEVID_WLAN).
+        * So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED
+        * while setting the wlan status through WMI.
+        * This is also the behavior that windows app will do.
+        */
+       if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
+            priv->asus->driver->wlan_ctrl_by_user)
+               dev_id = ASUS_WMI_DEVID_WLAN_LED;
+
+       return asus_wmi_set_devstate(dev_id, ctrl_param, NULL);
 }
 
 static void asus_rfkill_query(struct rfkill *rfkill, void *data)
@@ -1653,6 +1667,7 @@ static int asus_wmi_add(struct platform_device *pdev)
        struct asus_wmi *asus;
        acpi_status status;
        int err;
+       u32 result;
 
        asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL);
        if (!asus)
@@ -1711,6 +1726,10 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_debugfs;
 
+       asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);
+       if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
+               asus->driver->wlan_ctrl_by_user = 1;
+
        return 0;
 
 fail_debugfs:
index 9c1da8b81bea50f9007eac48f82da8f0bb29a73d..4c9bd38bb0a26141c27ceca8749358cf60da1cfb 100644 (file)
@@ -46,6 +46,7 @@ struct quirk_entry {
 struct asus_wmi_driver {
        int                     brightness;
        int                     panel_power;
+       int                     wlan_ctrl_by_user;
 
        const char              *name;
        struct module           *owner;
index 2ca7dd1ab3e452e49eb0c25561274cea435acbcf..c87ff16873f9753ef589111763d743bc09ed1409 100644 (file)
@@ -350,6 +350,7 @@ static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
        inputdev->close = cmpc_accel_close_v4;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cmpc_accel_suspend_v4(struct device *dev)
 {
        struct input_dev *inputdev;
@@ -384,6 +385,7 @@ static int cmpc_accel_resume_v4(struct device *dev)
 
        return 0;
 }
+#endif
 
 static int cmpc_accel_add_v4(struct acpi_device *acpi)
 {
@@ -723,8 +725,10 @@ static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
        struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
 
        if (event == 0x81) {
-               if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val)))
+               if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val))) {
                        input_report_switch(inputdev, SW_TABLET_MODE, !val);
+                       input_sync(inputdev);
+               }
        }
 }
 
@@ -737,8 +741,10 @@ static void cmpc_tablet_idev_init(struct input_dev *inputdev)
        set_bit(SW_TABLET_MODE, inputdev->swbit);
 
        acpi = to_acpi_device(inputdev->dev.parent);
-       if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
+       if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val))) {
                input_report_switch(inputdev, SW_TABLET_MODE, !val);
+               input_sync(inputdev);
+       }
 }
 
 static int cmpc_tablet_add(struct acpi_device *acpi)
@@ -752,15 +758,19 @@ static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
        return cmpc_remove_acpi_notify_device(acpi);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cmpc_tablet_resume(struct device *dev)
 {
        struct input_dev *inputdev = dev_get_drvdata(dev);
 
        unsigned long long val = 0;
-       if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val)))
+       if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val))) {
                input_report_switch(inputdev, SW_TABLET_MODE, !val);
+               input_sync(inputdev);
+       }
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
 
index 4e96e8c0b60f83dfb04e835fe0ec4ed40fddb6a6..927c33af67ecc994b46ae2802a25f1cd5bfac5ed 100644 (file)
@@ -211,7 +211,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                .ident = "Dell Inspiron 5420",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5420"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5420"),
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
@@ -220,7 +220,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                .ident = "Dell Inspiron 5520",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5520"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5520"),
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
@@ -229,7 +229,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                .ident = "Dell Inspiron 5720",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5720"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5720"),
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
@@ -238,7 +238,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                .ident = "Dell Inspiron 7420",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7420"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7420"),
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
@@ -247,7 +247,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                .ident = "Dell Inspiron 7520",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7520"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
@@ -256,7 +256,7 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                .ident = "Dell Inspiron 7720",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7720"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7720"),
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
index d2e41735a47b2d6178ef290211e0d13373ece570..7acae3f85f3b180cfe57865e08bb4fbf08bde40d 100644 (file)
@@ -440,11 +440,13 @@ static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_fujitsu_resume(struct device *dev)
 {
        fujitsu_reset();
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
 
index d9ab6f64dcec0185148075dca8f4ef8fda1319bf..777c7e3dda51ccb73dd6939717d95904ae5753cc 100644 (file)
@@ -305,10 +305,12 @@ static int hdaps_probe(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int hdaps_resume(struct device *dev)
 {
        return hdaps_device_init();
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(hdaps_pm, NULL, hdaps_resume);
 
index f4d91154ad67cca5d260cc681c5f7464dea0e87c..6b9af989632b72a9f2c0b1641a5fdd5600844de0 100644 (file)
@@ -352,7 +352,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int lis3lv02d_suspend(struct device *dev)
 {
        /* make sure the device is off when we suspend */
index 17f6dfd8dbfb093a332d7d9d9ebd572df9b850e7..dae7abe1d711487ce3499232f809f28bc3983232 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/fb.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/i8042.h>
 
 #define IDEAPAD_RFKILL_DEV_NUM (3)
 
@@ -63,8 +64,11 @@ enum {
        VPCCMD_R_3G,
        VPCCMD_W_3G,
        VPCCMD_R_ODD, /* 0x21 */
-       VPCCMD_R_RF = 0x23,
+       VPCCMD_W_FAN,
+       VPCCMD_R_RF,
        VPCCMD_W_RF,
+       VPCCMD_R_FAN = 0x2B,
+       VPCCMD_R_SPECIAL_BUTTONS = 0x31,
        VPCCMD_W_BL_POWER = 0x33,
 };
 
@@ -356,14 +360,46 @@ static ssize_t store_ideapad_cam(struct device *dev,
                return -EINVAL;
        ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state);
        if (ret < 0)
-               return ret;
+               return -EIO;
        return count;
 }
 
 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
 
+static ssize_t show_ideapad_fan(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       unsigned long result;
+
+       if (read_ec_data(ideapad_handle, VPCCMD_R_FAN, &result))
+               return sprintf(buf, "-1\n");
+       return sprintf(buf, "%lu\n", result);
+}
+
+static ssize_t store_ideapad_fan(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       int ret, state;
+
+       if (!count)
+               return 0;
+       if (sscanf(buf, "%i", &state) != 1)
+               return -EINVAL;
+       if (state < 0 || state > 4 || state == 3)
+               return -EINVAL;
+       ret = write_ec_cmd(ideapad_handle, VPCCMD_W_FAN, state);
+       if (ret < 0)
+               return -EIO;
+       return count;
+}
+
+static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
+
 static struct attribute *ideapad_attributes[] = {
        &dev_attr_camera_power.attr,
+       &dev_attr_fan_mode.attr,
        NULL
 };
 
@@ -377,7 +413,10 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
 
        if (attr == &dev_attr_camera_power.attr)
                supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
-       else
+       else if (attr == &dev_attr_fan_mode.attr) {
+               unsigned long value;
+               supported = !read_ec_data(ideapad_handle, VPCCMD_R_FAN, &value);
+       } else
                supported = true;
 
        return supported ? attr->mode : 0;
@@ -518,9 +557,15 @@ static void ideapad_platform_exit(struct ideapad_private *priv)
  */
 static const struct key_entry ideapad_keymap[] = {
        { KE_KEY, 6,  { KEY_SWITCHVIDEOMODE } },
+       { KE_KEY, 7,  { KEY_CAMERA } },
+       { KE_KEY, 11, { KEY_F16 } },
        { KE_KEY, 13, { KEY_WLAN } },
        { KE_KEY, 16, { KEY_PROG1 } },
        { KE_KEY, 17, { KEY_PROG2 } },
+       { KE_KEY, 64, { KEY_PROG3 } },
+       { KE_KEY, 65, { KEY_PROG4 } },
+       { KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
+       { KE_KEY, 67, { KEY_TOUCHPAD_ON } },
        { KE_END, 0 },
 };
 
@@ -587,6 +632,28 @@ static void ideapad_input_novokey(struct ideapad_private *priv)
                ideapad_input_report(priv, 16);
 }
 
+static void ideapad_check_special_buttons(struct ideapad_private *priv)
+{
+       unsigned long bit, value;
+
+       read_ec_data(ideapad_handle, VPCCMD_R_SPECIAL_BUTTONS, &value);
+
+       for (bit = 0; bit < 16; bit++) {
+               if (test_bit(bit, &value)) {
+                       switch (bit) {
+                       case 6:
+                               /* Thermal Management button */
+                               ideapad_input_report(priv, 65);
+                               break;
+                       case 1:
+                               /* OneKey Theater button */
+                               ideapad_input_report(priv, 64);
+                               break;
+                       }
+               }
+       }
+}
+
 /*
  * backlight
  */
@@ -691,6 +758,24 @@ static const struct acpi_device_id ideapad_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
 
+static void ideapad_sync_touchpad_state(struct acpi_device *adevice)
+{
+       struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+       unsigned long value;
+
+       /* Without reading from EC touchpad LED doesn't switch state */
+       if (!read_ec_data(adevice->handle, VPCCMD_R_TOUCHPAD, &value)) {
+               /* Some IdeaPads don't really turn off touchpad - they only
+                * switch the LED state. We (de)activate KBC AUX port to turn
+                * touchpad off and on. We send KEY_TOUCHPAD_OFF and
+                * KEY_TOUCHPAD_ON to not to get out of sync with LED */
+               unsigned char param;
+               i8042_command(&param, value ? I8042_CMD_AUX_ENABLE :
+                             I8042_CMD_AUX_DISABLE);
+               ideapad_input_report(priv, value ? 67 : 66);
+       }
+}
+
 static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
 {
        int ret, i;
@@ -727,6 +812,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
                        priv->rfk[i] = NULL;
        }
        ideapad_sync_rfk_state(priv);
+       ideapad_sync_touchpad_state(adevice);
 
        if (!acpi_video_backlight_support()) {
                ret = ideapad_backlight_init(priv);
@@ -785,9 +871,14 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
                                ideapad_sync_rfk_state(priv);
                                break;
                        case 13:
+                       case 11:
+                       case 7:
                        case 6:
                                ideapad_input_report(priv, vpc_bit);
                                break;
+                       case 5:
+                               ideapad_sync_touchpad_state(adevice);
+                               break;
                        case 4:
                                ideapad_backlight_notify_brightness(priv);
                                break;
@@ -797,6 +888,9 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
                        case 2:
                                ideapad_backlight_notify_power(priv);
                                break;
+                       case 0:
+                               ideapad_check_special_buttons(priv);
+                               break;
                        default:
                                pr_info("Unknown event: %lu\n", vpc_bit);
                        }
@@ -804,6 +898,15 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
        }
 }
 
+static int ideapad_acpi_resume(struct device *device)
+{
+       ideapad_sync_rfk_state(ideapad_priv);
+       ideapad_sync_touchpad_state(to_acpi_device(device));
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
+
 static struct acpi_driver ideapad_acpi_driver = {
        .name = "ideapad_acpi",
        .class = "IdeaPad",
@@ -811,6 +914,7 @@ static struct acpi_driver ideapad_acpi_driver = {
        .ops.add = ideapad_acpi_add,
        .ops.remove = ideapad_acpi_remove,
        .ops.notify = ideapad_acpi_notify,
+       .drv.pm = &ideapad_pm,
        .owner = THIS_MODULE,
 };
 
index f64441844317f513c6ec8db521fb0bad37afbda8..2111dbb7e1e380263b6118218b619089298a39a2 100644 (file)
@@ -85,7 +85,9 @@
 #define MSI_STANDARD_EC_TOUCHPAD_ADDRESS       0xe4
 #define MSI_STANDARD_EC_TOUCHPAD_MASK          (1 << 4)
 
+#ifdef CONFIG_PM_SLEEP
 static int msi_laptop_resume(struct device *device);
+#endif
 static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
 
 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -753,6 +755,7 @@ err_bluetooth:
        return retval;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int msi_laptop_resume(struct device *device)
 {
        u8 data;
@@ -773,6 +776,7 @@ static int msi_laptop_resume(struct device *device)
 
        return 0;
 }
+#endif
 
 static int __init msi_laptop_input_setup(void)
 {
index 24480074bcf047c40b219dcf5b055ce829d865d7..8e8caa767d6aec521e65cd42475e3b2950c32907 100644 (file)
@@ -188,7 +188,9 @@ static const struct acpi_device_id pcc_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_pcc_hotkey_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
 
 static struct acpi_driver acpi_pcc_driver = {
@@ -540,6 +542,7 @@ static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
 
 /* kernel module interface */
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_pcc_hotkey_resume(struct device *dev)
 {
        struct pcc_acpi *pcc;
@@ -556,6 +559,7 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
 
        return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
 }
+#endif
 
 static int acpi_pcc_hotkey_add(struct acpi_device *device)
 {
index 9363969ad07adf65cefe1a6aa918ca47363ca907..daaddec68def7e1c7cb11e4fe6d54e4193943c55 100644 (file)
@@ -140,7 +140,10 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
                 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
                 "(default: 0)");
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_kbd_backlight_resume(void);
+static void sony_nc_thermal_resume(void);
+#endif
 static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
                unsigned int handle);
 static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
@@ -151,7 +154,6 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd);
 
 static int sony_nc_thermal_setup(struct platform_device *pd);
 static void sony_nc_thermal_cleanup(struct platform_device *pd);
-static void sony_nc_thermal_resume(void);
 
 static int sony_nc_lid_resume_setup(struct platform_device *pd);
 static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
@@ -1431,6 +1433,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
        sony_nc_handles_cleanup(pd);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_function_resume(void)
 {
        unsigned int i, result, bitmask, arg;
@@ -1508,6 +1511,7 @@ static int sony_nc_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
 
@@ -1872,6 +1876,7 @@ static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_kbd_backlight_resume(void)
 {
        int ignore = 0;
@@ -1888,6 +1893,7 @@ static void sony_nc_kbd_backlight_resume(void)
                                (kbdbl_ctl->base + 0x200) |
                                (kbdbl_ctl->timeout << 0x10), &ignore);
 }
+#endif
 
 struct battery_care_control {
        struct device_attribute attrs[2];
@@ -2210,6 +2216,7 @@ static void sony_nc_thermal_cleanup(struct platform_device *pd)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_thermal_resume(void)
 {
        unsigned int status = sony_nc_thermal_mode_get();
@@ -2217,6 +2224,7 @@ static void sony_nc_thermal_resume(void)
        if (status != th_handle->mode)
                sony_nc_thermal_mode_set(th_handle->mode);
 }
+#endif
 
 /* resume on LID open */
 struct snc_lid_resume_control {
@@ -4287,6 +4295,7 @@ err_free_resources:
        return result;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int sony_pic_suspend(struct device *dev)
 {
        if (sony_pic_disable(to_acpi_device(dev)))
@@ -4300,6 +4309,7 @@ static int sony_pic_resume(struct device *dev)
                        spic_dev.cur_ioport, spic_dev.cur_irq);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
 
index e7f73287636cd9bdabb3f0b32104d4b7257e5e69..80e377949314ba37b3f00f09655290ed062349ed 100644 (file)
@@ -922,6 +922,7 @@ static struct input_dev *tpacpi_inputdev;
 static struct mutex tpacpi_inputdev_send_mutex;
 static LIST_HEAD(tpacpi_all_drivers);
 
+#ifdef CONFIG_PM_SLEEP
 static int tpacpi_suspend_handler(struct device *dev)
 {
        struct ibm_struct *ibm, *itmp;
@@ -949,6 +950,7 @@ static int tpacpi_resume_handler(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(tpacpi_pm,
                         tpacpi_suspend_handler, tpacpi_resume_handler);
@@ -8662,6 +8664,13 @@ static int __must_check __init get_thinkpad_model_data(
                tp->model_str = kstrdup(s, GFP_KERNEL);
                if (!tp->model_str)
                        return -ENOMEM;
+       } else {
+               s = dmi_get_system_info(DMI_BIOS_VENDOR);
+               if (s && !(strnicmp(s, "Lenovo", 6))) {
+                       tp->model_str = kstrdup(s, GFP_KERNEL);
+                       if (!tp->model_str)
+                               return -ENOMEM;
+               }
        }
 
        s = dmi_get_system_info(DMI_PRODUCT_NAME);
index c13ba5bac93f1c594f22ecb1b6e701586793a081..5f1256d5e9332cf45dbdd2031987ea41fe0212cf 100644 (file)
@@ -1296,6 +1296,7 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int toshiba_acpi_suspend(struct device *device)
 {
        struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
@@ -1317,6 +1318,7 @@ static int toshiba_acpi_resume(struct device *device)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
                         toshiba_acpi_suspend, toshiba_acpi_resume);
index 715a43cb5e3c49020c24a07c302ec3792fcce84a..5e5d6317d690095b9f95ff761b2c5d5d0cb5a7d4 100644 (file)
@@ -41,7 +41,9 @@ static const struct acpi_device_id bt_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, bt_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int toshiba_bt_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
 
 static struct acpi_driver toshiba_bt_rfkill_driver = {
@@ -90,10 +92,12 @@ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
        toshiba_bluetooth_enable(device->handle);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int toshiba_bt_resume(struct device *dev)
 {
        return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
 }
+#endif
 
 static int toshiba_bt_rfkill_add(struct acpi_device *device)
 {
index 849c07c13bf6cae790c3e99dfb402f55b88a2a1f..38ba39d7ca7de5cebd5f45163f55035b4f303d6e 100644 (file)
@@ -77,10 +77,12 @@ static void ebook_switch_notify(struct acpi_device *device, u32 event)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ebook_switch_resume(struct device *dev)
 {
        return ebook_send_state(to_acpi_device(dev));
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
 
index 8fc3808d7a3e8b08b2bc3a8eb53b899f9a41b953..90c5c7357a5041041f518f564849fa98240f50f4 100644 (file)
@@ -1,12 +1,31 @@
 menuconfig PWM
-       bool "PWM Support"
+       bool "Pulse-Width Modulation (PWM) Support"
        depends on !MACH_JZ4740 && !PUV3_PWM
        help
-         This enables PWM support through the generic PWM framework.
-         You only need to enable this, if you also want to enable
-         one or more of the PWM drivers below.
-
-         If unsure, say N.
+         Generic Pulse-Width Modulation (PWM) support.
+
+         In Pulse-Width Modulation, a variation of the width of pulses
+         in a rectangular pulse signal is used as a means to alter the
+         average power of the signal. Applications include efficient
+         power delivery and voltage regulation. In computer systems,
+         PWMs are commonly used to control fans or the brightness of
+         display backlights.
+
+         This framework provides a generic interface to PWM devices
+         within the Linux kernel. On the driver side it provides an API
+         to register and unregister a PWM chip, an abstraction of a PWM
+         controller, that supports one or more PWM devices. Client
+         drivers can request PWM devices and use the generic framework
+         to configure as well as enable and disable them.
+
+         This generic framework replaces the legacy PWM framework which
+         allows only a single driver implementing the required API. Not
+         all legacy implementations have been ported to the framework
+         yet. The framework provides an API that is backward compatible
+         with the legacy framework so that existing client drivers
+         continue to work as expected.
+
+         If unsure, say no.
 
 if PWM
 
index ecb76909e946542ee9beff407c8d2ed1e69ff56e..c6e05078d3adaff05708cc11ce76ea97763a375b 100644 (file)
@@ -129,8 +129,8 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        return 0;
 }
 
-static struct pwm_device *of_pwm_simple_xlate(struct pwm_chip *pc,
-                                             const struct of_phandle_args *args)
+static struct pwm_device *
+of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 {
        struct pwm_device *pwm;
 
@@ -149,7 +149,7 @@ static struct pwm_device *of_pwm_simple_xlate(struct pwm_chip *pc,
        return pwm;
 }
 
-void of_pwmchip_add(struct pwm_chip *chip)
+static void of_pwmchip_add(struct pwm_chip *chip)
 {
        if (!chip->dev || !chip->dev->of_node)
                return;
@@ -162,7 +162,7 @@ void of_pwmchip_add(struct pwm_chip *chip)
        of_node_get(chip->dev->of_node);
 }
 
-void of_pwmchip_remove(struct pwm_chip *chip)
+static void of_pwmchip_remove(struct pwm_chip *chip)
 {
        if (chip->dev && chip->dev->of_node)
                of_node_put(chip->dev->of_node);
@@ -527,7 +527,7 @@ void __init pwm_add_table(struct pwm_lookup *table, size_t num)
 struct pwm_device *pwm_get(struct device *dev, const char *con_id)
 {
        struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER);
-       const char *dev_id = dev ? dev_name(dev): NULL;
+       const char *dev_id = dev ? dev_name(dev) : NULL;
        struct pwm_chip *chip = NULL;
        unsigned int index = 0;
        unsigned int best = 0;
@@ -609,7 +609,7 @@ void pwm_put(struct pwm_device *pwm)
        mutex_lock(&pwm_lock);
 
        if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
-               pr_warning("PWM device already freed\n");
+               pr_warn("PWM device already freed\n");
                goto out;
        }
 
index d10386528c9ce4c684413f750960b23a12225fa8..e5187c0ade9fdde4a4cfd4e8ba55c8b2d337173a 100644 (file)
@@ -225,6 +225,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)
 
        /* calculate base of control bits in TCON */
        s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+       s3c->chip.dev = &pdev->dev;
        s3c->chip.ops = &s3c_pwm_ops;
        s3c->chip.base = -1;
        s3c->chip.npwm = 1;
index 02ce18d5e49a7800e396d2e519692bc1937701bf..057465e0553c7d252b8be7eebf5507deb5a24127 100644 (file)
@@ -187,10 +187,8 @@ static int tegra_pwm_probe(struct platform_device *pdev)
        }
 
        pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
-       if (!pwm->mmio_base) {
-               dev_err(&pdev->dev, "failed to ioremap() region\n");
+       if (!pwm->mmio_base)
                return -EADDRNOTAVAIL;
-       }
 
        platform_set_drvdata(pdev, pwm);
 
index 3c2ad284ee3ecce9a2ee80a140cdd2351b494530..0b66d0f259224f9e7ca679a2759a473708cd3be6 100644 (file)
@@ -192,10 +192,8 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev)
        }
 
        pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
-       if (!pc->mmio_base) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
+       if (!pc->mmio_base)
                return -EADDRNOTAVAIL;
-       }
 
        ret = pwmchip_add(&pc->chip);
        if (ret < 0) {
index 010d232cb0c8b3ab2f586f93aebae056a4d7daf1..c3756d1be19496fdf3dd163787b7e289e9ad70bd 100644 (file)
@@ -371,10 +371,8 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev)
        }
 
        pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
-       if (!pc->mmio_base) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
+       if (!pc->mmio_base)
                return  -EADDRNOTAVAIL;
-       }
 
        ret = pwmchip_add(&pc->chip);
        if (ret < 0) {
index 548021439f0cc2a71183496750a961d38d91b98d..ad14389b7144a29f142ed9b8e0c9d6df3b2793c0 100644 (file)
@@ -41,7 +41,7 @@ static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
                cpu_relax();
 
        if (unlikely(!loops))
-               pr_warning("Waiting for status bits 0x%x to clear timed out\n",
+               pr_warn("Waiting for status bits 0x%x to clear timed out\n",
                           bitmask);
 }
 
index 722246cf20ab2ed592a6a5ed5435b0f1320a5a44..5d44252b7342f3d72dd5060770f2b42ef3bb2e8f 100644 (file)
@@ -435,6 +435,9 @@ static void tsi721_db_dpc(struct work_struct *work)
                                " info %4.4x\n", DBELL_SID(idb.bytes),
                                DBELL_TID(idb.bytes), DBELL_INF(idb.bytes));
                }
+
+               wr_ptr = ioread32(priv->regs +
+                                 TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
        }
 
        iowrite32(rd_ptr & (IDB_QSIZE - 1),
@@ -445,6 +448,10 @@ static void tsi721_db_dpc(struct work_struct *work)
        regval |= TSI721_SR_CHINT_IDBQRCV;
        iowrite32(regval,
                priv->regs + TSI721_SR_CHINTE(IDB_QUEUE));
+
+       wr_ptr = ioread32(priv->regs + TSI721_IDQ_WP(IDB_QUEUE)) % IDB_QSIZE;
+       if (wr_ptr != rd_ptr)
+               schedule_work(&priv->idb_work);
 }
 
 /**
@@ -2212,7 +2219,7 @@ static int __devinit tsi721_probe(struct pci_dev *pdev,
                                  const struct pci_device_id *id)
 {
        struct tsi721_device *priv;
-       int i, cap;
+       int cap;
        int err;
        u32 regval;
 
@@ -2232,12 +2239,15 @@ static int __devinit tsi721_probe(struct pci_dev *pdev,
        priv->pdev = pdev;
 
 #ifdef DEBUG
+       {
+       int i;
        for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
                dev_dbg(&pdev->dev, "res[%d] @ 0x%llx (0x%lx, 0x%lx)\n",
                        i, (unsigned long long)pci_resource_start(pdev, i),
                        (unsigned long)pci_resource_len(pdev, i),
                        pci_resource_flags(pdev, i));
        }
+       }
 #endif
        /*
         * Verify BAR configuration
index 182b553059c9c82a15f8ff164d64c5d37e708c52..c151fd5d8c974d978c25cf9ded8a9805b333b9af 100644 (file)
@@ -486,6 +486,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .id   = AB3100_BUCK,
                .ops  = &regulator_ops_variable_sleepable,
                .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+               .volt_table = ldo_e_buck_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_time = 1000,
index e9c2085f9dfbe0993c6931c573efb52a660f06a0..ce0fe72a428e811418aa8190c7f534ce1009d5a4 100644 (file)
@@ -64,14 +64,15 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
 static int anatop_get_voltage_sel(struct regulator_dev *reg)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-       u32 val;
+       u32 val, mask;
 
        if (!anatop_reg->control_reg)
                return -ENOTSUPP;
 
        val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg);
-       val = (val & ((1 << anatop_reg->vol_bit_width) - 1)) >>
+       mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
                anatop_reg->vol_bit_shift;
+       val = (val & mask) >> anatop_reg->vol_bit_shift;
 
        return val - anatop_reg->min_bit_val;
 }
index f092588a078c65b3d3951a55a8ef861a44a50146..48385318175a83fe17208e099caa46c07a01d2f2 100644 (file)
@@ -3217,7 +3217,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        dev_set_drvdata(&rdev->dev, rdev);
 
-       if (config->ena_gpio) {
+       if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
                ret = gpio_request_one(config->ena_gpio,
                                       GPIOF_DIR_OUT | config->ena_gpio_flags,
                                       rdev_get_name(rdev));
index 34b67bee9323ce00a49b30bb0cf7d9256660b6f8..8b5944f2d7d1ddd36e82e92d786770e469743dfe 100644 (file)
@@ -57,16 +57,17 @@ static int gpio_regulator_get_value(struct regulator_dev *dev)
        return -EINVAL;
 }
 
-static int gpio_regulator_set_value(struct regulator_dev *dev,
-                                       int min, int max, unsigned *selector)
+static int gpio_regulator_set_voltage(struct regulator_dev *dev,
+                                       int min_uV, int max_uV,
+                                       unsigned *selector)
 {
        struct gpio_regulator_data *data = rdev_get_drvdata(dev);
        int ptr, target = 0, state, best_val = INT_MAX;
 
        for (ptr = 0; ptr < data->nr_states; ptr++)
                if (data->states[ptr].value < best_val &&
-                   data->states[ptr].value >= min &&
-                   data->states[ptr].value <= max) {
+                   data->states[ptr].value >= min_uV &&
+                   data->states[ptr].value <= max_uV) {
                        target = data->states[ptr].gpios;
                        best_val = data->states[ptr].value;
                        if (selector)
@@ -85,13 +86,6 @@ static int gpio_regulator_set_value(struct regulator_dev *dev,
        return 0;
 }
 
-static int gpio_regulator_set_voltage(struct regulator_dev *dev,
-                                       int min_uV, int max_uV,
-                                       unsigned *selector)
-{
-       return gpio_regulator_set_value(dev, min_uV, max_uV, selector);
-}
-
 static int gpio_regulator_list_voltage(struct regulator_dev *dev,
                                      unsigned selector)
 {
@@ -106,7 +100,27 @@ static int gpio_regulator_list_voltage(struct regulator_dev *dev,
 static int gpio_regulator_set_current_limit(struct regulator_dev *dev,
                                        int min_uA, int max_uA)
 {
-       return gpio_regulator_set_value(dev, min_uA, max_uA, NULL);
+       struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+       int ptr, target = 0, state, best_val = 0;
+
+       for (ptr = 0; ptr < data->nr_states; ptr++)
+               if (data->states[ptr].value > best_val &&
+                   data->states[ptr].value >= min_uA &&
+                   data->states[ptr].value <= max_uA) {
+                       target = data->states[ptr].gpios;
+                       best_val = data->states[ptr].value;
+               }
+
+       if (best_val == 0)
+               return -EINVAL;
+
+       for (ptr = 0; ptr < data->nr_gpios; ptr++) {
+               state = (target & (1 << ptr)) >> ptr;
+               gpio_set_value(data->gpios[ptr].gpio, state);
+       }
+       data->state = target;
+
+       return 0;
 }
 
 static struct regulator_ops gpio_regulator_voltage_ops = {
index 17d19fbbc490156c8507301808863411a5f3135f..46c7e88f8381910004a4e46b0a3a722a1bcd7f28 100644 (file)
@@ -486,9 +486,12 @@ static int palmas_map_voltage_ldo(struct regulator_dev *rdev,
 {
        int ret, voltage;
 
-       ret = ((min_uV - 900000) / 50000) + 1;
-       if (ret < 0)
-               return ret;
+       if (min_uV == 0)
+               return 0;
+
+       if (min_uV < 900000)
+               min_uV = 900000;
+       ret = DIV_ROUND_UP(min_uV - 900000, 50000) + 1;
 
        /* Map back into a voltage to verify we're still in bounds */
        voltage = palmas_list_voltage_ldo(rdev, ret);
@@ -586,7 +589,7 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
 
        addr = palmas_regs_info[id].ctrl_addr;
 
-       ret = palmas_smps_read(palmas, addr, &reg);
+       ret = palmas_ldo_read(palmas, addr, &reg);
        if (ret)
                return ret;
 
@@ -596,7 +599,7 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
        if (reg_init->mode_sleep)
                reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
 
-       ret = palmas_smps_write(palmas, addr, reg);
+       ret = palmas_ldo_write(palmas, addr, reg);
        if (ret)
                return ret;
 
@@ -630,7 +633,7 @@ static __devinit int palmas_probe(struct platform_device *pdev)
 
        ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, &reg);
        if (ret)
-               goto err_unregister_regulator;
+               return ret;
 
        if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN)
                pmic->smps123 = 1;
@@ -676,7 +679,9 @@ static __devinit int palmas_probe(struct platform_device *pdev)
                case PALMAS_REG_SMPS10:
                        pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
                        pmic->desc[id].ops = &palmas_ops_smps10;
-                       pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL;
+                       pmic->desc[id].vsel_reg =
+                                       PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
+                                                       PALMAS_SMPS10_CTRL);
                        pmic->desc[id].vsel_mask = SMPS10_VSEL;
                        pmic->desc[id].enable_reg =
                                        PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
@@ -778,8 +783,10 @@ static __devinit int palmas_probe(struct platform_device *pdev)
                        reg_init = pdata->reg_init[id];
                        if (reg_init) {
                                ret = palmas_ldo_init(palmas, id, reg_init);
-                               if (ret)
+                               if (ret) {
+                                       regulator_unregister(pmic->rdev[id]);
                                        goto err_unregister_regulator;
+                               }
                        }
                }
        }
index e6da90ab5153dedd64ebd96137776f652af7d152..19241fc300505f46ff0179470a734238cb7c76fd 100644 (file)
@@ -240,14 +240,16 @@ static struct tps6586x_regulator tps6586x_regulator[] = {
        TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
        TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
        TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
-       TPS6586X_LDO(SM_2, "sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
+       TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
 
        TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
                                        ENB, 3, VCC2, 6),
        TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
                                        END, 3, VCC1, 6),
-       TPS6586X_DVM(SM_0, "sm0", dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
-       TPS6586X_DVM(SM_1, "sm1", dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
+       TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1,
+                                       ENB, 1, VCC1, 2),
+       TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0,
+                                       ENB, 0, VCC1, 0),
 };
 
 /*
index 242fe90dc56502ad5c5e1cc0ced284561b0e6df9..77a71a5c17c338708ec112a874e59f15e6212257 100644 (file)
@@ -1037,7 +1037,7 @@ TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300);
 TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300);
 TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300);
 TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300);
-TWL4030_FIXED_LDO(VINTANA2, 0x3f, 1500, 11, 100, 0x08);
+TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08);
 TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
 TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08);
 TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08);
@@ -1048,7 +1048,6 @@ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0);
 TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0);
 TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0);
 TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0);
-TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0);
 TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34);
 TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10);
 TWL6025_ADJUSTABLE_SMPS(VIO, 0x16);
@@ -1117,7 +1116,7 @@ static const struct of_device_id twl_of_match[] __devinitconst = {
        TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6),
        TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN),
        TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB),
-       TWLFIXED_OF_MATCH("ti,twl4030-vintana2", VINTANA2),
+       TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1),
        TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG),
        TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5),
        TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8),
index eb415bd7649418f1d91b5c45b98fe9411f5171d3..9592b936b71bca1987d19aceba0f6e8b20b165b9 100644 (file)
@@ -582,6 +582,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
 void rtc_update_irq(struct rtc_device *rtc,
                unsigned long num, unsigned long events)
 {
+       pm_stay_awake(rtc->dev.parent);
        schedule_work(&rtc->irqwork);
 }
 EXPORT_SYMBOL_GPL(rtc_update_irq);
@@ -844,6 +845,7 @@ void rtc_timer_do_work(struct work_struct *work)
 
        mutex_lock(&rtc->ops_lock);
 again:
+       pm_relax(rtc->dev.parent);
        __rtc_read_time(rtc, &tm);
        now = rtc_tm_to_ktime(tm);
        while ((next = timerqueue_getnext(&rtc->timerqueue))) {
index 132333d754085d6b06a9c096444a95b708e45893..4267789ca9959413e90df5ea053154e07481d3ce 100644 (file)
@@ -568,7 +568,6 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
                hpet_mask_rtc_irq_bit(RTC_AIE);
 
                CMOS_READ(RTC_INTR_FLAGS);
-               pm_wakeup_event(cmos_rtc.dev, 0);
        }
        spin_unlock(&rtc_lock);
 
index 836118795c0bdb4f0ad5874a3b3dc50dee5ffd69..13e4df63974fa27e7d7acf97c7b94e57ff9722ac 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/rtc.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
+#include <linux/sysfs.h>
 
 #define DRV_VERSION "0.6"
 
@@ -292,6 +293,7 @@ static int __devinit pcf2123_probe(struct spi_device *spi)
        pdata->rtc = rtc;
 
        for (i = 0; i < 16; i++) {
+               sysfs_attr_init(&pdata->regs[i].attr.attr);
                sprintf(pdata->regs[i].name, "%1x", i);
                pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
                pdata->regs[i].attr.attr.name = pdata->regs[i].name;
index 77074ccd285071f345118079a4f7c3120e6b86a3..fd5c7af04ae5a7d7c1ba30a5822396e6780adc5f 100644 (file)
@@ -122,9 +122,12 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
        tm->tm_min = bcd2bin(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
        tm->tm_hour = bcd2bin(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
        if (!pdata->rtc_24h) {
-               tm->tm_hour %= 12;
-               if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM)
+               if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM) {
+                       tm->tm_hour -= 20;
+                       tm->tm_hour %= 12;
                        tm->tm_hour += 12;
+               } else
+                       tm->tm_hour %= 12;
        }
        tm->tm_wday = bcd2bin(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
        tm->tm_mday = bcd2bin(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
index 6a6f76bf6e3dad4fae79fedc125bb39b7678b79a..b1032931a1c41237766eaf6c38d7e5032e71e33d 100644 (file)
@@ -242,11 +242,13 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
        switch (sdias_evbuf.event_status) {
                case EVSTATE_ALL_STORED:
                        TRACE("all stored\n");
+                       break;
                case EVSTATE_PART_STORED:
                        TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
                        break;
                case EVSTATE_NO_DATA:
                        TRACE("no data\n");
+                       /* fall through */
                default:
                        pr_err("Error from SCLP while copying hsa. "
                               "Event status = %x\n",
index 2374468615ed57c147d9ba24489818268765ee70..32c26d795ed06d3a58c43bf3d295d8f75dcf676f 100644 (file)
@@ -324,8 +324,16 @@ int __init register_intc_controller(struct intc_desc *desc)
 
                res = irq_create_identity_mapping(d->domain, irq);
                if (unlikely(res)) {
-                       pr_err("can't get irq_desc for %d\n", irq);
-                       continue;
+                       if (res == -EEXIST) {
+                               res = irq_domain_associate(d->domain, irq, irq);
+                               if (unlikely(res)) {
+                                       pr_err("domain association failure\n");
+                                       continue;
+                               }
+                       } else {
+                               pr_err("can't identity map IRQ %d\n", irq);
+                               continue;
+                       }
                }
 
                intc_irq_xlate_set(irq, vect->enum_id, d);
@@ -345,8 +353,19 @@ int __init register_intc_controller(struct intc_desc *desc)
                         */
                        res = irq_create_identity_mapping(d->domain, irq2);
                        if (unlikely(res)) {
-                               pr_err("can't get irq_desc for %d\n", irq2);
-                               continue;
+                               if (res == -EEXIST) {
+                                       res = irq_domain_associate(d->domain,
+                                                                  irq, irq);
+                                       if (unlikely(res)) {
+                                               pr_err("domain association "
+                                                      "failure\n");
+                                               continue;
+                                       }
+                               } else {
+                                       pr_err("can't identity map IRQ %d\n",
+                                              irq);
+                                       continue;
+                               }
                        }
 
                        vect2->enum_id = 0;
index 6e25ef1bce91f98549e5b514c051fd065deb6fbc..ea0aaa3f13d07549263a8b8e4da08acd92c3bc7e 100644 (file)
@@ -438,7 +438,7 @@ out:
 
 static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct bcm63xx_spi *bs = spi_master_get_devdata(master);
 
        spi_unregister_master(master);
@@ -452,6 +452,8 @@ static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, 0);
 
+       spi_master_put(master);
+
        return 0;
 }
 
index b2d4b9e4e0105d53dff9a3c747bd535b6732a6b6..764bfee75920f1779aedf9a0bc78d3280fd2045d 100644 (file)
@@ -533,7 +533,6 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
        iounmap(mcfqspi->iobase);
        release_mem_region(res->start, resource_size(res));
        spi_unregister_master(master);
-       spi_master_put(master);
 
        return 0;
 }
@@ -541,7 +540,7 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int mcfqspi_suspend(struct device *dev)
 {
-       struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+       struct spi_master *master = dev_get_drvdata(dev);
        struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        spi_master_suspend(master);
@@ -553,7 +552,7 @@ static int mcfqspi_suspend(struct device *dev)
 
 static int mcfqspi_resume(struct device *dev)
 {
-       struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+       struct spi_master *master = dev_get_drvdata(dev);
        struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        spi_master_resume(master);
index bc4778175e343c6a9ebeceac09b0cc543c935bc2..b2fb141da37565de69139fee9743b153fb463699 100644 (file)
@@ -1228,18 +1228,16 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
 
        status = spi_register_master(master);
        if (status < 0)
-               goto err_spi_register;
+               goto disable_pm;
 
        return status;
 
-err_spi_register:
-       spi_master_put(master);
 disable_pm:
        pm_runtime_disable(&pdev->dev);
 dma_chnl_free:
        kfree(mcspi->dma_channels);
 free_master:
-       kfree(master);
+       spi_master_put(master);
        platform_set_drvdata(pdev, NULL);
        return status;
 }
index aab518ec2bbc234c983be65ec84372740c1e5344..6abbe23c39b4751a3da3fb4d940912771c0fbfbe 100644 (file)
@@ -2053,7 +2053,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
        printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
               adev->res.start, pl022->virtbase);
 
-       pm_runtime_enable(dev);
        pm_runtime_resume(dev);
 
        pl022->clk = clk_get(&adev->dev, NULL);
index 646a7657fe62fbb545f95fc771b406d0cad6e5f9..d1c8441f638c39e6ad18d3930cd90b22efe268e5 100644 (file)
@@ -826,7 +826,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
                                struct spi_device *spi)
 {
        struct s3c64xx_spi_csinfo *cs;
-       struct device_node *slave_np, *data_np;
+       struct device_node *slave_np, *data_np = NULL;
        u32 fb_delay = 0;
 
        slave_np = spi->dev.of_node;
@@ -1479,40 +1479,40 @@ static const struct dev_pm_ops s3c64xx_spi_pm = {
                           s3c64xx_spi_runtime_resume, NULL)
 };
 
-struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
+static struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
        .high_speed     = true,
 };
 
-struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
+static struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f, 0x7F },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
 };
 
-struct s3c64xx_spi_port_config s5p64x0_spi_port_config = {
+static struct s3c64xx_spi_port_config s5p64x0_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
 };
 
-struct s3c64xx_spi_port_config s5pc100_spi_port_config = {
+static struct s3c64xx_spi_port_config s5pc100_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f, 0x7F },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
        .high_speed     = true,
 };
 
-struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
+static struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
        .high_speed     = true,
 };
 
-struct s3c64xx_spi_port_config exynos4_spi_port_config = {
+static struct s3c64xx_spi_port_config exynos4_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
index 1f00d701da25ccdf1d281758fdf1f6ba35504966..df166652599f49f4126d46ebc51e0989d2326bfd 100644 (file)
@@ -17,4 +17,9 @@ config USB_G_CCG
          Configurable Composite Gadget can be compiled "M" only
          or not at all.
 
+         BIG FAT NOTE: DON'T RELY ON THIS USERINTERFACE HERE! AS PART
+         OF THE REWORK DONE HERE WILL BE A NEW USER INTERFACE WITHOUT ANY
+         COMPATIBILITY TO THIS SYSFS INTERFACE HERE. BE AWARE OF THIS
+         BEFORE SELECTING THIS.
+
 endif # USB_GADGET
index 693da637a6d87d569b0a8f8d309960af3e6a4bbe..814fa9de5f5784c3e292567380b68c27c417ba77 100644 (file)
@@ -1,4 +1,2 @@
 g_ccg-y                                := ccg.o
-ccflags-y                      += -Idrivers/usb/gadget
-
 obj-$(CONFIG_USB_G_CCG)                += g_ccg.o
index 6a7aab8d9bf5bdaed15f4d9164795f5dbb59e9c9..80feb95e27dc4f3b18460972a07abc256e3db595 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb/composite.h>
+#include "composite.h"
 #include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "../../usb/gadget/usbstring.c"
-#include "../../usb/gadget/config.c"
-#include "../../usb/gadget/epautoconf.c"
-#include "../../usb/gadget/composite.c"
-
-#include "../../usb/gadget/f_mass_storage.c"
-#include "../../usb/gadget/u_serial.c"
-#include "../../usb/gadget/f_acm.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+#include "composite.c"
+
+#include "f_mass_storage.c"
+#include "u_serial.c"
+#include "f_acm.c"
 #define USB_ETH_RNDIS y
-#include "../../usb/gadget/f_rndis.c"
-#include "../../usb/gadget/rndis.c"
-#include "../../usb/gadget/u_ether.c"
-#include "../../usb/gadget/f_fs.c"
+#include "f_rndis.c"
+#include "rndis.c"
+#include "u_ether.c"
+#include "f_fs.c"
 
 MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz");
 MODULE_DESCRIPTION("Configurable Composite USB Gadget");
@@ -1162,6 +1162,7 @@ static int ccg_usb_unbind(struct usb_composite_dev *cdev)
 static struct usb_composite_driver ccg_usb_driver = {
        .name           = "configurable_usb",
        .dev            = &device_desc,
+       .bind           = ccg_bind,
        .unbind         = ccg_usb_unbind,
        .needs_serial   = true,
        .iManufacturer  = "Linux Foundation",
@@ -1275,7 +1276,7 @@ static int __init init(void)
        composite_driver.setup = ccg_setup;
        composite_driver.disconnect = ccg_disconnect;
 
-       err = usb_composite_probe(&ccg_usb_driver, ccg_bind);
+       err = usb_composite_probe(&ccg_usb_driver);
        if (err) {
                class_destroy(ccg_class);
                kfree(dev);
diff --git a/drivers/staging/ccg/composite.c b/drivers/staging/ccg/composite.c
new file mode 100644 (file)
index 0000000..228b457
--- /dev/null
@@ -0,0 +1,1688 @@
+/*
+ * composite.c - infrastructure for Composite USB Gadgets
+ *
+ * Copyright (C) 2006-2008 David Brownell
+ *
+ * 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.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/utsname.h>
+
+#include <linux/usb/composite.h>
+#include <asm/unaligned.h>
+
+/*
+ * The code in this file is utility code, used to build a gadget driver
+ * from one or more "function" drivers, one or more "configuration"
+ * objects, and a "usb_composite_driver" by gluing them together along
+ * with the relevant device-wide data.
+ */
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ     1024
+
+static struct usb_composite_driver *composite;
+
+/* Some systems will need runtime overrides for the  product identifiers
+ * published in the device descriptor, either numbers or strings or both.
+ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort idVendor;
+module_param(idVendor, ushort, 0644);
+MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+
+static ushort idProduct;
+module_param(idProduct, ushort, 0644);
+MODULE_PARM_DESC(idProduct, "USB Product ID");
+
+static ushort bcdDevice;
+module_param(bcdDevice, ushort, 0644);
+MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+
+static char *iManufacturer;
+module_param(iManufacturer, charp, 0644);
+MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+
+static char *iProduct;
+module_param(iProduct, charp, 0644);
+MODULE_PARM_DESC(iProduct, "USB Product string");
+
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, 0644);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
+
+static char composite_manufacturer[50];
+
+/*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+       for (; *t; t++) {
+               if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+                       return t;
+       }
+       return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ *             descriptors list
+ * @start:     pointer within descriptor array.
+ * @ep_desc:   endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+       for (ep_desc = next_ep_desc(start); \
+             ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+                       struct usb_function *f,
+                       struct usb_ep *_ep)
+{
+       struct usb_composite_dev        *cdev = get_gadget_data(g);
+       struct usb_endpoint_descriptor *chosen_desc = NULL;
+       struct usb_descriptor_header **speed_desc = NULL;
+
+       struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+       int want_comp_desc = 0;
+
+       struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+       if (!g || !f || !_ep)
+               return -EIO;
+
+       /* select desired speed */
+       switch (g->speed) {
+       case USB_SPEED_SUPER:
+               if (gadget_is_superspeed(g)) {
+                       speed_desc = f->ss_descriptors;
+                       want_comp_desc = 1;
+                       break;
+               }
+               /* else: Fall trough */
+       case USB_SPEED_HIGH:
+               if (gadget_is_dualspeed(g)) {
+                       speed_desc = f->hs_descriptors;
+                       break;
+               }
+               /* else: fall through */
+       default:
+               speed_desc = f->descriptors;
+       }
+       /* find descriptors */
+       for_each_ep_desc(speed_desc, d_spd) {
+               chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+               if (chosen_desc->bEndpointAddress == _ep->address)
+                       goto ep_found;
+       }
+       return -EIO;
+
+ep_found:
+       /* commit results */
+       _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
+       _ep->desc = chosen_desc;
+       _ep->comp_desc = NULL;
+       _ep->maxburst = 0;
+       _ep->mult = 0;
+       if (!want_comp_desc)
+               return 0;
+
+       /*
+        * Companion descriptor should follow EP descriptor
+        * USB 3.0 spec, #9.6.7
+        */
+       comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+       if (!comp_desc ||
+           (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+               return -EIO;
+       _ep->comp_desc = comp_desc;
+       if (g->speed == USB_SPEED_SUPER) {
+               switch (usb_endpoint_type(_ep->desc)) {
+               case USB_ENDPOINT_XFER_ISOC:
+                       /* mult: bits 1:0 of bmAttributes */
+                       _ep->mult = comp_desc->bmAttributes & 0x3;
+               case USB_ENDPOINT_XFER_BULK:
+               case USB_ENDPOINT_XFER_INT:
+                       _ep->maxburst = comp_desc->bMaxBurst + 1;
+                       break;
+               default:
+                       if (comp_desc->bMaxBurst != 0)
+                               ERROR(cdev, "ep0 bMaxBurst must be 0\n");
+                       _ep->maxburst = 1;
+                       break;
+               }
+       }
+       return 0;
+}
+
+/**
+ * usb_add_function() - add a function to a configuration
+ * @config: the configuration
+ * @function: the function being added
+ * Context: single threaded during gadget setup
+ *
+ * After initialization, each configuration must have one or more
+ * functions added to it.  Adding a function involves calling its @bind()
+ * method to allocate resources such as interface and string identifiers
+ * and endpoints.
+ *
+ * This function returns the value of the function's bind(), which is
+ * zero for success else a negative errno value.
+ */
+int usb_add_function(struct usb_configuration *config,
+               struct usb_function *function)
+{
+       int     value = -EINVAL;
+
+       DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
+                       function->name, function,
+                       config->label, config);
+
+       if (!function->set_alt || !function->disable)
+               goto done;
+
+       function->config = config;
+       list_add_tail(&function->list, &config->functions);
+
+       /* REVISIT *require* function->bind? */
+       if (function->bind) {
+               value = function->bind(config, function);
+               if (value < 0) {
+                       list_del(&function->list);
+                       function->config = NULL;
+               }
+       } else
+               value = 0;
+
+       /* We allow configurations that don't work at both speeds.
+        * If we run into a lowspeed Linux system, treat it the same
+        * as full speed ... it's the function drivers that will need
+        * to avoid bulk and ISO transfers.
+        */
+       if (!config->fullspeed && function->descriptors)
+               config->fullspeed = true;
+       if (!config->highspeed && function->hs_descriptors)
+               config->highspeed = true;
+       if (!config->superspeed && function->ss_descriptors)
+               config->superspeed = true;
+
+done:
+       if (value)
+               DBG(config->cdev, "adding '%s'/%p --> %d\n",
+                               function->name, function, value);
+       return value;
+}
+
+/**
+ * usb_function_deactivate - prevent function and gadget enumeration
+ * @function: the function that isn't yet ready to respond
+ *
+ * Blocks response of the gadget driver to host enumeration by
+ * preventing the data line pullup from being activated.  This is
+ * normally called during @bind() processing to change from the
+ * initial "ready to respond" state, or when a required resource
+ * becomes available.
+ *
+ * For example, drivers that serve as a passthrough to a userspace
+ * daemon can block enumeration unless that daemon (such as an OBEX,
+ * MTP, or print server) is ready to handle host requests.
+ *
+ * Not all systems support software control of their USB peripheral
+ * data pullups.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_deactivate(struct usb_function *function)
+{
+       struct usb_composite_dev        *cdev = function->config->cdev;
+       unsigned long                   flags;
+       int                             status = 0;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+
+       if (cdev->deactivations == 0)
+               status = usb_gadget_disconnect(cdev->gadget);
+       if (status == 0)
+               cdev->deactivations++;
+
+       spin_unlock_irqrestore(&cdev->lock, flags);
+       return status;
+}
+
+/**
+ * usb_function_activate - allow function and gadget enumeration
+ * @function: function on which usb_function_activate() was called
+ *
+ * Reverses effect of usb_function_deactivate().  If no more functions
+ * are delaying their activation, the gadget driver will respond to
+ * host enumeration procedures.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_function_activate(struct usb_function *function)
+{
+       struct usb_composite_dev        *cdev = function->config->cdev;
+       unsigned long                   flags;
+       int                             status = 0;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+
+       if (WARN_ON(cdev->deactivations == 0))
+               status = -EINVAL;
+       else {
+               cdev->deactivations--;
+               if (cdev->deactivations == 0)
+                       status = usb_gadget_connect(cdev->gadget);
+       }
+
+       spin_unlock_irqrestore(&cdev->lock, flags);
+       return status;
+}
+
+/**
+ * usb_interface_id() - allocate an unused interface ID
+ * @config: configuration associated with the interface
+ * @function: function handling the interface
+ * Context: single threaded during gadget setup
+ *
+ * usb_interface_id() is called from usb_function.bind() callbacks to
+ * allocate new interface IDs.  The function driver will then store that
+ * ID in interface, association, CDC union, and other descriptors.  It
+ * will also handle any control requests targeted at that interface,
+ * particularly changing its altsetting via set_alt().  There may
+ * also be class-specific or vendor-specific requests to handle.
+ *
+ * All interface identifier should be allocated using this routine, to
+ * ensure that for example different functions don't wrongly assign
+ * different meanings to the same identifier.  Note that since interface
+ * identifiers are configuration-specific, functions used in more than
+ * one configuration (or more than once in a given configuration) need
+ * multiple versions of the relevant descriptors.
+ *
+ * Returns the interface ID which was allocated; or -ENODEV if no
+ * more interface IDs can be allocated.
+ */
+int usb_interface_id(struct usb_configuration *config,
+               struct usb_function *function)
+{
+       unsigned id = config->next_interface_id;
+
+       if (id < MAX_CONFIG_INTERFACES) {
+               config->interface[id] = function;
+               config->next_interface_id = id + 1;
+               return id;
+       }
+       return -ENODEV;
+}
+
+static int config_buf(struct usb_configuration *config,
+               enum usb_device_speed speed, void *buf, u8 type)
+{
+       struct usb_config_descriptor    *c = buf;
+       void                            *next = buf + USB_DT_CONFIG_SIZE;
+       int                             len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
+       struct usb_function             *f;
+       int                             status;
+
+       /* write the config descriptor */
+       c = buf;
+       c->bLength = USB_DT_CONFIG_SIZE;
+       c->bDescriptorType = type;
+       /* wTotalLength is written later */
+       c->bNumInterfaces = config->next_interface_id;
+       c->bConfigurationValue = config->bConfigurationValue;
+       c->iConfiguration = config->iConfiguration;
+       c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
+       c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
+
+       /* There may be e.g. OTG descriptors */
+       if (config->descriptors) {
+               status = usb_descriptor_fillbuf(next, len,
+                               config->descriptors);
+               if (status < 0)
+                       return status;
+               len -= status;
+               next += status;
+       }
+
+       /* add each function's descriptors */
+       list_for_each_entry(f, &config->functions, list) {
+               struct usb_descriptor_header **descriptors;
+
+               switch (speed) {
+               case USB_SPEED_SUPER:
+                       descriptors = f->ss_descriptors;
+                       break;
+               case USB_SPEED_HIGH:
+                       descriptors = f->hs_descriptors;
+                       break;
+               default:
+                       descriptors = f->descriptors;
+               }
+
+               if (!descriptors)
+                       continue;
+               status = usb_descriptor_fillbuf(next, len,
+                       (const struct usb_descriptor_header **) descriptors);
+               if (status < 0)
+                       return status;
+               len -= status;
+               next += status;
+       }
+
+       len = next - buf;
+       c->wTotalLength = cpu_to_le16(len);
+       return len;
+}
+
+static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
+{
+       struct usb_gadget               *gadget = cdev->gadget;
+       struct usb_configuration        *c;
+       u8                              type = w_value >> 8;
+       enum usb_device_speed           speed = USB_SPEED_UNKNOWN;
+
+       if (gadget->speed == USB_SPEED_SUPER)
+               speed = gadget->speed;
+       else if (gadget_is_dualspeed(gadget)) {
+               int     hs = 0;
+               if (gadget->speed == USB_SPEED_HIGH)
+                       hs = 1;
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+               if (hs)
+                       speed = USB_SPEED_HIGH;
+
+       }
+
+       /* This is a lookup by config *INDEX* */
+       w_value &= 0xff;
+       list_for_each_entry(c, &cdev->configs, list) {
+               /* ignore configs that won't work at this speed */
+               switch (speed) {
+               case USB_SPEED_SUPER:
+                       if (!c->superspeed)
+                               continue;
+                       break;
+               case USB_SPEED_HIGH:
+                       if (!c->highspeed)
+                               continue;
+                       break;
+               default:
+                       if (!c->fullspeed)
+                               continue;
+               }
+
+               if (w_value == 0)
+                       return config_buf(c, speed, cdev->req->buf, type);
+               w_value--;
+       }
+       return -EINVAL;
+}
+
+static int count_configs(struct usb_composite_dev *cdev, unsigned type)
+{
+       struct usb_gadget               *gadget = cdev->gadget;
+       struct usb_configuration        *c;
+       unsigned                        count = 0;
+       int                             hs = 0;
+       int                             ss = 0;
+
+       if (gadget_is_dualspeed(gadget)) {
+               if (gadget->speed == USB_SPEED_HIGH)
+                       hs = 1;
+               if (gadget->speed == USB_SPEED_SUPER)
+                       ss = 1;
+               if (type == USB_DT_DEVICE_QUALIFIER)
+                       hs = !hs;
+       }
+       list_for_each_entry(c, &cdev->configs, list) {
+               /* ignore configs that won't work at this speed */
+               if (ss) {
+                       if (!c->superspeed)
+                               continue;
+               } else if (hs) {
+                       if (!c->highspeed)
+                               continue;
+               } else {
+                       if (!c->fullspeed)
+                               continue;
+               }
+               count++;
+       }
+       return count;
+}
+
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ *     descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+       struct usb_ext_cap_descriptor   *usb_ext;
+       struct usb_ss_cap_descriptor    *ss_cap;
+       struct usb_dcd_config_params    dcd_config_params;
+       struct usb_bos_descriptor       *bos = cdev->req->buf;
+
+       bos->bLength = USB_DT_BOS_SIZE;
+       bos->bDescriptorType = USB_DT_BOS;
+
+       bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+       bos->bNumDeviceCaps = 0;
+
+       /*
+        * A SuperSpeed device shall include the USB2.0 extension descriptor
+        * and shall support LPM when operating in USB2.0 HS mode.
+        */
+       usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+       bos->bNumDeviceCaps++;
+       le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+       usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+       usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+       usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+       usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+       /*
+        * The Superspeed USB Capability descriptor shall be implemented by all
+        * SuperSpeed devices.
+        */
+       ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+       bos->bNumDeviceCaps++;
+       le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+       ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+       ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+       ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+       ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+       ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+                               USB_FULL_SPEED_OPERATION |
+                               USB_HIGH_SPEED_OPERATION |
+                               USB_5GBPS_OPERATION);
+       ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+       /* Get Controller configuration */
+       if (cdev->gadget->ops->get_config_params)
+               cdev->gadget->ops->get_config_params(&dcd_config_params);
+       else {
+               dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
+               dcd_config_params.bU2DevExitLat =
+                       cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+       }
+       ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+       ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+       return le16_to_cpu(bos->wTotalLength);
+}
+
+static void device_qual(struct usb_composite_dev *cdev)
+{
+       struct usb_qualifier_descriptor *qual = cdev->req->buf;
+
+       qual->bLength = sizeof(*qual);
+       qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+       /* POLICY: same bcdUSB and device type info at both speeds */
+       qual->bcdUSB = cdev->desc.bcdUSB;
+       qual->bDeviceClass = cdev->desc.bDeviceClass;
+       qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
+       qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
+       /* ASSUME same EP0 fifo size at both speeds */
+       qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
+       qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
+       qual->bRESERVED = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void reset_config(struct usb_composite_dev *cdev)
+{
+       struct usb_function             *f;
+
+       DBG(cdev, "reset config\n");
+
+       list_for_each_entry(f, &cdev->config->functions, list) {
+               if (f->disable)
+                       f->disable(f);
+
+               bitmap_zero(f->endpoints, 32);
+       }
+       cdev->config = NULL;
+}
+
+static int set_config(struct usb_composite_dev *cdev,
+               const struct usb_ctrlrequest *ctrl, unsigned number)
+{
+       struct usb_gadget       *gadget = cdev->gadget;
+       struct usb_configuration *c = NULL;
+       int                     result = -EINVAL;
+       unsigned                power = gadget_is_otg(gadget) ? 8 : 100;
+       int                     tmp;
+
+       if (number) {
+               list_for_each_entry(c, &cdev->configs, list) {
+                       if (c->bConfigurationValue == number) {
+                               /*
+                                * We disable the FDs of the previous
+                                * configuration only if the new configuration
+                                * is a valid one
+                                */
+                               if (cdev->config)
+                                       reset_config(cdev);
+                               result = 0;
+                               break;
+                       }
+               }
+               if (result < 0)
+                       goto done;
+       } else { /* Zero configuration value - need to reset the config */
+               if (cdev->config)
+                       reset_config(cdev);
+               result = 0;
+       }
+
+       INFO(cdev, "%s config #%d: %s\n",
+            usb_speed_string(gadget->speed),
+            number, c ? c->label : "unconfigured");
+
+       if (!c)
+               goto done;
+
+       cdev->config = c;
+
+       /* Initialize all interfaces by setting them to altsetting zero. */
+       for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
+               struct usb_function     *f = c->interface[tmp];
+               struct usb_descriptor_header **descriptors;
+
+               if (!f)
+                       break;
+
+               /*
+                * Record which endpoints are used by the function. This is used
+                * to dispatch control requests targeted at that endpoint to the
+                * function's setup callback instead of the current
+                * configuration's setup callback.
+                */
+               switch (gadget->speed) {
+               case USB_SPEED_SUPER:
+                       descriptors = f->ss_descriptors;
+                       break;
+               case USB_SPEED_HIGH:
+                       descriptors = f->hs_descriptors;
+                       break;
+               default:
+                       descriptors = f->descriptors;
+               }
+
+               for (; *descriptors; ++descriptors) {
+                       struct usb_endpoint_descriptor *ep;
+                       int addr;
+
+                       if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
+                               continue;
+
+                       ep = (struct usb_endpoint_descriptor *)*descriptors;
+                       addr = ((ep->bEndpointAddress & 0x80) >> 3)
+                            |  (ep->bEndpointAddress & 0x0f);
+                       set_bit(addr, f->endpoints);
+               }
+
+               result = f->set_alt(f, tmp, 0);
+               if (result < 0) {
+                       DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
+                                       tmp, f->name, f, result);
+
+                       reset_config(cdev);
+                       goto done;
+               }
+
+               if (result == USB_GADGET_DELAYED_STATUS) {
+                       DBG(cdev,
+                        "%s: interface %d (%s) requested delayed status\n",
+                                       __func__, tmp, f->name);
+                       cdev->delayed_status++;
+                       DBG(cdev, "delayed_status count %d\n",
+                                       cdev->delayed_status);
+               }
+       }
+
+       /* when we return, be sure our power usage is valid */
+       power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
+done:
+       usb_gadget_vbus_draw(gadget, power);
+       if (result >= 0 && cdev->delayed_status)
+               result = USB_GADGET_DELAYED_STATUS;
+       return result;
+}
+
+/**
+ * usb_add_config() - add a configuration to a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration, with bConfigurationValue assigned
+ * @bind: the configuration's bind function
+ * Context: single threaded during gadget setup
+ *
+ * One of the main tasks of a composite @bind() routine is to
+ * add each of the configurations it supports, using this routine.
+ *
+ * This function returns the value of the configuration's @bind(), which
+ * is zero for success else a negative errno value.  Binding configurations
+ * assigns global resources including string IDs, and per-configuration
+ * resources such as interface IDs and endpoints.
+ */
+int usb_add_config(struct usb_composite_dev *cdev,
+               struct usb_configuration *config,
+               int (*bind)(struct usb_configuration *))
+{
+       int                             status = -EINVAL;
+       struct usb_configuration        *c;
+
+       DBG(cdev, "adding config #%u '%s'/%p\n",
+                       config->bConfigurationValue,
+                       config->label, config);
+
+       if (!config->bConfigurationValue || !bind)
+               goto done;
+
+       /* Prevent duplicate configuration identifiers */
+       list_for_each_entry(c, &cdev->configs, list) {
+               if (c->bConfigurationValue == config->bConfigurationValue) {
+                       status = -EBUSY;
+                       goto done;
+               }
+       }
+
+       config->cdev = cdev;
+       list_add_tail(&config->list, &cdev->configs);
+
+       INIT_LIST_HEAD(&config->functions);
+       config->next_interface_id = 0;
+       memset(config->interface, 0, sizeof(config->interface));
+
+       status = bind(config);
+       if (status < 0) {
+               while (!list_empty(&config->functions)) {
+                       struct usb_function             *f;
+
+                       f = list_first_entry(&config->functions,
+                                       struct usb_function, list);
+                       list_del(&f->list);
+                       if (f->unbind) {
+                               DBG(cdev, "unbind function '%s'/%p\n",
+                                       f->name, f);
+                               f->unbind(config, f);
+                               /* may free memory for "f" */
+                       }
+               }
+               list_del(&config->list);
+               config->cdev = NULL;
+       } else {
+               unsigned        i;
+
+               DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
+                       config->bConfigurationValue, config,
+                       config->superspeed ? " super" : "",
+                       config->highspeed ? " high" : "",
+                       config->fullspeed
+                               ? (gadget_is_dualspeed(cdev->gadget)
+                                       ? " full"
+                                       : " full/low")
+                               : "");
+
+               for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
+                       struct usb_function     *f = config->interface[i];
+
+                       if (!f)
+                               continue;
+                       DBG(cdev, "  interface %d = %s/%p\n",
+                               i, f->name, f);
+               }
+       }
+
+       /* set_alt(), or next bind(), sets up
+        * ep->driver_data as needed.
+        */
+       usb_ep_autoconfig_reset(cdev->gadget);
+
+done:
+       if (status)
+               DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
+                               config->bConfigurationValue, status);
+       return status;
+}
+
+static void remove_config(struct usb_composite_dev *cdev,
+                             struct usb_configuration *config)
+{
+       while (!list_empty(&config->functions)) {
+               struct usb_function             *f;
+
+               f = list_first_entry(&config->functions,
+                               struct usb_function, list);
+               list_del(&f->list);
+               if (f->unbind) {
+                       DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+                       f->unbind(config, f);
+                       /* may free memory for "f" */
+               }
+       }
+       list_del(&config->list);
+       if (config->unbind) {
+               DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+               config->unbind(config);
+                       /* may free memory for "c" */
+       }
+}
+
+/**
+ * usb_remove_config() - remove a configuration from a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration
+ *
+ * Drivers must call usb_gadget_disconnect before calling this function
+ * to disconnect the device from the host and make sure the host will not
+ * try to enumerate the device while we are changing the config list.
+ */
+void usb_remove_config(struct usb_composite_dev *cdev,
+                     struct usb_configuration *config)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+
+       if (cdev->config == config)
+               reset_config(cdev);
+
+       spin_unlock_irqrestore(&cdev->lock, flags);
+
+       remove_config(cdev, config);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* We support strings in multiple languages ... string descriptor zero
+ * says which languages are supported.  The typical case will be that
+ * only one language (probably English) is used, with I18N handled on
+ * the host side.
+ */
+
+static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
+{
+       const struct usb_gadget_strings *s;
+       __le16                          language;
+       __le16                          *tmp;
+
+       while (*sp) {
+               s = *sp;
+               language = cpu_to_le16(s->language);
+               for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) {
+                       if (*tmp == language)
+                               goto repeat;
+               }
+               *tmp++ = language;
+repeat:
+               sp++;
+       }
+}
+
+static int lookup_string(
+       struct usb_gadget_strings       **sp,
+       void                            *buf,
+       u16                             language,
+       int                             id
+)
+{
+       struct usb_gadget_strings       *s;
+       int                             value;
+
+       while (*sp) {
+               s = *sp++;
+               if (s->language != language)
+                       continue;
+               value = usb_gadget_get_string(s, id, buf);
+               if (value > 0)
+                       return value;
+       }
+       return -EINVAL;
+}
+
+static int get_string(struct usb_composite_dev *cdev,
+               void *buf, u16 language, int id)
+{
+       struct usb_configuration        *c;
+       struct usb_function             *f;
+       int                             len;
+       const char                      *str;
+
+       /* Yes, not only is USB's I18N support probably more than most
+        * folk will ever care about ... also, it's all supported here.
+        * (Except for UTF8 support for Unicode's "Astral Planes".)
+        */
+
+       /* 0 == report all available language codes */
+       if (id == 0) {
+               struct usb_string_descriptor    *s = buf;
+               struct usb_gadget_strings       **sp;
+
+               memset(s, 0, 256);
+               s->bDescriptorType = USB_DT_STRING;
+
+               sp = composite->strings;
+               if (sp)
+                       collect_langs(sp, s->wData);
+
+               list_for_each_entry(c, &cdev->configs, list) {
+                       sp = c->strings;
+                       if (sp)
+                               collect_langs(sp, s->wData);
+
+                       list_for_each_entry(f, &c->functions, list) {
+                               sp = f->strings;
+                               if (sp)
+                                       collect_langs(sp, s->wData);
+                       }
+               }
+
+               for (len = 0; len <= 126 && s->wData[len]; len++)
+                       continue;
+               if (!len)
+                       return -EINVAL;
+
+               s->bLength = 2 * (len + 1);
+               return s->bLength;
+       }
+
+       /* Otherwise, look up and return a specified string.  First
+        * check if the string has not been overridden.
+        */
+       if (cdev->manufacturer_override == id)
+               str = iManufacturer ?: composite->iManufacturer ?:
+                       composite_manufacturer;
+       else if (cdev->product_override == id)
+               str = iProduct ?: composite->iProduct;
+       else if (cdev->serial_override == id)
+               str = iSerialNumber ?: composite->iSerialNumber;
+       else
+               str = NULL;
+       if (str) {
+               struct usb_gadget_strings strings = {
+                       .language = language,
+                       .strings  = &(struct usb_string) { 0xff, str }
+               };
+               return usb_gadget_get_string(&strings, 0xff, buf);
+       }
+
+       /* String IDs are device-scoped, so we look up each string
+        * table we're told about.  These lookups are infrequent;
+        * simpler-is-better here.
+        */
+       if (composite->strings) {
+               len = lookup_string(composite->strings, buf, language, id);
+               if (len > 0)
+                       return len;
+       }
+       list_for_each_entry(c, &cdev->configs, list) {
+               if (c->strings) {
+                       len = lookup_string(c->strings, buf, language, id);
+                       if (len > 0)
+                               return len;
+               }
+               list_for_each_entry(f, &c->functions, list) {
+                       if (!f->strings)
+                               continue;
+                       len = lookup_string(f->strings, buf, language, id);
+                       if (len > 0)
+                               return len;
+               }
+       }
+       return -EINVAL;
+}
+
+/**
+ * usb_string_id() - allocate an unused string ID
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_id() is called from bind() callbacks to allocate
+ * string IDs.  Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
+ * that for example different functions don't wrongly assign different
+ * meanings to the same identifier.
+ */
+int usb_string_id(struct usb_composite_dev *cdev)
+{
+       if (cdev->next_string_id < 254) {
+               /* string id 0 is reserved by USB spec for list of
+                * supported languages */
+               /* 255 reserved as well? -- mina86 */
+               cdev->next_string_id++;
+               return cdev->next_string_id;
+       }
+       return -ENODEV;
+}
+
+/**
+ * usb_string_ids() - allocate unused string IDs in batch
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * @str: an array of usb_string objects to assign numbers to
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_ids() is called from bind() callbacks to allocate
+ * string IDs.  Drivers for functions, configurations, or gadgets will
+ * then copy IDs from the string table to the appropriate descriptors
+ * and string table for other languages.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
+{
+       int next = cdev->next_string_id;
+
+       for (; str->s; ++str) {
+               if (unlikely(next >= 254))
+                       return -ENODEV;
+               str->id = ++next;
+       }
+
+       cdev->next_string_id = next;
+
+       return 0;
+}
+
+/**
+ * usb_string_ids_n() - allocate unused string IDs in batch
+ * @c: the device whose string descriptor IDs are being allocated
+ * @n: number of string IDs to allocate
+ * Context: single threaded during gadget setup
+ *
+ * Returns the first requested ID.  This ID and next @n-1 IDs are now
+ * valid IDs.  At least provided that @n is non-zero because if it
+ * is, returns last requested ID which is now very useful information.
+ *
+ * @usb_string_ids_n() is called from bind() callbacks to allocate
+ * string IDs.  Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
+{
+       unsigned next = c->next_string_id;
+       if (unlikely(n > 254 || (unsigned)next + n > 254))
+               return -ENODEV;
+       c->next_string_id += n;
+       return next + 1;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       if (req->status || req->actual != req->length)
+               DBG((struct usb_composite_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 and function specific setup.
+ */
+static int
+composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       struct usb_request              *req = cdev->req;
+       int                             value = -EOPNOTSUPP;
+       int                             status = 0;
+       u16                             w_index = le16_to_cpu(ctrl->wIndex);
+       u8                              intf = w_index & 0xFF;
+       u16                             w_value = le16_to_cpu(ctrl->wValue);
+       u16                             w_length = le16_to_cpu(ctrl->wLength);
+       struct usb_function             *f = NULL;
+       u8                              endp;
+
+       /* partial re-init of the response message; the function or the
+        * gadget might need to intercept e.g. a control-OUT completion
+        * when we delegate to it.
+        */
+       req->zero = 0;
+       req->complete = composite_setup_complete;
+       req->length = 0;
+       gadget->ep0->driver_data = cdev;
+
+       switch (ctrl->bRequest) {
+
+       /* we handle all standard USB descriptors */
+       case USB_REQ_GET_DESCRIPTOR:
+               if (ctrl->bRequestType != USB_DIR_IN)
+                       goto unknown;
+               switch (w_value >> 8) {
+
+               case USB_DT_DEVICE:
+                       cdev->desc.bNumConfigurations =
+                               count_configs(cdev, USB_DT_DEVICE);
+                       cdev->desc.bMaxPacketSize0 =
+                               cdev->gadget->ep0->maxpacket;
+                       if (gadget_is_superspeed(gadget)) {
+                               if (gadget->speed >= USB_SPEED_SUPER) {
+                                       cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+                                       cdev->desc.bMaxPacketSize0 = 9;
+                               } else {
+                                       cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+                               }
+                       }
+
+                       value = min(w_length, (u16) sizeof cdev->desc);
+                       memcpy(req->buf, &cdev->desc, value);
+                       break;
+               case USB_DT_DEVICE_QUALIFIER:
+                       if (!gadget_is_dualspeed(gadget) ||
+                           gadget->speed >= USB_SPEED_SUPER)
+                               break;
+                       device_qual(cdev);
+                       value = min_t(int, w_length,
+                               sizeof(struct usb_qualifier_descriptor));
+                       break;
+               case USB_DT_OTHER_SPEED_CONFIG:
+                       if (!gadget_is_dualspeed(gadget) ||
+                           gadget->speed >= USB_SPEED_SUPER)
+                               break;
+                       /* FALLTHROUGH */
+               case USB_DT_CONFIG:
+                       value = config_desc(cdev, w_value);
+                       if (value >= 0)
+                               value = min(w_length, (u16) value);
+                       break;
+               case USB_DT_STRING:
+                       value = get_string(cdev, req->buf,
+                                       w_index, w_value & 0xff);
+                       if (value >= 0)
+                               value = min(w_length, (u16) value);
+                       break;
+               case USB_DT_BOS:
+                       if (gadget_is_superspeed(gadget)) {
+                               value = bos_desc(cdev);
+                               value = min(w_length, (u16) value);
+                       }
+                       break;
+               }
+               break;
+
+       /* any number of configs can work */
+       case USB_REQ_SET_CONFIGURATION:
+               if (ctrl->bRequestType != 0)
+                       goto unknown;
+               if (gadget_is_otg(gadget)) {
+                       if (gadget->a_hnp_support)
+                               DBG(cdev, "HNP available\n");
+                       else if (gadget->a_alt_hnp_support)
+                               DBG(cdev, "HNP on another port\n");
+                       else
+                               VDBG(cdev, "HNP inactive\n");
+               }
+               spin_lock(&cdev->lock);
+               value = set_config(cdev, ctrl, w_value);
+               spin_unlock(&cdev->lock);
+               break;
+       case USB_REQ_GET_CONFIGURATION:
+               if (ctrl->bRequestType != USB_DIR_IN)
+                       goto unknown;
+               if (cdev->config)
+                       *(u8 *)req->buf = cdev->config->bConfigurationValue;
+               else
+                       *(u8 *)req->buf = 0;
+               value = min(w_length, (u16) 1);
+               break;
+
+       /* function drivers must handle get/set altsetting; if there's
+        * no get() method, we know only altsetting zero works.
+        */
+       case USB_REQ_SET_INTERFACE:
+               if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+                       goto unknown;
+               if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+                       break;
+               f = cdev->config->interface[intf];
+               if (!f)
+                       break;
+               if (w_value && !f->set_alt)
+                       break;
+               value = f->set_alt(f, w_index, w_value);
+               if (value == USB_GADGET_DELAYED_STATUS) {
+                       DBG(cdev,
+                        "%s: interface %d (%s) requested delayed status\n",
+                                       __func__, intf, f->name);
+                       cdev->delayed_status++;
+                       DBG(cdev, "delayed_status count %d\n",
+                                       cdev->delayed_status);
+               }
+               break;
+       case USB_REQ_GET_INTERFACE:
+               if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+                       goto unknown;
+               if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+                       break;
+               f = cdev->config->interface[intf];
+               if (!f)
+                       break;
+               /* lots of interfaces only need altsetting zero... */
+               value = f->get_alt ? f->get_alt(f, w_index) : 0;
+               if (value < 0)
+                       break;
+               *((u8 *)req->buf) = value;
+               value = min(w_length, (u16) 1);
+               break;
+
+       /*
+        * USB 3.0 additions:
+        * Function driver should handle get_status request. If such cb
+        * wasn't supplied we respond with default value = 0
+        * Note: function driver should supply such cb only for the first
+        * interface of the function
+        */
+       case USB_REQ_GET_STATUS:
+               if (!gadget_is_superspeed(gadget))
+                       goto unknown;
+               if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+                       goto unknown;
+               value = 2;      /* This is the length of the get_status reply */
+               put_unaligned_le16(0, req->buf);
+               if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+                       break;
+               f = cdev->config->interface[intf];
+               if (!f)
+                       break;
+               status = f->get_status ? f->get_status(f) : 0;
+               if (status < 0)
+                       break;
+               put_unaligned_le16(status & 0x0000ffff, req->buf);
+               break;
+       /*
+        * Function drivers should handle SetFeature/ClearFeature
+        * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+        * only for the first interface of the function
+        */
+       case USB_REQ_CLEAR_FEATURE:
+       case USB_REQ_SET_FEATURE:
+               if (!gadget_is_superspeed(gadget))
+                       goto unknown;
+               if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+                       goto unknown;
+               switch (w_value) {
+               case USB_INTRF_FUNC_SUSPEND:
+                       if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+                               break;
+                       f = cdev->config->interface[intf];
+                       if (!f)
+                               break;
+                       value = 0;
+                       if (f->func_suspend)
+                               value = f->func_suspend(f, w_index >> 8);
+                       if (value < 0) {
+                               ERROR(cdev,
+                                     "func_suspend() returned error %d\n",
+                                     value);
+                               value = 0;
+                       }
+                       break;
+               }
+               break;
+       default:
+unknown:
+               VDBG(cdev,
+                       "non-core control req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+
+               /* functions always handle their interfaces and endpoints...
+                * punt other recipients (other, WUSB, ...) to the current
+                * configuration code.
+                *
+                * REVISIT it could make sense to let the composite device
+                * take such requests too, if that's ever needed:  to work
+                * in config 0, etc.
+                */
+               switch (ctrl->bRequestType & USB_RECIP_MASK) {
+               case USB_RECIP_INTERFACE:
+                       if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+                               break;
+                       f = cdev->config->interface[intf];
+                       break;
+
+               case USB_RECIP_ENDPOINT:
+                       endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
+                       list_for_each_entry(f, &cdev->config->functions, list) {
+                               if (test_bit(endp, f->endpoints))
+                                       break;
+                       }
+                       if (&f->list == &cdev->config->functions)
+                               f = NULL;
+                       break;
+               }
+
+               if (f && f->setup)
+                       value = f->setup(f, ctrl);
+               else {
+                       struct usb_configuration        *c;
+
+                       c = cdev->config;
+                       if (c && c->setup)
+                               value = c->setup(c, ctrl);
+               }
+
+               goto done;
+       }
+
+       /* respond with data transfer before status phase? */
+       if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
+               req->length = value;
+               req->zero = value < w_length;
+               value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0) {
+                       DBG(cdev, "ep_queue --> %d\n", value);
+                       req->status = 0;
+                       composite_setup_complete(gadget->ep0, req);
+               }
+       } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
+               WARN(cdev,
+                       "%s: Delayed status not supported for w_length != 0",
+                       __func__);
+       }
+
+done:
+       /* device either stalls (value < 0) or reports success */
+       return value;
+}
+
+static void composite_disconnect(struct usb_gadget *gadget)
+{
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       unsigned long                   flags;
+
+       /* REVISIT:  should we have config and device level
+        * disconnect callbacks?
+        */
+       spin_lock_irqsave(&cdev->lock, flags);
+       if (cdev->config)
+               reset_config(cdev);
+       if (composite->disconnect)
+               composite->disconnect(cdev);
+       spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static ssize_t composite_show_suspended(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+       struct usb_composite_dev *cdev = get_gadget_data(gadget);
+
+       return sprintf(buf, "%d\n", cdev->suspended);
+}
+
+static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
+
+static void
+composite_unbind(struct usb_gadget *gadget)
+{
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+
+       /* composite_disconnect() must already have been called
+        * by the underlying peripheral controller driver!
+        * so there's no i/o concurrency that could affect the
+        * state protected by cdev->lock.
+        */
+       WARN_ON(cdev->config);
+
+       while (!list_empty(&cdev->configs)) {
+               struct usb_configuration        *c;
+               c = list_first_entry(&cdev->configs,
+                               struct usb_configuration, list);
+               remove_config(cdev, c);
+       }
+       if (composite->unbind)
+               composite->unbind(cdev);
+
+       if (cdev->req) {
+               kfree(cdev->req->buf);
+               usb_ep_free_request(gadget->ep0, cdev->req);
+       }
+       device_remove_file(&gadget->dev, &dev_attr_suspended);
+       kfree(cdev);
+       set_gadget_data(gadget, NULL);
+       composite = NULL;
+}
+
+static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
+{
+       if (!*desc) {
+               int ret = usb_string_id(cdev);
+               if (unlikely(ret < 0))
+                       WARNING(cdev, "failed to override string ID\n");
+               else
+                       *desc = ret;
+       }
+
+       return *desc;
+}
+
+static int composite_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       struct usb_composite_dev        *cdev;
+       int                             status = -ENOMEM;
+
+       cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
+       if (!cdev)
+               return status;
+
+       spin_lock_init(&cdev->lock);
+       cdev->gadget = gadget;
+       set_gadget_data(gadget, cdev);
+       INIT_LIST_HEAD(&cdev->configs);
+
+       /* preallocate control response and buffer */
+       cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+       if (!cdev->req)
+               goto fail;
+       cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
+       if (!cdev->req->buf)
+               goto fail;
+       cdev->req->complete = composite_setup_complete;
+       gadget->ep0->driver_data = cdev;
+
+       cdev->bufsiz = USB_BUFSIZ;
+       cdev->driver = composite;
+
+       /*
+        * As per USB compliance update, a device that is actively drawing
+        * more than 100mA from USB must report itself as bus-powered in
+        * the GetStatus(DEVICE) call.
+        */
+       if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
+               usb_gadget_set_selfpowered(gadget);
+
+       /* interface and string IDs start at zero via kzalloc.
+        * we force endpoints to start unassigned; few controller
+        * drivers will zero ep->driver_data.
+        */
+       usb_ep_autoconfig_reset(cdev->gadget);
+
+       /* composite gadget needs to assign strings for whole device (like
+        * serial number), register function drivers, potentially update
+        * power state and consumption, etc
+        */
+       status = composite->bind(cdev);
+       if (status < 0)
+               goto fail;
+
+       cdev->desc = *composite->dev;
+
+       /* standardized runtime overrides for device ID data */
+       if (idVendor)
+               cdev->desc.idVendor = cpu_to_le16(idVendor);
+       else
+               idVendor = le16_to_cpu(cdev->desc.idVendor);
+       if (idProduct)
+               cdev->desc.idProduct = cpu_to_le16(idProduct);
+       else
+               idProduct = le16_to_cpu(cdev->desc.idProduct);
+       if (bcdDevice)
+               cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+       else
+               bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
+
+       /* string overrides */
+       if (iManufacturer || !cdev->desc.iManufacturer) {
+               if (!iManufacturer && !composite->iManufacturer &&
+                   !*composite_manufacturer)
+                       snprintf(composite_manufacturer,
+                                sizeof composite_manufacturer,
+                                "%s %s with %s",
+                                init_utsname()->sysname,
+                                init_utsname()->release,
+                                gadget->name);
+
+               cdev->manufacturer_override =
+                       override_id(cdev, &cdev->desc.iManufacturer);
+       }
+
+       if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
+               cdev->product_override =
+                       override_id(cdev, &cdev->desc.iProduct);
+
+       if (iSerialNumber ||
+           (!cdev->desc.iSerialNumber && composite->iSerialNumber))
+               cdev->serial_override =
+                       override_id(cdev, &cdev->desc.iSerialNumber);
+
+       /* has userspace failed to provide a serial number? */
+       if (composite->needs_serial && !cdev->desc.iSerialNumber)
+               WARNING(cdev, "userspace failed to provide iSerialNumber\n");
+
+       /* finish up */
+       status = device_create_file(&gadget->dev, &dev_attr_suspended);
+       if (status)
+               goto fail;
+
+       INFO(cdev, "%s ready\n", composite->name);
+       return 0;
+
+fail:
+       composite_unbind(gadget);
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+composite_suspend(struct usb_gadget *gadget)
+{
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       struct usb_function             *f;
+
+       /* REVISIT:  should we have config level
+        * suspend/resume callbacks?
+        */
+       DBG(cdev, "suspend\n");
+       if (cdev->config) {
+               list_for_each_entry(f, &cdev->config->functions, list) {
+                       if (f->suspend)
+                               f->suspend(f);
+               }
+       }
+       if (composite->suspend)
+               composite->suspend(cdev);
+
+       cdev->suspended = 1;
+
+       usb_gadget_vbus_draw(gadget, 2);
+}
+
+static void
+composite_resume(struct usb_gadget *gadget)
+{
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       struct usb_function             *f;
+       u8                              maxpower;
+
+       /* REVISIT:  should we have config level
+        * suspend/resume callbacks?
+        */
+       DBG(cdev, "resume\n");
+       if (composite->resume)
+               composite->resume(cdev);
+       if (cdev->config) {
+               list_for_each_entry(f, &cdev->config->functions, list) {
+                       if (f->resume)
+                               f->resume(f);
+               }
+
+               maxpower = cdev->config->bMaxPower;
+
+               usb_gadget_vbus_draw(gadget, maxpower ?
+                       (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
+       }
+
+       cdev->suspended = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver composite_driver = {
+       .bind           = composite_bind,
+       .unbind         = composite_unbind,
+
+       .setup          = composite_setup,
+       .disconnect     = composite_disconnect,
+
+       .suspend        = composite_suspend,
+       .resume         = composite_resume,
+
+       .driver = {
+               .owner          = THIS_MODULE,
+       },
+};
+
+/**
+ * usb_composite_probe() - register a composite driver
+ * @driver: the driver to register
+ * @bind: the callback used to allocate resources that are shared across the
+ *     whole device, such as string IDs, and add its configurations using
+ *     @usb_add_config().  This may fail by returning a negative errno
+ *     value; it should return zero on successful initialization.
+ * Context: single threaded during gadget setup
+ *
+ * This function is used to register drivers using the composite driver
+ * framework.  The return value is zero, or a negative errno value.
+ * Those values normally come from the driver's @bind method, which does
+ * all the work of setting up the driver to match the hardware.
+ *
+ * On successful return, the gadget is ready to respond to requests from
+ * the host, unless one of its components invokes usb_gadget_disconnect()
+ * while it was binding.  That would usually be done in order to wait for
+ * some userspace participation.
+ */
+int usb_composite_probe(struct usb_composite_driver *driver)
+{
+       if (!driver || !driver->dev || composite || !driver->bind)
+               return -EINVAL;
+
+       if (!driver->name)
+               driver->name = "composite";
+       if (!driver->iProduct)
+               driver->iProduct = driver->name;
+       composite_driver.function =  (char *) driver->name;
+       composite_driver.driver.name = driver->name;
+       composite_driver.max_speed = driver->max_speed;
+       composite = driver;
+
+       return usb_gadget_probe_driver(&composite_driver);
+}
+
+/**
+ * usb_composite_unregister() - unregister a composite driver
+ * @driver: the driver to unregister
+ *
+ * This function is used to unregister drivers using the composite
+ * driver framework.
+ */
+void usb_composite_unregister(struct usb_composite_driver *driver)
+{
+       if (composite != driver)
+               return;
+       usb_gadget_unregister_driver(&composite_driver);
+}
+
+/**
+ * usb_composite_setup_continue() - Continue with the control transfer
+ * @cdev: the composite device who's control transfer was kept waiting
+ *
+ * This function must be called by the USB function driver to continue
+ * with the control transfer's data/status stage in case it had requested to
+ * delay the data/status stages. A USB function's setup handler (e.g. set_alt())
+ * can request the composite framework to delay the setup request's data/status
+ * stages by returning USB_GADGET_DELAYED_STATUS.
+ */
+void usb_composite_setup_continue(struct usb_composite_dev *cdev)
+{
+       int                     value;
+       struct usb_request      *req = cdev->req;
+       unsigned long           flags;
+
+       DBG(cdev, "%s\n", __func__);
+       spin_lock_irqsave(&cdev->lock, flags);
+
+       if (cdev->delayed_status == 0) {
+               WARN(cdev, "%s: Unexpected call\n", __func__);
+
+       } else if (--cdev->delayed_status == 0) {
+               DBG(cdev, "%s: Completing delayed status\n", __func__);
+               req->length = 0;
+               value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0) {
+                       DBG(cdev, "ep_queue --> %d\n", value);
+                       req->status = 0;
+                       composite_setup_complete(cdev->gadget->ep0, req);
+               }
+       }
+
+       spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
diff --git a/drivers/staging/ccg/composite.h b/drivers/staging/ccg/composite.h
new file mode 100644 (file)
index 0000000..19a5adf
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * composite.h -- framework for usb gadgets which are composite devices
+ *
+ * Copyright (C) 2006-2008 David Brownell
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef        __LINUX_USB_COMPOSITE_H
+#define        __LINUX_USB_COMPOSITE_H
+
+/*
+ * This framework is an optional layer on top of the USB Gadget interface,
+ * making it easier to build (a) Composite devices, supporting multiple
+ * functions within any single configuration, and (b) Multi-configuration
+ * devices, also supporting multiple functions but without necessarily
+ * having more than one function per configuration.
+ *
+ * Example:  a device with a single configuration supporting both network
+ * link and mass storage functions is a composite device.  Those functions
+ * might alternatively be packaged in individual configurations, but in
+ * the composite model the host can use both functions at the same time.
+ */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/*
+ * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
+ * wish to delay the data/status stages of the control transfer till they
+ * are ready. The control transfer will then be kept from completing till
+ * all the function drivers that requested for USB_GADGET_DELAYED_STAUS
+ * invoke usb_composite_setup_continue().
+ */
+#define USB_GADGET_DELAYED_STATUS       0x7fff /* Impossibly large value */
+
+struct usb_configuration;
+
+/**
+ * struct usb_function - describes one function of a configuration
+ * @name: For diagnostics, identifies the function.
+ * @strings: tables of strings, keyed by identifiers assigned during bind()
+ *     and by language IDs provided in control requests
+ * @descriptors: Table of full (or low) speed descriptors, using interface and
+ *     string identifiers assigned during @bind().  If this pointer is null,
+ *     the function will not be available at full speed (or at low speed).
+ * @hs_descriptors: Table of high speed descriptors, using interface and
+ *     string identifiers assigned during @bind().  If this pointer is null,
+ *     the function will not be available at high speed.
+ * @ss_descriptors: Table of super speed descriptors, using interface and
+ *     string identifiers assigned during @bind(). If this
+ *     pointer is null after initiation, the function will not
+ *     be available at super speed.
+ * @config: assigned when @usb_add_function() is called; this is the
+ *     configuration with which this function is associated.
+ * @bind: Before the gadget can register, all of its functions bind() to the
+ *     available resources including string and interface identifiers used
+ *     in interface or class descriptors; endpoints; I/O buffers; and so on.
+ * @unbind: Reverses @bind; called as a side effect of unregistering the
+ *     driver which added this function.
+ * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
+ *     initialize usb_ep.driver data at this time (when it is used).
+ *     Note that setting an interface to its current altsetting resets
+ *     interface state, and that all interfaces have a disabled state.
+ * @get_alt: Returns the active altsetting.  If this is not provided,
+ *     then only altsetting zero is supported.
+ * @disable: (REQUIRED) Indicates the function should be disabled.  Reasons
+ *     include host resetting or reconfiguring the gadget, and disconnection.
+ * @setup: Used for interface-specific control requests.
+ * @suspend: Notifies functions when the host stops sending USB traffic.
+ * @resume: Notifies functions when the host restarts USB traffic.
+ * @get_status: Returns function status as a reply to
+ *     GetStatus() request when the recepient is Interface.
+ * @func_suspend: callback to be called when
+ *     SetFeature(FUNCTION_SUSPEND) is reseived
+ *
+ * A single USB function uses one or more interfaces, and should in most
+ * cases support operation at both full and high speeds.  Each function is
+ * associated by @usb_add_function() with a one configuration; that function
+ * causes @bind() to be called so resources can be allocated as part of
+ * setting up a gadget driver.  Those resources include endpoints, which
+ * should be allocated using @usb_ep_autoconfig().
+ *
+ * To support dual speed operation, a function driver provides descriptors
+ * for both high and full speed operation.  Except in rare cases that don't
+ * involve bulk endpoints, each speed needs different endpoint descriptors.
+ *
+ * Function drivers choose their own strategies for managing instance data.
+ * The simplest strategy just declares it "static', which means the function
+ * can only be activated once.  If the function needs to be exposed in more
+ * than one configuration at a given speed, it needs to support multiple
+ * usb_function structures (one for each configuration).
+ *
+ * A more complex strategy might encapsulate a @usb_function structure inside
+ * a driver-specific instance structure to allows multiple activations.  An
+ * example of multiple activations might be a CDC ACM function that supports
+ * two or more distinct instances within the same configuration, providing
+ * several independent logical data links to a USB host.
+ */
+struct usb_function {
+       const char                      *name;
+       struct usb_gadget_strings       **strings;
+       struct usb_descriptor_header    **descriptors;
+       struct usb_descriptor_header    **hs_descriptors;
+       struct usb_descriptor_header    **ss_descriptors;
+
+       struct usb_configuration        *config;
+
+       /* REVISIT:  bind() functions can be marked __init, which
+        * makes trouble for section mismatch analysis.  See if
+        * we can't restructure things to avoid mismatching.
+        * Related:  unbind() may kfree() but bind() won't...
+        */
+
+       /* configuration management:  bind/unbind */
+       int                     (*bind)(struct usb_configuration *,
+                                       struct usb_function *);
+       void                    (*unbind)(struct usb_configuration *,
+                                       struct usb_function *);
+
+       /* runtime state management */
+       int                     (*set_alt)(struct usb_function *,
+                                       unsigned interface, unsigned alt);
+       int                     (*get_alt)(struct usb_function *,
+                                       unsigned interface);
+       void                    (*disable)(struct usb_function *);
+       int                     (*setup)(struct usb_function *,
+                                       const struct usb_ctrlrequest *);
+       void                    (*suspend)(struct usb_function *);
+       void                    (*resume)(struct usb_function *);
+
+       /* USB 3.0 additions */
+       int                     (*get_status)(struct usb_function *);
+       int                     (*func_suspend)(struct usb_function *,
+                                               u8 suspend_opt);
+       /* private: */
+       /* internals */
+       struct list_head                list;
+       DECLARE_BITMAP(endpoints, 32);
+};
+
+int usb_add_function(struct usb_configuration *, struct usb_function *);
+
+int usb_function_deactivate(struct usb_function *);
+int usb_function_activate(struct usb_function *);
+
+int usb_interface_id(struct usb_configuration *, struct usb_function *);
+
+int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
+                       struct usb_ep *_ep);
+
+#define        MAX_CONFIG_INTERFACES           16      /* arbitrary; max 255 */
+
+/**
+ * struct usb_configuration - represents one gadget configuration
+ * @label: For diagnostics, describes the configuration.
+ * @strings: Tables of strings, keyed by identifiers assigned during @bind()
+ *     and by language IDs provided in control requests.
+ * @descriptors: Table of descriptors preceding all function descriptors.
+ *     Examples include OTG and vendor-specific descriptors.
+ * @unbind: Reverses @bind; called as a side effect of unregistering the
+ *     driver which added this configuration.
+ * @setup: Used to delegate control requests that aren't handled by standard
+ *     device infrastructure or directed at a specific interface.
+ * @bConfigurationValue: Copied into configuration descriptor.
+ * @iConfiguration: Copied into configuration descriptor.
+ * @bmAttributes: Copied into configuration descriptor.
+ * @bMaxPower: Copied into configuration descriptor.
+ * @cdev: assigned by @usb_add_config() before calling @bind(); this is
+ *     the device associated with this configuration.
+ *
+ * Configurations are building blocks for gadget drivers structured around
+ * function drivers.  Simple USB gadgets require only one function and one
+ * configuration, and handle dual-speed hardware by always providing the same
+ * functionality.  Slightly more complex gadgets may have more than one
+ * single-function configuration at a given speed; or have configurations
+ * that only work at one speed.
+ *
+ * Composite devices are, by definition, ones with configurations which
+ * include more than one function.
+ *
+ * The lifecycle of a usb_configuration includes allocation, initialization
+ * of the fields described above, and calling @usb_add_config() to set up
+ * internal data and bind it to a specific device.  The configuration's
+ * @bind() method is then used to initialize all the functions and then
+ * call @usb_add_function() for them.
+ *
+ * Those functions would normally be independent of each other, but that's
+ * not mandatory.  CDC WMC devices are an example where functions often
+ * depend on other functions, with some functions subsidiary to others.
+ * Such interdependency may be managed in any way, so long as all of the
+ * descriptors complete by the time the composite driver returns from
+ * its bind() routine.
+ */
+struct usb_configuration {
+       const char                      *label;
+       struct usb_gadget_strings       **strings;
+       const struct usb_descriptor_header **descriptors;
+
+       /* REVISIT:  bind() functions can be marked __init, which
+        * makes trouble for section mismatch analysis.  See if
+        * we can't restructure things to avoid mismatching...
+        */
+
+       /* configuration management: unbind/setup */
+       void                    (*unbind)(struct usb_configuration *);
+       int                     (*setup)(struct usb_configuration *,
+                                       const struct usb_ctrlrequest *);
+
+       /* fields in the config descriptor */
+       u8                      bConfigurationValue;
+       u8                      iConfiguration;
+       u8                      bmAttributes;
+       u8                      bMaxPower;
+
+       struct usb_composite_dev        *cdev;
+
+       /* private: */
+       /* internals */
+       struct list_head        list;
+       struct list_head        functions;
+       u8                      next_interface_id;
+       unsigned                superspeed:1;
+       unsigned                highspeed:1;
+       unsigned                fullspeed:1;
+       struct usb_function     *interface[MAX_CONFIG_INTERFACES];
+};
+
+int usb_add_config(struct usb_composite_dev *,
+               struct usb_configuration *,
+               int (*)(struct usb_configuration *));
+
+void usb_remove_config(struct usb_composite_dev *,
+               struct usb_configuration *);
+
+/**
+ * struct usb_composite_driver - groups configurations into a gadget
+ * @name: For diagnostics, identifies the driver.
+ * @iProduct: Used as iProduct override if @dev->iProduct is not set.
+ *     If NULL value of @name is taken.
+ * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
+ *     not set. If NULL a default "<system> <release> with <udc>" value
+ *     will be used.
+ * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
+ *     not set.
+ * @dev: Template descriptor for the device, including default device
+ *     identifiers.
+ * @strings: tables of strings, keyed by identifiers assigned during @bind
+ *     and language IDs provided in control requests
+ * @max_speed: Highest speed the driver supports.
+ * @needs_serial: set to 1 if the gadget needs userspace to provide
+ *     a serial number.  If one is not provided, warning will be printed.
+ * @bind: (REQUIRED) Used to allocate resources that are shared across the
+ *     whole device, such as string IDs, and add its configurations using
+ *     @usb_add_config(). This may fail by returning a negative errno
+ *     value; it should return zero on successful initialization.
+ * @unbind: Reverses @bind; called as a side effect of unregistering
+ *     this driver.
+ * @disconnect: optional driver disconnect method
+ * @suspend: Notifies when the host stops sending USB traffic,
+ *     after function notifications
+ * @resume: Notifies configuration when the host restarts USB traffic,
+ *     before function notifications
+ *
+ * Devices default to reporting self powered operation.  Devices which rely
+ * on bus powered operation should report this in their @bind method.
+ *
+ * Before returning from @bind, various fields in the template descriptor
+ * may be overridden.  These include the idVendor/idProduct/bcdDevice values
+ * normally to bind the appropriate host side driver, and the three strings
+ * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
+ * meaningful device identifiers.  (The strings will not be defined unless
+ * they are defined in @dev and @strings.)  The correct ep0 maxpacket size
+ * is also reported, as defined by the underlying controller driver.
+ */
+struct usb_composite_driver {
+       const char                              *name;
+       const char                              *iProduct;
+       const char                              *iManufacturer;
+       const char                              *iSerialNumber;
+       const struct usb_device_descriptor      *dev;
+       struct usb_gadget_strings               **strings;
+       enum usb_device_speed                   max_speed;
+       unsigned                needs_serial:1;
+
+       int                     (*bind)(struct usb_composite_dev *cdev);
+       int                     (*unbind)(struct usb_composite_dev *);
+
+       void                    (*disconnect)(struct usb_composite_dev *);
+
+       /* global suspend hooks */
+       void                    (*suspend)(struct usb_composite_dev *);
+       void                    (*resume)(struct usb_composite_dev *);
+};
+
+extern int usb_composite_probe(struct usb_composite_driver *driver);
+extern void usb_composite_unregister(struct usb_composite_driver *driver);
+extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
+
+
+/**
+ * struct usb_composite_device - represents one composite usb gadget
+ * @gadget: read-only, abstracts the gadget's usb peripheral controller
+ * @req: used for control responses; buffer is pre-allocated
+ * @bufsiz: size of buffer pre-allocated in @req
+ * @config: the currently active configuration
+ *
+ * One of these devices is allocated and initialized before the
+ * associated device driver's bind() is called.
+ *
+ * OPEN ISSUE:  it appears that some WUSB devices will need to be
+ * built by combining a normal (wired) gadget with a wireless one.
+ * This revision of the gadget framework should probably try to make
+ * sure doing that won't hurt too much.
+ *
+ * One notion for how to handle Wireless USB devices involves:
+ * (a) a second gadget here, discovery mechanism TBD, but likely
+ *     needing separate "register/unregister WUSB gadget" calls;
+ * (b) updates to usb_gadget to include flags "is it wireless",
+ *     "is it wired", plus (presumably in a wrapper structure)
+ *     bandgroup and PHY info;
+ * (c) presumably a wireless_ep wrapping a usb_ep, and reporting
+ *     wireless-specific parameters like maxburst and maxsequence;
+ * (d) configurations that are specific to wireless links;
+ * (e) function drivers that understand wireless configs and will
+ *     support wireless for (additional) function instances;
+ * (f) a function to support association setup (like CBAF), not
+ *     necessarily requiring a wireless adapter;
+ * (g) composite device setup that can create one or more wireless
+ *     configs, including appropriate association setup support;
+ * (h) more, TBD.
+ */
+struct usb_composite_dev {
+       struct usb_gadget               *gadget;
+       struct usb_request              *req;
+       unsigned                        bufsiz;
+
+       struct usb_configuration        *config;
+
+       /* private: */
+       /* internals */
+       unsigned int                    suspended:1;
+       struct usb_device_descriptor    desc;
+       struct list_head                configs;
+       struct usb_composite_driver     *driver;
+       u8                              next_string_id;
+       u8                              manufacturer_override;
+       u8                              product_override;
+       u8                              serial_override;
+
+       /* the gadget driver won't enable the data pullup
+        * while the deactivation count is nonzero.
+        */
+       unsigned                        deactivations;
+
+       /* the composite driver won't complete the control transfer's
+        * data/status stages till delayed_status is zero.
+        */
+       int                             delayed_status;
+
+       /* protects deactivations and delayed_status counts*/
+       spinlock_t                      lock;
+};
+
+extern int usb_string_id(struct usb_composite_dev *c);
+extern int usb_string_ids_tab(struct usb_composite_dev *c,
+                             struct usb_string *str);
+extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
+
+
+/* messaging utils */
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
+
+#endif /* __LINUX_USB_COMPOSITE_H */
diff --git a/drivers/staging/ccg/config.c b/drivers/staging/ccg/config.c
new file mode 100644 (file)
index 0000000..7542a72
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * usb/gadget/config.c -- simplify building config descriptors
+ *
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+
+/**
+ * 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 (; NULL != *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;
+}
+
+/**
+ * usb_copy_descriptors - copy a vector of USB descriptors
+ * @src: null-terminated vector to copy
+ * Context: initialization code, which may sleep
+ *
+ * This makes a copy of a vector of USB descriptors.  Its primary use
+ * is to support usb_function objects which can have multiple copies,
+ * each needing different descriptors.  Functions may have static
+ * tables of descriptors, which are used as templates and customized
+ * with identifiers (for interfaces, strings, endpoints, and more)
+ * as needed by a given function instance.
+ */
+struct usb_descriptor_header **
+usb_copy_descriptors(struct usb_descriptor_header **src)
+{
+       struct usb_descriptor_header **tmp;
+       unsigned bytes;
+       unsigned n_desc;
+       void *mem;
+       struct usb_descriptor_header **ret;
+
+       /* count descriptors and their sizes; then add vector size */
+       for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
+               bytes += (*tmp)->bLength;
+       bytes += (n_desc + 1) * sizeof(*tmp);
+
+       mem = kmalloc(bytes, GFP_KERNEL);
+       if (!mem)
+               return NULL;
+
+       /* fill in pointers starting at "tmp",
+        * to descriptors copied starting at "mem";
+        * and return "ret"
+        */
+       tmp = mem;
+       ret = mem;
+       mem += (n_desc + 1) * sizeof(*tmp);
+       while (*src) {
+               memcpy(mem, *src, (*src)->bLength);
+               *tmp = mem;
+               tmp++;
+               mem += (*src)->bLength;
+               src++;
+       }
+       *tmp = NULL;
+
+       return ret;
+}
+
diff --git a/drivers/staging/ccg/epautoconf.c b/drivers/staging/ccg/epautoconf.c
new file mode 100644 (file)
index 0000000..51f3d42
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
+ *
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "gadget_chips.h"
+
+
+/* we must assign addresses for configurable endpoints (like net2280) */
+static unsigned epnum;
+
+// #define MANY_ENDPOINTS
+#ifdef MANY_ENDPOINTS
+/* more than 15 configurable endpoints */
+static unsigned in_epnum;
+#endif
+
+
+/*
+ * This should work with endpoints from controller drivers sharing the
+ * same endpoint naming convention.  By example:
+ *
+ *     - ep1, ep2, ... address is fixed, not direction or type
+ *     - ep1in, ep2out, ... address and direction are fixed, not type
+ *     - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
+ *     - ep1in-bulk, ep2out-iso, ... all three are fixed
+ *     - ep-* ... no functionality restrictions
+ *
+ * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
+ * Less common restrictions are implied by gadget_is_*().
+ *
+ * NOTE:  each endpoint is unidirectional, as specified by its USB
+ * descriptor; and isn't specific to a configuration or altsetting.
+ */
+static int
+ep_matches (
+       struct usb_gadget               *gadget,
+       struct usb_ep                   *ep,
+       struct usb_endpoint_descriptor  *desc,
+       struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+       u8              type;
+       const char      *tmp;
+       u16             max;
+
+       int             num_req_streams = 0;
+
+       /* endpoint already claimed? */
+       if (NULL != ep->driver_data)
+               return 0;
+
+       /* only support ep0 for portable CONTROL traffic */
+       type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+       if (USB_ENDPOINT_XFER_CONTROL == type)
+               return 0;
+
+       /* some other naming convention */
+       if ('e' != ep->name[0])
+               return 0;
+
+       /* type-restriction:  "-iso", "-bulk", or "-int".
+        * direction-restriction:  "in", "out".
+        */
+       if ('-' != ep->name[2]) {
+               tmp = strrchr (ep->name, '-');
+               if (tmp) {
+                       switch (type) {
+                       case USB_ENDPOINT_XFER_INT:
+                               /* bulk endpoints handle interrupt transfers,
+                                * except the toggle-quirky iso-synch kind
+                                */
+                               if ('s' == tmp[2])      // == "-iso"
+                                       return 0;
+                               /* for now, avoid PXA "interrupt-in";
+                                * it's documented as never using DATA1.
+                                */
+                               if (gadget_is_pxa (gadget)
+                                               && 'i' == tmp [1])
+                                       return 0;
+                               break;
+                       case USB_ENDPOINT_XFER_BULK:
+                               if ('b' != tmp[1])      // != "-bulk"
+                                       return 0;
+                               break;
+                       case USB_ENDPOINT_XFER_ISOC:
+                               if ('s' != tmp[2])      // != "-iso"
+                                       return 0;
+                       }
+               } else {
+                       tmp = ep->name + strlen (ep->name);
+               }
+
+               /* direction-restriction:  "..in-..", "out-.." */
+               tmp--;
+               if (!isdigit (*tmp)) {
+                       if (desc->bEndpointAddress & USB_DIR_IN) {
+                               if ('n' != *tmp)
+                                       return 0;
+                       } else {
+                               if ('t' != *tmp)
+                                       return 0;
+                       }
+               }
+       }
+
+       /*
+        * Get the number of required streams from the EP companion
+        * descriptor and see if the EP matches it
+        */
+       if (usb_endpoint_xfer_bulk(desc)) {
+               if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
+                       num_req_streams = ep_comp->bmAttributes & 0x1f;
+                       if (num_req_streams > ep->max_streams)
+                               return 0;
+               }
+
+       }
+
+       /*
+        * If the protocol driver hasn't yet decided on wMaxPacketSize
+        * and wants to know the maximum possible, provide the info.
+        */
+       if (desc->wMaxPacketSize == 0)
+               desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket);
+
+       /* endpoint maxpacket size is an input parameter, except for bulk
+        * where it's an output parameter representing the full speed limit.
+        * the usb spec fixes high speed bulk maxpacket at 512 bytes.
+        */
+       max = 0x7ff & usb_endpoint_maxp(desc);
+       switch (type) {
+       case USB_ENDPOINT_XFER_INT:
+               /* INT:  limit 64 bytes full speed, 1024 high/super speed */
+               if (!gadget_is_dualspeed(gadget) && max > 64)
+                       return 0;
+               /* FALLTHROUGH */
+
+       case USB_ENDPOINT_XFER_ISOC:
+               /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
+               if (ep->maxpacket < max)
+                       return 0;
+               if (!gadget_is_dualspeed(gadget) && max > 1023)
+                       return 0;
+
+               /* BOTH:  "high bandwidth" works only at high speed */
+               if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
+                       if (!gadget_is_dualspeed(gadget))
+                               return 0;
+                       /* configure your hardware with enough buffering!! */
+               }
+               break;
+       }
+
+       /* MATCH!! */
+
+       /* report address */
+       desc->bEndpointAddress &= USB_DIR_IN;
+       if (isdigit (ep->name [2])) {
+               u8      num = simple_strtoul (&ep->name [2], NULL, 10);
+               desc->bEndpointAddress |= num;
+#ifdef MANY_ENDPOINTS
+       } else if (desc->bEndpointAddress & USB_DIR_IN) {
+               if (++in_epnum > 15)
+                       return 0;
+               desc->bEndpointAddress = USB_DIR_IN | in_epnum;
+#endif
+       } else {
+               if (++epnum > 15)
+                       return 0;
+               desc->bEndpointAddress |= epnum;
+       }
+
+       /* report (variable) full speed bulk maxpacket */
+       if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
+               int size = ep->maxpacket;
+
+               /* min() doesn't work on bitfields with gcc-3.5 */
+               if (size > 64)
+                       size = 64;
+               desc->wMaxPacketSize = cpu_to_le16(size);
+       }
+       ep->address = desc->bEndpointAddress;
+       return 1;
+}
+
+static struct usb_ep *
+find_ep (struct usb_gadget *gadget, const char *name)
+{
+       struct usb_ep   *ep;
+
+       list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+               if (0 == strcmp (ep->name, name))
+                       return ep;
+       }
+       return NULL;
+}
+
+/**
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
+ *
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig_ss(
+       struct usb_gadget               *gadget,
+       struct usb_endpoint_descriptor  *desc,
+       struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+       struct usb_ep   *ep;
+       u8              type;
+
+       type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+       /* First, apply chip-specific "best usage" knowledge.
+        * This might make a good usb_gadget_ops hook ...
+        */
+       if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
+               /* ep-e, ep-f are PIO with only 64 byte fifos */
+               ep = find_ep (gadget, "ep-e");
+               if (ep && ep_matches(gadget, ep, desc, ep_comp))
+                       goto found_ep;
+               ep = find_ep (gadget, "ep-f");
+               if (ep && ep_matches(gadget, ep, desc, ep_comp))
+                       goto found_ep;
+
+       } else if (gadget_is_goku (gadget)) {
+               if (USB_ENDPOINT_XFER_INT == type) {
+                       /* single buffering is enough */
+                       ep = find_ep(gadget, "ep3-bulk");
+                       if (ep && ep_matches(gadget, ep, desc, ep_comp))
+                               goto found_ep;
+               } else if (USB_ENDPOINT_XFER_BULK == type
+                               && (USB_DIR_IN & desc->bEndpointAddress)) {
+                       /* DMA may be available */
+                       ep = find_ep(gadget, "ep2-bulk");
+                       if (ep && ep_matches(gadget, ep, desc,
+                                             ep_comp))
+                               goto found_ep;
+               }
+
+#ifdef CONFIG_BLACKFIN
+       } else if (gadget_is_musbhdrc(gadget)) {
+               if ((USB_ENDPOINT_XFER_BULK == type) ||
+                   (USB_ENDPOINT_XFER_ISOC == type)) {
+                       if (USB_DIR_IN & desc->bEndpointAddress)
+                               ep = find_ep (gadget, "ep5in");
+                       else
+                               ep = find_ep (gadget, "ep6out");
+               } else if (USB_ENDPOINT_XFER_INT == type) {
+                       if (USB_DIR_IN & desc->bEndpointAddress)
+                               ep = find_ep(gadget, "ep1in");
+                       else
+                               ep = find_ep(gadget, "ep2out");
+               } else
+                       ep = NULL;
+               if (ep && ep_matches(gadget, ep, desc, ep_comp))
+                       goto found_ep;
+#endif
+       }
+
+       /* Second, look at endpoints until an unclaimed one looks usable */
+       list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+               if (ep_matches(gadget, ep, desc, ep_comp))
+                       goto found_ep;
+       }
+
+       /* Fail */
+       return NULL;
+found_ep:
+       ep->desc = NULL;
+       ep->comp_desc = NULL;
+       return ep;
+}
+
+/**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *     initialized.  For periodic transfers, the maximum packet
+ *     size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+       struct usb_gadget               *gadget,
+       struct usb_endpoint_descriptor  *desc
+)
+{
+       return usb_ep_autoconfig_ss(gadget, desc, NULL);
+}
+
+
+/**
+ * usb_ep_autoconfig_reset - reset endpoint autoconfig state
+ * @gadget: device for which autoconfig state will be reset
+ *
+ * Use this for devices where one configuration may need to assign
+ * endpoint resources very differently from the next one.  It clears
+ * state such as ep->driver_data and the record of assigned endpoints
+ * used by usb_ep_autoconfig().
+ */
+void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+{
+       struct usb_ep   *ep;
+
+       list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+               ep->driver_data = NULL;
+       }
+#ifdef MANY_ENDPOINTS
+       in_epnum = 0;
+#endif
+       epnum = 0;
+}
+
diff --git a/drivers/staging/ccg/f_acm.c b/drivers/staging/ccg/f_acm.c
new file mode 100644 (file)
index 0000000..d672250
--- /dev/null
@@ -0,0 +1,814 @@
+/*
+ * f_acm.c -- USB CDC serial (ACM) function driver
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ * Copyright (C) 2009 by Samsung Electronics
+ * Author: Michal Nazarewicz (mina86@mina86.com)
+ *
+ * This software is 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.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "gadget_chips.h"
+
+
+/*
+ * This CDC ACM function support just wraps control functions and
+ * notifications around the generic serial-over-usb code.
+ *
+ * Because CDC ACM is standardized by the USB-IF, many host operating
+ * systems have drivers for it.  Accordingly, ACM is the preferred
+ * interop solution for serial-port type connections.  The control
+ * models are often not necessary, and in any case don't do much in
+ * this bare-bones implementation.
+ *
+ * Note that even MS-Windows has some support for ACM.  However, that
+ * support is somewhat broken because when you use ACM in a composite
+ * device, having multiple interfaces confuses the poor OS.  It doesn't
+ * seem to understand CDC Union descriptors.  The new "association"
+ * descriptors (roughly equivalent to CDC Unions) may sometimes help.
+ */
+
+struct f_acm {
+       struct gserial                  port;
+       u8                              ctrl_id, data_id;
+       u8                              port_num;
+
+       u8                              pending;
+
+       /* lock is mostly for pending and notify_req ... they get accessed
+        * by callbacks both from tty (open/close/break) under its spinlock,
+        * and notify_req.complete() which can't use that lock.
+        */
+       spinlock_t                      lock;
+
+       struct usb_ep                   *notify;
+       struct usb_request              *notify_req;
+
+       struct usb_cdc_line_coding      port_line_coding;       /* 8-N-1 etc */
+
+       /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
+       u16                             port_handshake_bits;
+#define ACM_CTRL_RTS   (1 << 1)        /* unused with full duplex */
+#define ACM_CTRL_DTR   (1 << 0)        /* host is ready for data r/w */
+
+       /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
+       u16                             serial_state;
+#define ACM_CTRL_OVERRUN       (1 << 6)
+#define ACM_CTRL_PARITY                (1 << 5)
+#define ACM_CTRL_FRAMING       (1 << 4)
+#define ACM_CTRL_RI            (1 << 3)
+#define ACM_CTRL_BRK           (1 << 2)
+#define ACM_CTRL_DSR           (1 << 1)
+#define ACM_CTRL_DCD           (1 << 0)
+};
+
+static inline struct f_acm *func_to_acm(struct usb_function *f)
+{
+       return container_of(f, struct f_acm, port.func);
+}
+
+static inline struct f_acm *port_to_acm(struct gserial *p)
+{
+       return container_of(p, struct f_acm, port);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* notification endpoint uses smallish and infrequent fixed-size messages */
+
+#define GS_LOG2_NOTIFY_INTERVAL                5       /* 1 << 5 == 32 msec */
+#define GS_NOTIFY_MAXPACKET            10      /* notification + 2 bytes */
+
+/* interface and class descriptors: */
+
+static struct usb_interface_assoc_descriptor
+acm_iad_descriptor = {
+       .bLength =              sizeof acm_iad_descriptor,
+       .bDescriptorType =      USB_DT_INTERFACE_ASSOCIATION,
+
+       /* .bFirstInterface =   DYNAMIC, */
+       .bInterfaceCount =      2,      // control + data
+       .bFunctionClass =       USB_CLASS_COMM,
+       .bFunctionSubClass =    USB_CDC_SUBCLASS_ACM,
+       .bFunctionProtocol =    USB_CDC_ACM_PROTO_AT_V25TER,
+       /* .iFunction =         DYNAMIC */
+};
+
+
+static struct usb_interface_descriptor acm_control_interface_desc = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       /* .bInterfaceNumber = DYNAMIC */
+       .bNumEndpoints =        1,
+       .bInterfaceClass =      USB_CLASS_COMM,
+       .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+       .bInterfaceProtocol =   USB_CDC_ACM_PROTO_AT_V25TER,
+       /* .iInterface = DYNAMIC */
+};
+
+static struct usb_interface_descriptor acm_data_interface_desc = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       /* .bInterfaceNumber = DYNAMIC */
+       .bNumEndpoints =        2,
+       .bInterfaceClass =      USB_CLASS_CDC_DATA,
+       .bInterfaceSubClass =   0,
+       .bInterfaceProtocol =   0,
+       /* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc acm_header_desc = {
+       .bLength =              sizeof(acm_header_desc),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
+       .bcdCDC =               cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor
+acm_call_mgmt_descriptor = {
+       .bLength =              sizeof(acm_call_mgmt_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+       .bmCapabilities =       0,
+       /* .bDataInterface = DYNAMIC */
+};
+
+static struct usb_cdc_acm_descriptor acm_descriptor = {
+       .bLength =              sizeof(acm_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+       .bmCapabilities =       USB_CDC_CAP_LINE,
+};
+
+static struct usb_cdc_union_desc acm_union_desc = {
+       .bLength =              sizeof(acm_union_desc),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_UNION_TYPE,
+       /* .bMasterInterface0 = DYNAMIC */
+       /* .bSlaveInterface0 =  DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor acm_fs_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(GS_NOTIFY_MAXPACKET),
+       .bInterval =            1 << GS_LOG2_NOTIFY_INTERVAL,
+};
+
+static struct usb_endpoint_descriptor acm_fs_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor acm_fs_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *acm_fs_function[] = {
+       (struct usb_descriptor_header *) &acm_iad_descriptor,
+       (struct usb_descriptor_header *) &acm_control_interface_desc,
+       (struct usb_descriptor_header *) &acm_header_desc,
+       (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &acm_descriptor,
+       (struct usb_descriptor_header *) &acm_union_desc,
+       (struct usb_descriptor_header *) &acm_fs_notify_desc,
+       (struct usb_descriptor_header *) &acm_data_interface_desc,
+       (struct usb_descriptor_header *) &acm_fs_in_desc,
+       (struct usb_descriptor_header *) &acm_fs_out_desc,
+       NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor acm_hs_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(GS_NOTIFY_MAXPACKET),
+       .bInterval =            GS_LOG2_NOTIFY_INTERVAL+4,
+};
+
+static struct usb_endpoint_descriptor acm_hs_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor acm_hs_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *acm_hs_function[] = {
+       (struct usb_descriptor_header *) &acm_iad_descriptor,
+       (struct usb_descriptor_header *) &acm_control_interface_desc,
+       (struct usb_descriptor_header *) &acm_header_desc,
+       (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &acm_descriptor,
+       (struct usb_descriptor_header *) &acm_union_desc,
+       (struct usb_descriptor_header *) &acm_hs_notify_desc,
+       (struct usb_descriptor_header *) &acm_data_interface_desc,
+       (struct usb_descriptor_header *) &acm_hs_in_desc,
+       (struct usb_descriptor_header *) &acm_hs_out_desc,
+       NULL,
+};
+
+static struct usb_endpoint_descriptor acm_ss_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor acm_ss_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
+       .bLength =              sizeof acm_ss_bulk_comp_desc,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *acm_ss_function[] = {
+       (struct usb_descriptor_header *) &acm_iad_descriptor,
+       (struct usb_descriptor_header *) &acm_control_interface_desc,
+       (struct usb_descriptor_header *) &acm_header_desc,
+       (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &acm_descriptor,
+       (struct usb_descriptor_header *) &acm_union_desc,
+       (struct usb_descriptor_header *) &acm_hs_notify_desc,
+       (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+       (struct usb_descriptor_header *) &acm_data_interface_desc,
+       (struct usb_descriptor_header *) &acm_ss_in_desc,
+       (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+       (struct usb_descriptor_header *) &acm_ss_out_desc,
+       (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+       NULL,
+};
+
+/* string descriptors: */
+
+#define ACM_CTRL_IDX   0
+#define ACM_DATA_IDX   1
+#define ACM_IAD_IDX    2
+
+/* static strings, in UTF-8 */
+static struct usb_string acm_string_defs[] = {
+       [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
+       [ACM_DATA_IDX].s = "CDC ACM Data",
+       [ACM_IAD_IDX ].s = "CDC Serial",
+       {  /* ZEROES END LIST */ },
+};
+
+static struct usb_gadget_strings acm_string_table = {
+       .language =             0x0409, /* en-us */
+       .strings =              acm_string_defs,
+};
+
+static struct usb_gadget_strings *acm_strings[] = {
+       &acm_string_table,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* ACM control ... data handling is delegated to tty library code.
+ * The main task of this function is to activate and deactivate
+ * that code based on device state; track parameters like line
+ * speed, handshake state, and so on; and issue notifications.
+ */
+
+static void acm_complete_set_line_coding(struct usb_ep *ep,
+               struct usb_request *req)
+{
+       struct f_acm    *acm = ep->driver_data;
+       struct usb_composite_dev *cdev = acm->port.func.config->cdev;
+
+       if (req->status != 0) {
+               DBG(cdev, "acm ttyGS%d completion, err %d\n",
+                               acm->port_num, req->status);
+               return;
+       }
+
+       /* normal completion */
+       if (req->actual != sizeof(acm->port_line_coding)) {
+               DBG(cdev, "acm ttyGS%d short resp, len %d\n",
+                               acm->port_num, req->actual);
+               usb_ep_set_halt(ep);
+       } else {
+               struct usb_cdc_line_coding      *value = req->buf;
+
+               /* REVISIT:  we currently just remember this data.
+                * If we change that, (a) validate it first, then
+                * (b) update whatever hardware needs updating,
+                * (c) worry about locking.  This is information on
+                * the order of 9600-8-N-1 ... most of which means
+                * nothing unless we control a real RS232 line.
+                */
+               acm->port_line_coding = *value;
+       }
+}
+
+static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+       struct f_acm            *acm = func_to_acm(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_request      *req = cdev->req;
+       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);
+
+       /* composite driver infrastructure handles everything except
+        * CDC class messages; interface activation uses set_alt().
+        *
+        * Note CDC spec table 4 lists the ACM request profile.  It requires
+        * encapsulated command support ... we don't handle any, and respond
+        * to them by stalling.  Options include get/set/clear comm features
+        * (not that useful) and SEND_BREAK.
+        */
+       switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+       /* SET_LINE_CODING ... just read and save what the host sends */
+       case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+                       | USB_CDC_REQ_SET_LINE_CODING:
+               if (w_length != sizeof(struct usb_cdc_line_coding)
+                               || w_index != acm->ctrl_id)
+                       goto invalid;
+
+               value = w_length;
+               cdev->gadget->ep0->driver_data = acm;
+               req->complete = acm_complete_set_line_coding;
+               break;
+
+       /* GET_LINE_CODING ... return what host sent, or initial value */
+       case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+                       | USB_CDC_REQ_GET_LINE_CODING:
+               if (w_index != acm->ctrl_id)
+                       goto invalid;
+
+               value = min_t(unsigned, w_length,
+                               sizeof(struct usb_cdc_line_coding));
+               memcpy(req->buf, &acm->port_line_coding, value);
+               break;
+
+       /* SET_CONTROL_LINE_STATE ... save what the host sent */
+       case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+                       | USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+               if (w_index != acm->ctrl_id)
+                       goto invalid;
+
+               value = 0;
+
+               /* FIXME we should not allow data to flow until the
+                * host sets the ACM_CTRL_DTR bit; and when it clears
+                * that bit, we should return to that no-flow state.
+                */
+               acm->port_handshake_bits = w_value;
+               break;
+
+       default:
+invalid:
+               VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+       }
+
+       /* respond with data transfer or status phase? */
+       if (value >= 0) {
+               DBG(cdev, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
+                       acm->port_num, ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+               req->zero = 0;
+               req->length = value;
+               value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0)
+                       ERROR(cdev, "acm response on ttyGS%d, err %d\n",
+                                       acm->port_num, value);
+       }
+
+       /* device either stalls (value < 0) or reports success */
+       return value;
+}
+
+static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct f_acm            *acm = func_to_acm(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+
+       /* we know alt == 0, so this is an activation or a reset */
+
+       if (intf == acm->ctrl_id) {
+               if (acm->notify->driver_data) {
+                       VDBG(cdev, "reset acm control interface %d\n", intf);
+                       usb_ep_disable(acm->notify);
+               } else {
+                       VDBG(cdev, "init acm ctrl interface %d\n", intf);
+                       if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+                               return -EINVAL;
+               }
+               usb_ep_enable(acm->notify);
+               acm->notify->driver_data = acm;
+
+       } else if (intf == acm->data_id) {
+               if (acm->port.in->driver_data) {
+                       DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
+                       gserial_disconnect(&acm->port);
+               }
+               if (!acm->port.in->desc || !acm->port.out->desc) {
+                       DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
+                       if (config_ep_by_speed(cdev->gadget, f,
+                                              acm->port.in) ||
+                           config_ep_by_speed(cdev->gadget, f,
+                                              acm->port.out)) {
+                               acm->port.in->desc = NULL;
+                               acm->port.out->desc = NULL;
+                               return -EINVAL;
+                       }
+               }
+               gserial_connect(&acm->port, acm->port_num);
+
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static void acm_disable(struct usb_function *f)
+{
+       struct f_acm    *acm = func_to_acm(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+
+       DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
+       gserial_disconnect(&acm->port);
+       usb_ep_disable(acm->notify);
+       acm->notify->driver_data = NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * acm_cdc_notify - issue CDC notification to host
+ * @acm: wraps host to be notified
+ * @type: notification type
+ * @value: Refer to cdc specs, wValue field.
+ * @data: data to be sent
+ * @length: size of data
+ * Context: irqs blocked, acm->lock held, acm_notify_req non-null
+ *
+ * Returns zero on success or a negative errno.
+ *
+ * See section 6.3.5 of the CDC 1.1 specification for information
+ * about the only notification we issue:  SerialState change.
+ */
+static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
+               void *data, unsigned length)
+{
+       struct usb_ep                   *ep = acm->notify;
+       struct usb_request              *req;
+       struct usb_cdc_notification     *notify;
+       const unsigned                  len = sizeof(*notify) + length;
+       void                            *buf;
+       int                             status;
+
+       req = acm->notify_req;
+       acm->notify_req = NULL;
+       acm->pending = false;
+
+       req->length = len;
+       notify = req->buf;
+       buf = notify + 1;
+
+       notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+                       | USB_RECIP_INTERFACE;
+       notify->bNotificationType = type;
+       notify->wValue = cpu_to_le16(value);
+       notify->wIndex = cpu_to_le16(acm->ctrl_id);
+       notify->wLength = cpu_to_le16(length);
+       memcpy(buf, data, length);
+
+       /* ep_queue() can complete immediately if it fills the fifo... */
+       spin_unlock(&acm->lock);
+       status = usb_ep_queue(ep, req, GFP_ATOMIC);
+       spin_lock(&acm->lock);
+
+       if (status < 0) {
+               ERROR(acm->port.func.config->cdev,
+                               "acm ttyGS%d can't notify serial state, %d\n",
+                               acm->port_num, status);
+               acm->notify_req = req;
+       }
+
+       return status;
+}
+
+static int acm_notify_serial_state(struct f_acm *acm)
+{
+       struct usb_composite_dev *cdev = acm->port.func.config->cdev;
+       int                     status;
+
+       spin_lock(&acm->lock);
+       if (acm->notify_req) {
+               DBG(cdev, "acm ttyGS%d serial state %04x\n",
+                               acm->port_num, acm->serial_state);
+               status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
+                               0, &acm->serial_state, sizeof(acm->serial_state));
+       } else {
+               acm->pending = true;
+               status = 0;
+       }
+       spin_unlock(&acm->lock);
+       return status;
+}
+
+static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_acm            *acm = req->context;
+       u8                      doit = false;
+
+       /* on this call path we do NOT hold the port spinlock,
+        * which is why ACM needs its own spinlock
+        */
+       spin_lock(&acm->lock);
+       if (req->status != -ESHUTDOWN)
+               doit = acm->pending;
+       acm->notify_req = req;
+       spin_unlock(&acm->lock);
+
+       if (doit)
+               acm_notify_serial_state(acm);
+}
+
+/* connect == the TTY link is open */
+
+static void acm_connect(struct gserial *port)
+{
+       struct f_acm            *acm = port_to_acm(port);
+
+       acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
+       acm_notify_serial_state(acm);
+}
+
+static void acm_disconnect(struct gserial *port)
+{
+       struct f_acm            *acm = port_to_acm(port);
+
+       acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
+       acm_notify_serial_state(acm);
+}
+
+static int acm_send_break(struct gserial *port, int duration)
+{
+       struct f_acm            *acm = port_to_acm(port);
+       u16                     state;
+
+       state = acm->serial_state;
+       state &= ~ACM_CTRL_BRK;
+       if (duration)
+               state |= ACM_CTRL_BRK;
+
+       acm->serial_state = state;
+       return acm_notify_serial_state(acm);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ACM function driver setup/binding */
+static int
+acm_bind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct usb_composite_dev *cdev = c->cdev;
+       struct f_acm            *acm = func_to_acm(f);
+       int                     status;
+       struct usb_ep           *ep;
+
+       /* allocate instance-specific interface IDs, and patch descriptors */
+       status = usb_interface_id(c, f);
+       if (status < 0)
+               goto fail;
+       acm->ctrl_id = status;
+       acm_iad_descriptor.bFirstInterface = status;
+
+       acm_control_interface_desc.bInterfaceNumber = status;
+       acm_union_desc .bMasterInterface0 = status;
+
+       status = usb_interface_id(c, f);
+       if (status < 0)
+               goto fail;
+       acm->data_id = status;
+
+       acm_data_interface_desc.bInterfaceNumber = status;
+       acm_union_desc.bSlaveInterface0 = status;
+       acm_call_mgmt_descriptor.bDataInterface = status;
+
+       status = -ENODEV;
+
+       /* allocate instance-specific endpoints */
+       ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
+       if (!ep)
+               goto fail;
+       acm->port.in = ep;
+       ep->driver_data = cdev; /* claim */
+
+       ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
+       if (!ep)
+               goto fail;
+       acm->port.out = ep;
+       ep->driver_data = cdev; /* claim */
+
+       ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
+       if (!ep)
+               goto fail;
+       acm->notify = ep;
+       ep->driver_data = cdev; /* claim */
+
+       /* allocate notification */
+       acm->notify_req = gs_alloc_req(ep,
+                       sizeof(struct usb_cdc_notification) + 2,
+                       GFP_KERNEL);
+       if (!acm->notify_req)
+               goto fail;
+
+       acm->notify_req->complete = acm_cdc_notify_complete;
+       acm->notify_req->context = acm;
+
+       /* copy descriptors */
+       f->descriptors = usb_copy_descriptors(acm_fs_function);
+       if (!f->descriptors)
+               goto fail;
+
+       /* support all relevant hardware speeds... we expect that when
+        * hardware is dual speed, all bulk-capable endpoints work at
+        * both speeds
+        */
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
+               acm_hs_in_desc.bEndpointAddress =
+                               acm_fs_in_desc.bEndpointAddress;
+               acm_hs_out_desc.bEndpointAddress =
+                               acm_fs_out_desc.bEndpointAddress;
+               acm_hs_notify_desc.bEndpointAddress =
+                               acm_fs_notify_desc.bEndpointAddress;
+
+               /* copy descriptors */
+               f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
+       }
+       if (gadget_is_superspeed(c->cdev->gadget)) {
+               acm_ss_in_desc.bEndpointAddress =
+                       acm_fs_in_desc.bEndpointAddress;
+               acm_ss_out_desc.bEndpointAddress =
+                       acm_fs_out_desc.bEndpointAddress;
+
+               /* copy descriptors, and track endpoint copies */
+               f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
+               if (!f->ss_descriptors)
+                       goto fail;
+       }
+
+       DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+                       acm->port_num,
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
+                       gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+                       acm->port.in->name, acm->port.out->name,
+                       acm->notify->name);
+       return 0;
+
+fail:
+       if (acm->notify_req)
+               gs_free_req(acm->notify, acm->notify_req);
+
+       /* we might as well release our claims on endpoints */
+       if (acm->notify)
+               acm->notify->driver_data = NULL;
+       if (acm->port.out)
+               acm->port.out->driver_data = NULL;
+       if (acm->port.in)
+               acm->port.in->driver_data = NULL;
+
+       ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
+
+       return status;
+}
+
+static void
+acm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct f_acm            *acm = func_to_acm(f);
+
+       if (gadget_is_dualspeed(c->cdev->gadget))
+               usb_free_descriptors(f->hs_descriptors);
+       if (gadget_is_superspeed(c->cdev->gadget))
+               usb_free_descriptors(f->ss_descriptors);
+       usb_free_descriptors(f->descriptors);
+       gs_free_req(acm->notify, acm->notify_req);
+       kfree(acm);
+}
+
+/* Some controllers can't support CDC ACM ... */
+static inline bool can_support_cdc(struct usb_configuration *c)
+{
+       /* everything else is *probably* fine ... */
+       return true;
+}
+
+/**
+ * acm_bind_config - add a CDC ACM function to a configuration
+ * @c: the configuration to support the CDC ACM instance
+ * @port_num: /dev/ttyGS* port this interface will use
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gserial_setup() with enough ports to
+ * handle all the ones it binds.  Caller is also responsible
+ * for calling @gserial_cleanup() before module unload.
+ */
+int acm_bind_config(struct usb_configuration *c, u8 port_num)
+{
+       struct f_acm    *acm;
+       int             status;
+
+       if (!can_support_cdc(c))
+               return -EINVAL;
+
+       /* REVISIT might want instance-specific strings to help
+        * distinguish instances ...
+        */
+
+       /* maybe allocate device-global string IDs, and patch descriptors */
+       if (acm_string_defs[ACM_CTRL_IDX].id == 0) {
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               acm_string_defs[ACM_CTRL_IDX].id = status;
+
+               acm_control_interface_desc.iInterface = status;
+
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               acm_string_defs[ACM_DATA_IDX].id = status;
+
+               acm_data_interface_desc.iInterface = status;
+
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               acm_string_defs[ACM_IAD_IDX].id = status;
+
+               acm_iad_descriptor.iFunction = status;
+       }
+
+       /* allocate and initialize one new instance */
+       acm = kzalloc(sizeof *acm, GFP_KERNEL);
+       if (!acm)
+               return -ENOMEM;
+
+       spin_lock_init(&acm->lock);
+
+       acm->port_num = port_num;
+
+       acm->port.connect = acm_connect;
+       acm->port.disconnect = acm_disconnect;
+       acm->port.send_break = acm_send_break;
+
+       acm->port.func.name = "acm";
+       acm->port.func.strings = acm_strings;
+       /* descriptors are per-instance copies */
+       acm->port.func.bind = acm_bind;
+       acm->port.func.unbind = acm_unbind;
+       acm->port.func.set_alt = acm_set_alt;
+       acm->port.func.setup = acm_setup;
+       acm->port.func.disable = acm_disable;
+
+       status = usb_add_function(c, &acm->port.func);
+       if (status)
+               kfree(acm);
+       return status;
+}
diff --git a/drivers/staging/ccg/f_fs.c b/drivers/staging/ccg/f_fs.c
new file mode 100644 (file)
index 0000000..8adc79d
--- /dev/null
@@ -0,0 +1,2455 @@
+/*
+ * f_fs.c -- user mode file system API for USB composite function controllers
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Author: Michal Nazarewicz <mina86@mina86.com>
+ *
+ * Based on inode.c (GadgetFS) which was:
+ * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003 Agilent Technologies
+ *
+ * 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.
+ */
+
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/blkdev.h>
+#include <linux/pagemap.h>
+#include <linux/export.h>
+#include <linux/hid.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/functionfs.h>
+
+
+#define FUNCTIONFS_MAGIC       0xa647361 /* Chosen by a honest dice roll ;) */
+
+
+/* Debugging ****************************************************************/
+
+#ifdef VERBOSE_DEBUG
+#  define pr_vdebug pr_debug
+#  define ffs_dump_mem(prefix, ptr, len) \
+       print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
+#else
+#  define pr_vdebug(...)                 do { } while (0)
+#  define ffs_dump_mem(prefix, ptr, len) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define ENTER()    pr_vdebug("%s()\n", __func__)
+
+
+/* The data structure and setup file ****************************************/
+
+enum ffs_state {
+       /*
+        * Waiting for descriptors and strings.
+        *
+        * In this state no open(2), read(2) or write(2) on epfiles
+        * may succeed (which should not be the problem as there
+        * should be no such files opened in the first place).
+        */
+       FFS_READ_DESCRIPTORS,
+       FFS_READ_STRINGS,
+
+       /*
+        * We've got descriptors and strings.  We are or have called
+        * functionfs_ready_callback().  functionfs_bind() may have
+        * been called but we don't know.
+        *
+        * This is the only state in which operations on epfiles may
+        * succeed.
+        */
+       FFS_ACTIVE,
+
+       /*
+        * All endpoints have been closed.  This state is also set if
+        * we encounter an unrecoverable error.  The only
+        * unrecoverable error is situation when after reading strings
+        * from user space we fail to initialise epfiles or
+        * functionfs_ready_callback() returns with error (<0).
+        *
+        * In this state no open(2), read(2) or write(2) (both on ep0
+        * as well as epfile) may succeed (at this point epfiles are
+        * unlinked and all closed so this is not a problem; ep0 is
+        * also closed but ep0 file exists and so open(2) on ep0 must
+        * fail).
+        */
+       FFS_CLOSING
+};
+
+
+enum ffs_setup_state {
+       /* There is no setup request pending. */
+       FFS_NO_SETUP,
+       /*
+        * User has read events and there was a setup request event
+        * there.  The next read/write on ep0 will handle the
+        * request.
+        */
+       FFS_SETUP_PENDING,
+       /*
+        * There was event pending but before user space handled it
+        * some other event was introduced which canceled existing
+        * setup.  If this state is set read/write on ep0 return
+        * -EIDRM.  This state is only set when adding event.
+        */
+       FFS_SETUP_CANCELED
+};
+
+
+
+struct ffs_epfile;
+struct ffs_function;
+
+struct ffs_data {
+       struct usb_gadget               *gadget;
+
+       /*
+        * Protect access read/write operations, only one read/write
+        * at a time.  As a consequence protects ep0req and company.
+        * While setup request is being processed (queued) this is
+        * held.
+        */
+       struct mutex                    mutex;
+
+       /*
+        * Protect access to endpoint related structures (basically
+        * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
+        * endpoint zero.
+        */
+       spinlock_t                      eps_lock;
+
+       /*
+        * XXX REVISIT do we need our own request? Since we are not
+        * handling setup requests immediately user space may be so
+        * slow that another setup will be sent to the gadget but this
+        * time not to us but another function and then there could be
+        * a race.  Is that the case? Or maybe we can use cdev->req
+        * after all, maybe we just need some spinlock for that?
+        */
+       struct usb_request              *ep0req;                /* P: mutex */
+       struct completion               ep0req_completion;      /* P: mutex */
+       int                             ep0req_status;          /* P: mutex */
+
+       /* reference counter */
+       atomic_t                        ref;
+       /* how many files are opened (EP0 and others) */
+       atomic_t                        opened;
+
+       /* EP0 state */
+       enum ffs_state                  state;
+
+       /*
+        * Possible transitions:
+        * + FFS_NO_SETUP       -> FFS_SETUP_PENDING  -- P: ev.waitq.lock
+        *               happens only in ep0 read which is P: mutex
+        * + FFS_SETUP_PENDING  -> FFS_NO_SETUP       -- P: ev.waitq.lock
+        *               happens only in ep0 i/o  which is P: mutex
+        * + FFS_SETUP_PENDING  -> FFS_SETUP_CANCELED -- P: ev.waitq.lock
+        * + FFS_SETUP_CANCELED -> FFS_NO_SETUP       -- cmpxchg
+        */
+       enum ffs_setup_state            setup_state;
+
+#define FFS_SETUP_STATE(ffs)                                   \
+       ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state,     \
+                                      FFS_SETUP_CANCELED, FFS_NO_SETUP))
+
+       /* Events & such. */
+       struct {
+               u8                              types[4];
+               unsigned short                  count;
+               /* XXX REVISIT need to update it in some places, or do we? */
+               unsigned short                  can_stall;
+               struct usb_ctrlrequest          setup;
+
+               wait_queue_head_t               waitq;
+       } ev; /* the whole structure, P: ev.waitq.lock */
+
+       /* Flags */
+       unsigned long                   flags;
+#define FFS_FL_CALL_CLOSED_CALLBACK 0
+#define FFS_FL_BOUND                1
+
+       /* Active function */
+       struct ffs_function             *func;
+
+       /*
+        * Device name, write once when file system is mounted.
+        * Intended for user to read if she wants.
+        */
+       const char                      *dev_name;
+       /* Private data for our user (ie. gadget).  Managed by user. */
+       void                            *private_data;
+
+       /* filled by __ffs_data_got_descs() */
+       /*
+        * Real descriptors are 16 bytes after raw_descs (so you need
+        * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
+        * first full speed descriptor).  raw_descs_length and
+        * raw_fs_descs_length do not have those 16 bytes added.
+        */
+       const void                      *raw_descs;
+       unsigned                        raw_descs_length;
+       unsigned                        raw_fs_descs_length;
+       unsigned                        fs_descs_count;
+       unsigned                        hs_descs_count;
+
+       unsigned short                  strings_count;
+       unsigned short                  interfaces_count;
+       unsigned short                  eps_count;
+       unsigned short                  _pad1;
+
+       /* filled by __ffs_data_got_strings() */
+       /* ids in stringtabs are set in functionfs_bind() */
+       const void                      *raw_strings;
+       struct usb_gadget_strings       **stringtabs;
+
+       /*
+        * File system's super block, write once when file system is
+        * mounted.
+        */
+       struct super_block              *sb;
+
+       /* File permissions, written once when fs is mounted */
+       struct ffs_file_perms {
+               umode_t                         mode;
+               uid_t                           uid;
+               gid_t                           gid;
+       }                               file_perms;
+
+       /*
+        * The endpoint files, filled by ffs_epfiles_create(),
+        * destroyed by ffs_epfiles_destroy().
+        */
+       struct ffs_epfile               *epfiles;
+};
+
+/* Reference counter handling */
+static void ffs_data_get(struct ffs_data *ffs);
+static void ffs_data_put(struct ffs_data *ffs);
+/* Creates new ffs_data object. */
+static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
+
+/* Opened counter handling. */
+static void ffs_data_opened(struct ffs_data *ffs);
+static void ffs_data_closed(struct ffs_data *ffs);
+
+/* Called with ffs->mutex held; take over ownership of data. */
+static int __must_check
+__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
+static int __must_check
+__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
+
+
+/* The function structure ***************************************************/
+
+struct ffs_ep;
+
+struct ffs_function {
+       struct usb_configuration        *conf;
+       struct usb_gadget               *gadget;
+       struct ffs_data                 *ffs;
+
+       struct ffs_ep                   *eps;
+       u8                              eps_revmap[16];
+       short                           *interfaces_nums;
+
+       struct usb_function             function;
+};
+
+
+static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
+{
+       return container_of(f, struct ffs_function, function);
+}
+
+static void ffs_func_free(struct ffs_function *func);
+
+static void ffs_func_eps_disable(struct ffs_function *func);
+static int __must_check ffs_func_eps_enable(struct ffs_function *func);
+
+static int ffs_func_bind(struct usb_configuration *,
+                        struct usb_function *);
+static void ffs_func_unbind(struct usb_configuration *,
+                           struct usb_function *);
+static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
+static void ffs_func_disable(struct usb_function *);
+static int ffs_func_setup(struct usb_function *,
+                         const struct usb_ctrlrequest *);
+static void ffs_func_suspend(struct usb_function *);
+static void ffs_func_resume(struct usb_function *);
+
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
+
+
+/* The endpoints structures *************************************************/
+
+struct ffs_ep {
+       struct usb_ep                   *ep;    /* P: ffs->eps_lock */
+       struct usb_request              *req;   /* P: epfile->mutex */
+
+       /* [0]: full speed, [1]: high speed */
+       struct usb_endpoint_descriptor  *descs[2];
+
+       u8                              num;
+
+       int                             status; /* P: epfile->mutex */
+};
+
+struct ffs_epfile {
+       /* Protects ep->ep and ep->req. */
+       struct mutex                    mutex;
+       wait_queue_head_t               wait;
+
+       struct ffs_data                 *ffs;
+       struct ffs_ep                   *ep;    /* P: ffs->eps_lock */
+
+       struct dentry                   *dentry;
+
+       char                            name[5];
+
+       unsigned char                   in;     /* P: ffs->eps_lock */
+       unsigned char                   isoc;   /* P: ffs->eps_lock */
+
+       unsigned char                   _pad;
+};
+
+static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
+
+static struct inode *__must_check
+ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
+                  const struct file_operations *fops,
+                  struct dentry **dentry_p);
+
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+       __attribute__((warn_unused_result, nonnull));
+static char *ffs_prepare_buffer(const char * __user buf, size_t len)
+       __attribute__((warn_unused_result, nonnull));
+
+
+/* Control file aka ep0 *****************************************************/
+
+static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct ffs_data *ffs = req->context;
+
+       complete_all(&ffs->ep0req_completion);
+}
+
+static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
+{
+       struct usb_request *req = ffs->ep0req;
+       int ret;
+
+       req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
+
+       spin_unlock_irq(&ffs->ev.waitq.lock);
+
+       req->buf      = data;
+       req->length   = len;
+
+       /*
+        * UDC layer requires to provide a buffer even for ZLP, but should
+        * not use it at all. Let's provide some poisoned pointer to catch
+        * possible bug in the driver.
+        */
+       if (req->buf == NULL)
+               req->buf = (void *)0xDEADBABE;
+
+       INIT_COMPLETION(ffs->ep0req_completion);
+
+       ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
+       if (unlikely(ret < 0))
+               return ret;
+
+       ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
+       if (unlikely(ret)) {
+               usb_ep_dequeue(ffs->gadget->ep0, req);
+               return -EINTR;
+       }
+
+       ffs->setup_state = FFS_NO_SETUP;
+       return ffs->ep0req_status;
+}
+
+static int __ffs_ep0_stall(struct ffs_data *ffs)
+{
+       if (ffs->ev.can_stall) {
+               pr_vdebug("ep0 stall\n");
+               usb_ep_set_halt(ffs->gadget->ep0);
+               ffs->setup_state = FFS_NO_SETUP;
+               return -EL2HLT;
+       } else {
+               pr_debug("bogus ep0 stall!\n");
+               return -ESRCH;
+       }
+}
+
+static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
+                            size_t len, loff_t *ptr)
+{
+       struct ffs_data *ffs = file->private_data;
+       ssize_t ret;
+       char *data;
+
+       ENTER();
+
+       /* Fast check if setup was canceled */
+       if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+               return -EIDRM;
+
+       /* Acquire mutex */
+       ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+       if (unlikely(ret < 0))
+               return ret;
+
+       /* Check state */
+       switch (ffs->state) {
+       case FFS_READ_DESCRIPTORS:
+       case FFS_READ_STRINGS:
+               /* Copy data */
+               if (unlikely(len < 16)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               data = ffs_prepare_buffer(buf, len);
+               if (IS_ERR(data)) {
+                       ret = PTR_ERR(data);
+                       break;
+               }
+
+               /* Handle data */
+               if (ffs->state == FFS_READ_DESCRIPTORS) {
+                       pr_info("read descriptors\n");
+                       ret = __ffs_data_got_descs(ffs, data, len);
+                       if (unlikely(ret < 0))
+                               break;
+
+                       ffs->state = FFS_READ_STRINGS;
+                       ret = len;
+               } else {
+                       pr_info("read strings\n");
+                       ret = __ffs_data_got_strings(ffs, data, len);
+                       if (unlikely(ret < 0))
+                               break;
+
+                       ret = ffs_epfiles_create(ffs);
+                       if (unlikely(ret)) {
+                               ffs->state = FFS_CLOSING;
+                               break;
+                       }
+
+                       ffs->state = FFS_ACTIVE;
+                       mutex_unlock(&ffs->mutex);
+
+                       ret = functionfs_ready_callback(ffs);
+                       if (unlikely(ret < 0)) {
+                               ffs->state = FFS_CLOSING;
+                               return ret;
+                       }
+
+                       set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
+                       return len;
+               }
+               break;
+
+       case FFS_ACTIVE:
+               data = NULL;
+               /*
+                * We're called from user space, we can use _irq
+                * rather then _irqsave
+                */
+               spin_lock_irq(&ffs->ev.waitq.lock);
+               switch (FFS_SETUP_STATE(ffs)) {
+               case FFS_SETUP_CANCELED:
+                       ret = -EIDRM;
+                       goto done_spin;
+
+               case FFS_NO_SETUP:
+                       ret = -ESRCH;
+                       goto done_spin;
+
+               case FFS_SETUP_PENDING:
+                       break;
+               }
+
+               /* FFS_SETUP_PENDING */
+               if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
+                       spin_unlock_irq(&ffs->ev.waitq.lock);
+                       ret = __ffs_ep0_stall(ffs);
+                       break;
+               }
+
+               /* FFS_SETUP_PENDING and not stall */
+               len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+               spin_unlock_irq(&ffs->ev.waitq.lock);
+
+               data = ffs_prepare_buffer(buf, len);
+               if (IS_ERR(data)) {
+                       ret = PTR_ERR(data);
+                       break;
+               }
+
+               spin_lock_irq(&ffs->ev.waitq.lock);
+
+               /*
+                * We are guaranteed to be still in FFS_ACTIVE state
+                * but the state of setup could have changed from
+                * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
+                * to check for that.  If that happened we copied data
+                * from user space in vain but it's unlikely.
+                *
+                * For sure we are not in FFS_NO_SETUP since this is
+                * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
+                * transition can be performed and it's protected by
+                * mutex.
+                */
+               if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+                       ret = -EIDRM;
+done_spin:
+                       spin_unlock_irq(&ffs->ev.waitq.lock);
+               } else {
+                       /* unlocks spinlock */
+                       ret = __ffs_ep0_queue_wait(ffs, data, len);
+               }
+               kfree(data);
+               break;
+
+       default:
+               ret = -EBADFD;
+               break;
+       }
+
+       mutex_unlock(&ffs->mutex);
+       return ret;
+}
+
+static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
+                                    size_t n)
+{
+       /*
+        * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
+        * to release them.
+        */
+       struct usb_functionfs_event events[n];
+       unsigned i = 0;
+
+       memset(events, 0, sizeof events);
+
+       do {
+               events[i].type = ffs->ev.types[i];
+               if (events[i].type == FUNCTIONFS_SETUP) {
+                       events[i].u.setup = ffs->ev.setup;
+                       ffs->setup_state = FFS_SETUP_PENDING;
+               }
+       } while (++i < n);
+
+       if (n < ffs->ev.count) {
+               ffs->ev.count -= n;
+               memmove(ffs->ev.types, ffs->ev.types + n,
+                       ffs->ev.count * sizeof *ffs->ev.types);
+       } else {
+               ffs->ev.count = 0;
+       }
+
+       spin_unlock_irq(&ffs->ev.waitq.lock);
+       mutex_unlock(&ffs->mutex);
+
+       return unlikely(__copy_to_user(buf, events, sizeof events))
+               ? -EFAULT : sizeof events;
+}
+
+static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
+                           size_t len, loff_t *ptr)
+{
+       struct ffs_data *ffs = file->private_data;
+       char *data = NULL;
+       size_t n;
+       int ret;
+
+       ENTER();
+
+       /* Fast check if setup was canceled */
+       if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
+               return -EIDRM;
+
+       /* Acquire mutex */
+       ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+       if (unlikely(ret < 0))
+               return ret;
+
+       /* Check state */
+       if (ffs->state != FFS_ACTIVE) {
+               ret = -EBADFD;
+               goto done_mutex;
+       }
+
+       /*
+        * We're called from user space, we can use _irq rather then
+        * _irqsave
+        */
+       spin_lock_irq(&ffs->ev.waitq.lock);
+
+       switch (FFS_SETUP_STATE(ffs)) {
+       case FFS_SETUP_CANCELED:
+               ret = -EIDRM;
+               break;
+
+       case FFS_NO_SETUP:
+               n = len / sizeof(struct usb_functionfs_event);
+               if (unlikely(!n)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
+                       ret = -EAGAIN;
+                       break;
+               }
+
+               if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
+                                                       ffs->ev.count)) {
+                       ret = -EINTR;
+                       break;
+               }
+
+               return __ffs_ep0_read_events(ffs, buf,
+                                            min(n, (size_t)ffs->ev.count));
+
+       case FFS_SETUP_PENDING:
+               if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
+                       spin_unlock_irq(&ffs->ev.waitq.lock);
+                       ret = __ffs_ep0_stall(ffs);
+                       goto done_mutex;
+               }
+
+               len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+               spin_unlock_irq(&ffs->ev.waitq.lock);
+
+               if (likely(len)) {
+                       data = kmalloc(len, GFP_KERNEL);
+                       if (unlikely(!data)) {
+                               ret = -ENOMEM;
+                               goto done_mutex;
+                       }
+               }
+
+               spin_lock_irq(&ffs->ev.waitq.lock);
+
+               /* See ffs_ep0_write() */
+               if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
+                       ret = -EIDRM;
+                       break;
+               }
+
+               /* unlocks spinlock */
+               ret = __ffs_ep0_queue_wait(ffs, data, len);
+               if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len)))
+                       ret = -EFAULT;
+               goto done_mutex;
+
+       default:
+               ret = -EBADFD;
+               break;
+       }
+
+       spin_unlock_irq(&ffs->ev.waitq.lock);
+done_mutex:
+       mutex_unlock(&ffs->mutex);
+       kfree(data);
+       return ret;
+}
+
+static int ffs_ep0_open(struct inode *inode, struct file *file)
+{
+       struct ffs_data *ffs = inode->i_private;
+
+       ENTER();
+
+       if (unlikely(ffs->state == FFS_CLOSING))
+               return -EBUSY;
+
+       file->private_data = ffs;
+       ffs_data_opened(ffs);
+
+       return 0;
+}
+
+static int ffs_ep0_release(struct inode *inode, struct file *file)
+{
+       struct ffs_data *ffs = file->private_data;
+
+       ENTER();
+
+       ffs_data_closed(ffs);
+
+       return 0;
+}
+
+static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
+{
+       struct ffs_data *ffs = file->private_data;
+       struct usb_gadget *gadget = ffs->gadget;
+       long ret;
+
+       ENTER();
+
+       if (code == FUNCTIONFS_INTERFACE_REVMAP) {
+               struct ffs_function *func = ffs->func;
+               ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
+       } else if (gadget && gadget->ops->ioctl) {
+               ret = gadget->ops->ioctl(gadget, code, value);
+       } else {
+               ret = -ENOTTY;
+       }
+
+       return ret;
+}
+
+static const struct file_operations ffs_ep0_operations = {
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+
+       .open =         ffs_ep0_open,
+       .write =        ffs_ep0_write,
+       .read =         ffs_ep0_read,
+       .release =      ffs_ep0_release,
+       .unlocked_ioctl =       ffs_ep0_ioctl,
+};
+
+
+/* "Normal" endpoints operations ********************************************/
+
+static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+       ENTER();
+       if (likely(req->context)) {
+               struct ffs_ep *ep = _ep->driver_data;
+               ep->status = req->status ? req->status : req->actual;
+               complete(req->context);
+       }
+}
+
+static ssize_t ffs_epfile_io(struct file *file,
+                            char __user *buf, size_t len, int read)
+{
+       struct ffs_epfile *epfile = file->private_data;
+       struct ffs_ep *ep;
+       char *data = NULL;
+       ssize_t ret;
+       int halt;
+
+       goto first_try;
+       do {
+               spin_unlock_irq(&epfile->ffs->eps_lock);
+               mutex_unlock(&epfile->mutex);
+
+first_try:
+               /* Are we still active? */
+               if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) {
+                       ret = -ENODEV;
+                       goto error;
+               }
+
+               /* Wait for endpoint to be enabled */
+               ep = epfile->ep;
+               if (!ep) {
+                       if (file->f_flags & O_NONBLOCK) {
+                               ret = -EAGAIN;
+                               goto error;
+                       }
+
+                       if (wait_event_interruptible(epfile->wait,
+                                                    (ep = epfile->ep))) {
+                               ret = -EINTR;
+                               goto error;
+                       }
+               }
+
+               /* Do we halt? */
+               halt = !read == !epfile->in;
+               if (halt && epfile->isoc) {
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               /* Allocate & copy */
+               if (!halt && !data) {
+                       data = kzalloc(len, GFP_KERNEL);
+                       if (unlikely(!data))
+                               return -ENOMEM;
+
+                       if (!read &&
+                           unlikely(__copy_from_user(data, buf, len))) {
+                               ret = -EFAULT;
+                               goto error;
+                       }
+               }
+
+               /* We will be using request */
+               ret = ffs_mutex_lock(&epfile->mutex,
+                                    file->f_flags & O_NONBLOCK);
+               if (unlikely(ret))
+                       goto error;
+
+               /*
+                * We're called from user space, we can use _irq rather then
+                * _irqsave
+                */
+               spin_lock_irq(&epfile->ffs->eps_lock);
+
+               /*
+                * While we were acquiring mutex endpoint got disabled
+                * or changed?
+                */
+       } while (unlikely(epfile->ep != ep));
+
+       /* Halt */
+       if (unlikely(halt)) {
+               if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
+                       usb_ep_set_halt(ep->ep);
+               spin_unlock_irq(&epfile->ffs->eps_lock);
+               ret = -EBADMSG;
+       } else {
+               /* Fire the request */
+               DECLARE_COMPLETION_ONSTACK(done);
+
+               struct usb_request *req = ep->req;
+               req->context  = &done;
+               req->complete = ffs_epfile_io_complete;
+               req->buf      = data;
+               req->length   = len;
+
+               ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+
+               spin_unlock_irq(&epfile->ffs->eps_lock);
+
+               if (unlikely(ret < 0)) {
+                       /* nop */
+               } else if (unlikely(wait_for_completion_interruptible(&done))) {
+                       ret = -EINTR;
+                       usb_ep_dequeue(ep->ep, req);
+               } else {
+                       ret = ep->status;
+                       if (read && ret > 0 &&
+                           unlikely(copy_to_user(buf, data, ret)))
+                               ret = -EFAULT;
+               }
+       }
+
+       mutex_unlock(&epfile->mutex);
+error:
+       kfree(data);
+       return ret;
+}
+
+static ssize_t
+ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
+                loff_t *ptr)
+{
+       ENTER();
+
+       return ffs_epfile_io(file, (char __user *)buf, len, 0);
+}
+
+static ssize_t
+ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
+{
+       ENTER();
+
+       return ffs_epfile_io(file, buf, len, 1);
+}
+
+static int
+ffs_epfile_open(struct inode *inode, struct file *file)
+{
+       struct ffs_epfile *epfile = inode->i_private;
+
+       ENTER();
+
+       if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+               return -ENODEV;
+
+       file->private_data = epfile;
+       ffs_data_opened(epfile->ffs);
+
+       return 0;
+}
+
+static int
+ffs_epfile_release(struct inode *inode, struct file *file)
+{
+       struct ffs_epfile *epfile = inode->i_private;
+
+       ENTER();
+
+       ffs_data_closed(epfile->ffs);
+
+       return 0;
+}
+
+static long ffs_epfile_ioctl(struct file *file, unsigned code,
+                            unsigned long value)
+{
+       struct ffs_epfile *epfile = file->private_data;
+       int ret;
+
+       ENTER();
+
+       if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+               return -ENODEV;
+
+       spin_lock_irq(&epfile->ffs->eps_lock);
+       if (likely(epfile->ep)) {
+               switch (code) {
+               case FUNCTIONFS_FIFO_STATUS:
+                       ret = usb_ep_fifo_status(epfile->ep->ep);
+                       break;
+               case FUNCTIONFS_FIFO_FLUSH:
+                       usb_ep_fifo_flush(epfile->ep->ep);
+                       ret = 0;
+                       break;
+               case FUNCTIONFS_CLEAR_HALT:
+                       ret = usb_ep_clear_halt(epfile->ep->ep);
+                       break;
+               case FUNCTIONFS_ENDPOINT_REVMAP:
+                       ret = epfile->ep->num;
+                       break;
+               default:
+                       ret = -ENOTTY;
+               }
+       } else {
+               ret = -ENODEV;
+       }
+       spin_unlock_irq(&epfile->ffs->eps_lock);
+
+       return ret;
+}
+
+static const struct file_operations ffs_epfile_operations = {
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+
+       .open =         ffs_epfile_open,
+       .write =        ffs_epfile_write,
+       .read =         ffs_epfile_read,
+       .release =      ffs_epfile_release,
+       .unlocked_ioctl =       ffs_epfile_ioctl,
+};
+
+
+/* File system and super block operations ***********************************/
+
+/*
+ * Mounting the file system creates a controller file, used first for
+ * function configuration then later for event monitoring.
+ */
+
+static struct inode *__must_check
+ffs_sb_make_inode(struct super_block *sb, void *data,
+                 const struct file_operations *fops,
+                 const struct inode_operations *iops,
+                 struct ffs_file_perms *perms)
+{
+       struct inode *inode;
+
+       ENTER();
+
+       inode = new_inode(sb);
+
+       if (likely(inode)) {
+               struct timespec current_time = CURRENT_TIME;
+
+               inode->i_ino     = get_next_ino();
+               inode->i_mode    = perms->mode;
+               inode->i_uid     = perms->uid;
+               inode->i_gid     = perms->gid;
+               inode->i_atime   = current_time;
+               inode->i_mtime   = current_time;
+               inode->i_ctime   = current_time;
+               inode->i_private = data;
+               if (fops)
+                       inode->i_fop = fops;
+               if (iops)
+                       inode->i_op  = iops;
+       }
+
+       return inode;
+}
+
+/* Create "regular" file */
+static struct inode *ffs_sb_create_file(struct super_block *sb,
+                                       const char *name, void *data,
+                                       const struct file_operations *fops,
+                                       struct dentry **dentry_p)
+{
+       struct ffs_data *ffs = sb->s_fs_info;
+       struct dentry   *dentry;
+       struct inode    *inode;
+
+       ENTER();
+
+       dentry = d_alloc_name(sb->s_root, name);
+       if (unlikely(!dentry))
+               return NULL;
+
+       inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
+       if (unlikely(!inode)) {
+               dput(dentry);
+               return NULL;
+       }
+
+       d_add(dentry, inode);
+       if (dentry_p)
+               *dentry_p = dentry;
+
+       return inode;
+}
+
+/* Super block */
+static const struct super_operations ffs_sb_operations = {
+       .statfs =       simple_statfs,
+       .drop_inode =   generic_delete_inode,
+};
+
+struct ffs_sb_fill_data {
+       struct ffs_file_perms perms;
+       umode_t root_mode;
+       const char *dev_name;
+       union {
+               /* set by ffs_fs_mount(), read by ffs_sb_fill() */
+               void *private_data;
+               /* set by ffs_sb_fill(), read by ffs_fs_mount */
+               struct ffs_data *ffs_data;
+       };
+};
+
+static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
+{
+       struct ffs_sb_fill_data *data = _data;
+       struct inode    *inode;
+       struct ffs_data *ffs;
+
+       ENTER();
+
+       /* Initialise data */
+       ffs = ffs_data_new();
+       if (unlikely(!ffs))
+               goto Enomem;
+
+       ffs->sb              = sb;
+       ffs->dev_name        = kstrdup(data->dev_name, GFP_KERNEL);
+       if (unlikely(!ffs->dev_name))
+               goto Enomem;
+       ffs->file_perms      = data->perms;
+       ffs->private_data    = data->private_data;
+
+       /* used by the caller of this function */
+       data->ffs_data       = ffs;
+
+       sb->s_fs_info        = ffs;
+       sb->s_blocksize      = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+       sb->s_magic          = FUNCTIONFS_MAGIC;
+       sb->s_op             = &ffs_sb_operations;
+       sb->s_time_gran      = 1;
+
+       /* Root inode */
+       data->perms.mode = data->root_mode;
+       inode = ffs_sb_make_inode(sb, NULL,
+                                 &simple_dir_operations,
+                                 &simple_dir_inode_operations,
+                                 &data->perms);
+       sb->s_root = d_make_root(inode);
+       if (unlikely(!sb->s_root))
+               goto Enomem;
+
+       /* EP0 file */
+       if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
+                                        &ffs_ep0_operations, NULL)))
+               goto Enomem;
+
+       return 0;
+
+Enomem:
+       return -ENOMEM;
+}
+
+static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
+{
+       ENTER();
+
+       if (!opts || !*opts)
+               return 0;
+
+       for (;;) {
+               char *end, *eq, *comma;
+               unsigned long value;
+
+               /* Option limit */
+               comma = strchr(opts, ',');
+               if (comma)
+                       *comma = 0;
+
+               /* Value limit */
+               eq = strchr(opts, '=');
+               if (unlikely(!eq)) {
+                       pr_err("'=' missing in %s\n", opts);
+                       return -EINVAL;
+               }
+               *eq = 0;
+
+               /* Parse value */
+               value = simple_strtoul(eq + 1, &end, 0);
+               if (unlikely(*end != ',' && *end != 0)) {
+                       pr_err("%s: invalid value: %s\n", opts, eq + 1);
+                       return -EINVAL;
+               }
+
+               /* Interpret option */
+               switch (eq - opts) {
+               case 5:
+                       if (!memcmp(opts, "rmode", 5))
+                               data->root_mode  = (value & 0555) | S_IFDIR;
+                       else if (!memcmp(opts, "fmode", 5))
+                               data->perms.mode = (value & 0666) | S_IFREG;
+                       else
+                               goto invalid;
+                       break;
+
+               case 4:
+                       if (!memcmp(opts, "mode", 4)) {
+                               data->root_mode  = (value & 0555) | S_IFDIR;
+                               data->perms.mode = (value & 0666) | S_IFREG;
+                       } else {
+                               goto invalid;
+                       }
+                       break;
+
+               case 3:
+                       if (!memcmp(opts, "uid", 3))
+                               data->perms.uid = value;
+                       else if (!memcmp(opts, "gid", 3))
+                               data->perms.gid = value;
+                       else
+                               goto invalid;
+                       break;
+
+               default:
+invalid:
+                       pr_err("%s: invalid option\n", opts);
+                       return -EINVAL;
+               }
+
+               /* Next iteration */
+               if (!comma)
+                       break;
+               opts = comma + 1;
+       }
+
+       return 0;
+}
+
+/* "mount -t functionfs dev_name /dev/function" ends up here */
+
+static struct dentry *
+ffs_fs_mount(struct file_system_type *t, int flags,
+             const char *dev_name, void *opts)
+{
+       struct ffs_sb_fill_data data = {
+               .perms = {
+                       .mode = S_IFREG | 0600,
+                       .uid = 0,
+                       .gid = 0
+               },
+               .root_mode = S_IFDIR | 0500,
+       };
+       struct dentry *rv;
+       int ret;
+       void *ffs_dev;
+
+       ENTER();
+
+       ret = ffs_fs_parse_opts(&data, opts);
+       if (unlikely(ret < 0))
+               return ERR_PTR(ret);
+
+       ffs_dev = functionfs_acquire_dev_callback(dev_name);
+       if (IS_ERR(ffs_dev))
+               return ffs_dev;
+
+       data.dev_name = dev_name;
+       data.private_data = ffs_dev;
+       rv = mount_nodev(t, flags, &data, ffs_sb_fill);
+
+       /* data.ffs_data is set by ffs_sb_fill */
+       if (IS_ERR(rv))
+               functionfs_release_dev_callback(data.ffs_data);
+
+       return rv;
+}
+
+static void
+ffs_fs_kill_sb(struct super_block *sb)
+{
+       ENTER();
+
+       kill_litter_super(sb);
+       if (sb->s_fs_info) {
+               functionfs_release_dev_callback(sb->s_fs_info);
+               ffs_data_put(sb->s_fs_info);
+       }
+}
+
+static struct file_system_type ffs_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "functionfs",
+       .mount          = ffs_fs_mount,
+       .kill_sb        = ffs_fs_kill_sb,
+};
+
+
+/* Driver's main init/cleanup functions *************************************/
+
+static int functionfs_init(void)
+{
+       int ret;
+
+       ENTER();
+
+       ret = register_filesystem(&ffs_fs_type);
+       if (likely(!ret))
+               pr_info("file system registered\n");
+       else
+               pr_err("failed registering file system (%d)\n", ret);
+
+       return ret;
+}
+
+static void functionfs_cleanup(void)
+{
+       ENTER();
+
+       pr_info("unloading\n");
+       unregister_filesystem(&ffs_fs_type);
+}
+
+
+/* ffs_data and ffs_function construction and destruction code **************/
+
+static void ffs_data_clear(struct ffs_data *ffs);
+static void ffs_data_reset(struct ffs_data *ffs);
+
+static void ffs_data_get(struct ffs_data *ffs)
+{
+       ENTER();
+
+       atomic_inc(&ffs->ref);
+}
+
+static void ffs_data_opened(struct ffs_data *ffs)
+{
+       ENTER();
+
+       atomic_inc(&ffs->ref);
+       atomic_inc(&ffs->opened);
+}
+
+static void ffs_data_put(struct ffs_data *ffs)
+{
+       ENTER();
+
+       if (unlikely(atomic_dec_and_test(&ffs->ref))) {
+               pr_info("%s(): freeing\n", __func__);
+               ffs_data_clear(ffs);
+               BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
+                      waitqueue_active(&ffs->ep0req_completion.wait));
+               kfree(ffs->dev_name);
+               kfree(ffs);
+       }
+}
+
+static void ffs_data_closed(struct ffs_data *ffs)
+{
+       ENTER();
+
+       if (atomic_dec_and_test(&ffs->opened)) {
+               ffs->state = FFS_CLOSING;
+               ffs_data_reset(ffs);
+       }
+
+       ffs_data_put(ffs);
+}
+
+static struct ffs_data *ffs_data_new(void)
+{
+       struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
+       if (unlikely(!ffs))
+               return 0;
+
+       ENTER();
+
+       atomic_set(&ffs->ref, 1);
+       atomic_set(&ffs->opened, 0);
+       ffs->state = FFS_READ_DESCRIPTORS;
+       mutex_init(&ffs->mutex);
+       spin_lock_init(&ffs->eps_lock);
+       init_waitqueue_head(&ffs->ev.waitq);
+       init_completion(&ffs->ep0req_completion);
+
+       /* XXX REVISIT need to update it in some places, or do we? */
+       ffs->ev.can_stall = 1;
+
+       return ffs;
+}
+
+static void ffs_data_clear(struct ffs_data *ffs)
+{
+       ENTER();
+
+       if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags))
+               functionfs_closed_callback(ffs);
+
+       BUG_ON(ffs->gadget);
+
+       if (ffs->epfiles)
+               ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+
+       kfree(ffs->raw_descs);
+       kfree(ffs->raw_strings);
+       kfree(ffs->stringtabs);
+}
+
+static void ffs_data_reset(struct ffs_data *ffs)
+{
+       ENTER();
+
+       ffs_data_clear(ffs);
+
+       ffs->epfiles = NULL;
+       ffs->raw_descs = NULL;
+       ffs->raw_strings = NULL;
+       ffs->stringtabs = NULL;
+
+       ffs->raw_descs_length = 0;
+       ffs->raw_fs_descs_length = 0;
+       ffs->fs_descs_count = 0;
+       ffs->hs_descs_count = 0;
+
+       ffs->strings_count = 0;
+       ffs->interfaces_count = 0;
+       ffs->eps_count = 0;
+
+       ffs->ev.count = 0;
+
+       ffs->state = FFS_READ_DESCRIPTORS;
+       ffs->setup_state = FFS_NO_SETUP;
+       ffs->flags = 0;
+}
+
+
+static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
+{
+       struct usb_gadget_strings **lang;
+       int first_id;
+
+       ENTER();
+
+       if (WARN_ON(ffs->state != FFS_ACTIVE
+                || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
+               return -EBADFD;
+
+       first_id = usb_string_ids_n(cdev, ffs->strings_count);
+       if (unlikely(first_id < 0))
+               return first_id;
+
+       ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
+       if (unlikely(!ffs->ep0req))
+               return -ENOMEM;
+       ffs->ep0req->complete = ffs_ep0_complete;
+       ffs->ep0req->context = ffs;
+
+       lang = ffs->stringtabs;
+       for (lang = ffs->stringtabs; *lang; ++lang) {
+               struct usb_string *str = (*lang)->strings;
+               int id = first_id;
+               for (; str->s; ++id, ++str)
+                       str->id = id;
+       }
+
+       ffs->gadget = cdev->gadget;
+       ffs_data_get(ffs);
+       return 0;
+}
+
+static void functionfs_unbind(struct ffs_data *ffs)
+{
+       ENTER();
+
+       if (!WARN_ON(!ffs->gadget)) {
+               usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
+               ffs->ep0req = NULL;
+               ffs->gadget = NULL;
+               ffs_data_put(ffs);
+               clear_bit(FFS_FL_BOUND, &ffs->flags);
+       }
+}
+
+static int ffs_epfiles_create(struct ffs_data *ffs)
+{
+       struct ffs_epfile *epfile, *epfiles;
+       unsigned i, count;
+
+       ENTER();
+
+       count = ffs->eps_count;
+       epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
+       if (!epfiles)
+               return -ENOMEM;
+
+       epfile = epfiles;
+       for (i = 1; i <= count; ++i, ++epfile) {
+               epfile->ffs = ffs;
+               mutex_init(&epfile->mutex);
+               init_waitqueue_head(&epfile->wait);
+               sprintf(epfiles->name, "ep%u",  i);
+               if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile,
+                                                &ffs_epfile_operations,
+                                                &epfile->dentry))) {
+                       ffs_epfiles_destroy(epfiles, i - 1);
+                       return -ENOMEM;
+               }
+       }
+
+       ffs->epfiles = epfiles;
+       return 0;
+}
+
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+{
+       struct ffs_epfile *epfile = epfiles;
+
+       ENTER();
+
+       for (; count; --count, ++epfile) {
+               BUG_ON(mutex_is_locked(&epfile->mutex) ||
+                      waitqueue_active(&epfile->wait));
+               if (epfile->dentry) {
+                       d_delete(epfile->dentry);
+                       dput(epfile->dentry);
+                       epfile->dentry = NULL;
+               }
+       }
+
+       kfree(epfiles);
+}
+
+static int functionfs_bind_config(struct usb_composite_dev *cdev,
+                                 struct usb_configuration *c,
+                                 struct ffs_data *ffs)
+{
+       struct ffs_function *func;
+       int ret;
+
+       ENTER();
+
+       func = kzalloc(sizeof *func, GFP_KERNEL);
+       if (unlikely(!func))
+               return -ENOMEM;
+
+       func->function.name    = "Function FS Gadget";
+       func->function.strings = ffs->stringtabs;
+
+       func->function.bind    = ffs_func_bind;
+       func->function.unbind  = ffs_func_unbind;
+       func->function.set_alt = ffs_func_set_alt;
+       func->function.disable = ffs_func_disable;
+       func->function.setup   = ffs_func_setup;
+       func->function.suspend = ffs_func_suspend;
+       func->function.resume  = ffs_func_resume;
+
+       func->conf   = c;
+       func->gadget = cdev->gadget;
+       func->ffs = ffs;
+       ffs_data_get(ffs);
+
+       ret = usb_add_function(c, &func->function);
+       if (unlikely(ret))
+               ffs_func_free(func);
+
+       return ret;
+}
+
+static void ffs_func_free(struct ffs_function *func)
+{
+       struct ffs_ep *ep         = func->eps;
+       unsigned count            = func->ffs->eps_count;
+       unsigned long flags;
+
+       ENTER();
+
+       /* cleanup after autoconfig */
+       spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       do {
+               if (ep->ep && ep->req)
+                       usb_ep_free_request(ep->ep, ep->req);
+               ep->req = NULL;
+               ++ep;
+       } while (--count);
+       spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
+       ffs_data_put(func->ffs);
+
+       kfree(func->eps);
+       /*
+        * eps and interfaces_nums are allocated in the same chunk so
+        * only one free is required.  Descriptors are also allocated
+        * in the same chunk.
+        */
+
+       kfree(func);
+}
+
+static void ffs_func_eps_disable(struct ffs_function *func)
+{
+       struct ffs_ep *ep         = func->eps;
+       struct ffs_epfile *epfile = func->ffs->epfiles;
+       unsigned count            = func->ffs->eps_count;
+       unsigned long flags;
+
+       spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       do {
+               /* pending requests get nuked */
+               if (likely(ep->ep))
+                       usb_ep_disable(ep->ep);
+               epfile->ep = NULL;
+
+               ++ep;
+               ++epfile;
+       } while (--count);
+       spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+}
+
+static int ffs_func_eps_enable(struct ffs_function *func)
+{
+       struct ffs_data *ffs      = func->ffs;
+       struct ffs_ep *ep         = func->eps;
+       struct ffs_epfile *epfile = ffs->epfiles;
+       unsigned count            = ffs->eps_count;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       do {
+               struct usb_endpoint_descriptor *ds;
+               ds = ep->descs[ep->descs[1] ? 1 : 0];
+
+               ep->ep->driver_data = ep;
+               ep->ep->desc = ds;
+               ret = usb_ep_enable(ep->ep);
+               if (likely(!ret)) {
+                       epfile->ep = ep;
+                       epfile->in = usb_endpoint_dir_in(ds);
+                       epfile->isoc = usb_endpoint_xfer_isoc(ds);
+               } else {
+                       break;
+               }
+
+               wake_up(&epfile->wait);
+
+               ++ep;
+               ++epfile;
+       } while (--count);
+       spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
+       return ret;
+}
+
+
+/* Parsing and building descriptors and strings *****************************/
+
+/*
+ * This validates if data pointed by data is a valid USB descriptor as
+ * well as record how many interfaces, endpoints and strings are
+ * required by given configuration.  Returns address after the
+ * descriptor or NULL if data is invalid.
+ */
+
+enum ffs_entity_type {
+       FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
+};
+
+typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
+                                  u8 *valuep,
+                                  struct usb_descriptor_header *desc,
+                                  void *priv);
+
+static int __must_check ffs_do_desc(char *data, unsigned len,
+                                   ffs_entity_callback entity, void *priv)
+{
+       struct usb_descriptor_header *_ds = (void *)data;
+       u8 length;
+       int ret;
+
+       ENTER();
+
+       /* At least two bytes are required: length and type */
+       if (len < 2) {
+               pr_vdebug("descriptor too short\n");
+               return -EINVAL;
+       }
+
+       /* If we have at least as many bytes as the descriptor takes? */
+       length = _ds->bLength;
+       if (len < length) {
+               pr_vdebug("descriptor longer then available data\n");
+               return -EINVAL;
+       }
+
+#define __entity_check_INTERFACE(val)  1
+#define __entity_check_STRING(val)     (val)
+#define __entity_check_ENDPOINT(val)   ((val) & USB_ENDPOINT_NUMBER_MASK)
+#define __entity(type, val) do {                                       \
+               pr_vdebug("entity " #type "(%02x)\n", (val));           \
+               if (unlikely(!__entity_check_ ##type(val))) {           \
+                       pr_vdebug("invalid entity's value\n");          \
+                       return -EINVAL;                                 \
+               }                                                       \
+               ret = entity(FFS_ ##type, &val, _ds, priv);             \
+               if (unlikely(ret < 0)) {                                \
+                       pr_debug("entity " #type "(%02x); ret = %d\n",  \
+                                (val), ret);                           \
+                       return ret;                                     \
+               }                                                       \
+       } while (0)
+
+       /* Parse descriptor depending on type. */
+       switch (_ds->bDescriptorType) {
+       case USB_DT_DEVICE:
+       case USB_DT_CONFIG:
+       case USB_DT_STRING:
+       case USB_DT_DEVICE_QUALIFIER:
+               /* function can't have any of those */
+               pr_vdebug("descriptor reserved for gadget: %d\n",
+                     _ds->bDescriptorType);
+               return -EINVAL;
+
+       case USB_DT_INTERFACE: {
+               struct usb_interface_descriptor *ds = (void *)_ds;
+               pr_vdebug("interface descriptor\n");
+               if (length != sizeof *ds)
+                       goto inv_length;
+
+               __entity(INTERFACE, ds->bInterfaceNumber);
+               if (ds->iInterface)
+                       __entity(STRING, ds->iInterface);
+       }
+               break;
+
+       case USB_DT_ENDPOINT: {
+               struct usb_endpoint_descriptor *ds = (void *)_ds;
+               pr_vdebug("endpoint descriptor\n");
+               if (length != USB_DT_ENDPOINT_SIZE &&
+                   length != USB_DT_ENDPOINT_AUDIO_SIZE)
+                       goto inv_length;
+               __entity(ENDPOINT, ds->bEndpointAddress);
+       }
+               break;
+
+       case HID_DT_HID:
+               pr_vdebug("hid descriptor\n");
+               if (length != sizeof(struct hid_descriptor))
+                       goto inv_length;
+               break;
+
+       case USB_DT_OTG:
+               if (length != sizeof(struct usb_otg_descriptor))
+                       goto inv_length;
+               break;
+
+       case USB_DT_INTERFACE_ASSOCIATION: {
+               struct usb_interface_assoc_descriptor *ds = (void *)_ds;
+               pr_vdebug("interface association descriptor\n");
+               if (length != sizeof *ds)
+                       goto inv_length;
+               if (ds->iFunction)
+                       __entity(STRING, ds->iFunction);
+       }
+               break;
+
+       case USB_DT_OTHER_SPEED_CONFIG:
+       case USB_DT_INTERFACE_POWER:
+       case USB_DT_DEBUG:
+       case USB_DT_SECURITY:
+       case USB_DT_CS_RADIO_CONTROL:
+               /* TODO */
+               pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
+               return -EINVAL;
+
+       default:
+               /* We should never be here */
+               pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
+               return -EINVAL;
+
+inv_length:
+               pr_vdebug("invalid length: %d (descriptor %d)\n",
+                         _ds->bLength, _ds->bDescriptorType);
+               return -EINVAL;
+       }
+
+#undef __entity
+#undef __entity_check_DESCRIPTOR
+#undef __entity_check_INTERFACE
+#undef __entity_check_STRING
+#undef __entity_check_ENDPOINT
+
+       return length;
+}
+
+static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
+                                    ffs_entity_callback entity, void *priv)
+{
+       const unsigned _len = len;
+       unsigned long num = 0;
+
+       ENTER();
+
+       for (;;) {
+               int ret;
+
+               if (num == count)
+                       data = NULL;
+
+               /* Record "descriptor" entity */
+               ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
+               if (unlikely(ret < 0)) {
+                       pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
+                                num, ret);
+                       return ret;
+               }
+
+               if (!data)
+                       return _len - len;
+
+               ret = ffs_do_desc(data, len, entity, priv);
+               if (unlikely(ret < 0)) {
+                       pr_debug("%s returns %d\n", __func__, ret);
+                       return ret;
+               }
+
+               len -= ret;
+               data += ret;
+               ++num;
+       }
+}
+
+static int __ffs_data_do_entity(enum ffs_entity_type type,
+                               u8 *valuep, struct usb_descriptor_header *desc,
+                               void *priv)
+{
+       struct ffs_data *ffs = priv;
+
+       ENTER();
+
+       switch (type) {
+       case FFS_DESCRIPTOR:
+               break;
+
+       case FFS_INTERFACE:
+               /*
+                * Interfaces are indexed from zero so if we
+                * encountered interface "n" then there are at least
+                * "n+1" interfaces.
+                */
+               if (*valuep >= ffs->interfaces_count)
+                       ffs->interfaces_count = *valuep + 1;
+               break;
+
+       case FFS_STRING:
+               /*
+                * Strings are indexed from 1 (0 is magic ;) reserved
+                * for languages list or some such)
+                */
+               if (*valuep > ffs->strings_count)
+                       ffs->strings_count = *valuep;
+               break;
+
+       case FFS_ENDPOINT:
+               /* Endpoints are indexed from 1 as well. */
+               if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
+                       ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
+               break;
+       }
+
+       return 0;
+}
+
+static int __ffs_data_got_descs(struct ffs_data *ffs,
+                               char *const _data, size_t len)
+{
+       unsigned fs_count, hs_count;
+       int fs_len, ret = -EINVAL;
+       char *data = _data;
+
+       ENTER();
+
+       if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
+                    get_unaligned_le32(data + 4) != len))
+               goto error;
+       fs_count = get_unaligned_le32(data +  8);
+       hs_count = get_unaligned_le32(data + 12);
+
+       if (!fs_count && !hs_count)
+               goto einval;
+
+       data += 16;
+       len  -= 16;
+
+       if (likely(fs_count)) {
+               fs_len = ffs_do_descs(fs_count, data, len,
+                                     __ffs_data_do_entity, ffs);
+               if (unlikely(fs_len < 0)) {
+                       ret = fs_len;
+                       goto error;
+               }
+
+               data += fs_len;
+               len  -= fs_len;
+       } else {
+               fs_len = 0;
+       }
+
+       if (likely(hs_count)) {
+               ret = ffs_do_descs(hs_count, data, len,
+                                  __ffs_data_do_entity, ffs);
+               if (unlikely(ret < 0))
+                       goto error;
+       } else {
+               ret = 0;
+       }
+
+       if (unlikely(len != ret))
+               goto einval;
+
+       ffs->raw_fs_descs_length = fs_len;
+       ffs->raw_descs_length    = fs_len + ret;
+       ffs->raw_descs           = _data;
+       ffs->fs_descs_count      = fs_count;
+       ffs->hs_descs_count      = hs_count;
+
+       return 0;
+
+einval:
+       ret = -EINVAL;
+error:
+       kfree(_data);
+       return ret;
+}
+
+static int __ffs_data_got_strings(struct ffs_data *ffs,
+                                 char *const _data, size_t len)
+{
+       u32 str_count, needed_count, lang_count;
+       struct usb_gadget_strings **stringtabs, *t;
+       struct usb_string *strings, *s;
+       const char *data = _data;
+
+       ENTER();
+
+       if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+                    get_unaligned_le32(data + 4) != len))
+               goto error;
+       str_count  = get_unaligned_le32(data + 8);
+       lang_count = get_unaligned_le32(data + 12);
+
+       /* if one is zero the other must be zero */
+       if (unlikely(!str_count != !lang_count))
+               goto error;
+
+       /* Do we have at least as many strings as descriptors need? */
+       needed_count = ffs->strings_count;
+       if (unlikely(str_count < needed_count))
+               goto error;
+
+       /*
+        * If we don't need any strings just return and free all
+        * memory.
+        */
+       if (!needed_count) {
+               kfree(_data);
+               return 0;
+       }
+
+       /* Allocate everything in one chunk so there's less maintenance. */
+       {
+               struct {
+                       struct usb_gadget_strings *stringtabs[lang_count + 1];
+                       struct usb_gadget_strings stringtab[lang_count];
+                       struct usb_string strings[lang_count*(needed_count+1)];
+               } *d;
+               unsigned i = 0;
+
+               d = kmalloc(sizeof *d, GFP_KERNEL);
+               if (unlikely(!d)) {
+                       kfree(_data);
+                       return -ENOMEM;
+               }
+
+               stringtabs = d->stringtabs;
+               t = d->stringtab;
+               i = lang_count;
+               do {
+                       *stringtabs++ = t++;
+               } while (--i);
+               *stringtabs = NULL;
+
+               stringtabs = d->stringtabs;
+               t = d->stringtab;
+               s = d->strings;
+               strings = s;
+       }
+
+       /* For each language */
+       data += 16;
+       len -= 16;
+
+       do { /* lang_count > 0 so we can use do-while */
+               unsigned needed = needed_count;
+
+               if (unlikely(len < 3))
+                       goto error_free;
+               t->language = get_unaligned_le16(data);
+               t->strings  = s;
+               ++t;
+
+               data += 2;
+               len -= 2;
+
+               /* For each string */
+               do { /* str_count > 0 so we can use do-while */
+                       size_t length = strnlen(data, len);
+
+                       if (unlikely(length == len))
+                               goto error_free;
+
+                       /*
+                        * User may provide more strings then we need,
+                        * if that's the case we simply ignore the
+                        * rest
+                        */
+                       if (likely(needed)) {
+                               /*
+                                * s->id will be set while adding
+                                * function to configuration so for
+                                * now just leave garbage here.
+                                */
+                               s->s = data;
+                               --needed;
+                               ++s;
+                       }
+
+                       data += length + 1;
+                       len -= length + 1;
+               } while (--str_count);
+
+               s->id = 0;   /* terminator */
+               s->s = NULL;
+               ++s;
+
+       } while (--lang_count);
+
+       /* Some garbage left? */
+       if (unlikely(len))
+               goto error_free;
+
+       /* Done! */
+       ffs->stringtabs = stringtabs;
+       ffs->raw_strings = _data;
+
+       return 0;
+
+error_free:
+       kfree(stringtabs);
+error:
+       kfree(_data);
+       return -EINVAL;
+}
+
+
+/* Events handling and management *******************************************/
+
+static void __ffs_event_add(struct ffs_data *ffs,
+                           enum usb_functionfs_event_type type)
+{
+       enum usb_functionfs_event_type rem_type1, rem_type2 = type;
+       int neg = 0;
+
+       /*
+        * Abort any unhandled setup
+        *
+        * We do not need to worry about some cmpxchg() changing value
+        * of ffs->setup_state without holding the lock because when
+        * state is FFS_SETUP_PENDING cmpxchg() in several places in
+        * the source does nothing.
+        */
+       if (ffs->setup_state == FFS_SETUP_PENDING)
+               ffs->setup_state = FFS_SETUP_CANCELED;
+
+       switch (type) {
+       case FUNCTIONFS_RESUME:
+               rem_type2 = FUNCTIONFS_SUSPEND;
+               /* FALL THROUGH */
+       case FUNCTIONFS_SUSPEND:
+       case FUNCTIONFS_SETUP:
+               rem_type1 = type;
+               /* Discard all similar events */
+               break;
+
+       case FUNCTIONFS_BIND:
+       case FUNCTIONFS_UNBIND:
+       case FUNCTIONFS_DISABLE:
+       case FUNCTIONFS_ENABLE:
+               /* Discard everything other then power management. */
+               rem_type1 = FUNCTIONFS_SUSPEND;
+               rem_type2 = FUNCTIONFS_RESUME;
+               neg = 1;
+               break;
+
+       default:
+               BUG();
+       }
+
+       {
+               u8 *ev  = ffs->ev.types, *out = ev;
+               unsigned n = ffs->ev.count;
+               for (; n; --n, ++ev)
+                       if ((*ev == rem_type1 || *ev == rem_type2) == neg)
+                               *out++ = *ev;
+                       else
+                               pr_vdebug("purging event %d\n", *ev);
+               ffs->ev.count = out - ffs->ev.types;
+       }
+
+       pr_vdebug("adding event %d\n", type);
+       ffs->ev.types[ffs->ev.count++] = type;
+       wake_up_locked(&ffs->ev.waitq);
+}
+
+static void ffs_event_add(struct ffs_data *ffs,
+                         enum usb_functionfs_event_type type)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+       __ffs_event_add(ffs, type);
+       spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+}
+
+
+/* Bind/unbind USB function hooks *******************************************/
+
+static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
+                                   struct usb_descriptor_header *desc,
+                                   void *priv)
+{
+       struct usb_endpoint_descriptor *ds = (void *)desc;
+       struct ffs_function *func = priv;
+       struct ffs_ep *ffs_ep;
+
+       /*
+        * If hs_descriptors is not NULL then we are reading hs
+        * descriptors now
+        */
+       const int isHS = func->function.hs_descriptors != NULL;
+       unsigned idx;
+
+       if (type != FFS_DESCRIPTOR)
+               return 0;
+
+       if (isHS)
+               func->function.hs_descriptors[(long)valuep] = desc;
+       else
+               func->function.descriptors[(long)valuep]    = desc;
+
+       if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+               return 0;
+
+       idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
+       ffs_ep = func->eps + idx;
+
+       if (unlikely(ffs_ep->descs[isHS])) {
+               pr_vdebug("two %sspeed descriptors for EP %d\n",
+                         isHS ? "high" : "full",
+                         ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+               return -EINVAL;
+       }
+       ffs_ep->descs[isHS] = ds;
+
+       ffs_dump_mem(": Original  ep desc", ds, ds->bLength);
+       if (ffs_ep->ep) {
+               ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
+               if (!ds->wMaxPacketSize)
+                       ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
+       } else {
+               struct usb_request *req;
+               struct usb_ep *ep;
+
+               pr_vdebug("autoconfig\n");
+               ep = usb_ep_autoconfig(func->gadget, ds);
+               if (unlikely(!ep))
+                       return -ENOTSUPP;
+               ep->driver_data = func->eps + idx;
+
+               req = usb_ep_alloc_request(ep, GFP_KERNEL);
+               if (unlikely(!req))
+                       return -ENOMEM;
+
+               ffs_ep->ep  = ep;
+               ffs_ep->req = req;
+               func->eps_revmap[ds->bEndpointAddress &
+                                USB_ENDPOINT_NUMBER_MASK] = idx + 1;
+       }
+       ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
+
+       return 0;
+}
+
+static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
+                                  struct usb_descriptor_header *desc,
+                                  void *priv)
+{
+       struct ffs_function *func = priv;
+       unsigned idx;
+       u8 newValue;
+
+       switch (type) {
+       default:
+       case FFS_DESCRIPTOR:
+               /* Handled in previous pass by __ffs_func_bind_do_descs() */
+               return 0;
+
+       case FFS_INTERFACE:
+               idx = *valuep;
+               if (func->interfaces_nums[idx] < 0) {
+                       int id = usb_interface_id(func->conf, &func->function);
+                       if (unlikely(id < 0))
+                               return id;
+                       func->interfaces_nums[idx] = id;
+               }
+               newValue = func->interfaces_nums[idx];
+               break;
+
+       case FFS_STRING:
+               /* String' IDs are allocated when fsf_data is bound to cdev */
+               newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
+               break;
+
+       case FFS_ENDPOINT:
+               /*
+                * USB_DT_ENDPOINT are handled in
+                * __ffs_func_bind_do_descs().
+                */
+               if (desc->bDescriptorType == USB_DT_ENDPOINT)
+                       return 0;
+
+               idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
+               if (unlikely(!func->eps[idx].ep))
+                       return -EINVAL;
+
+               {
+                       struct usb_endpoint_descriptor **descs;
+                       descs = func->eps[idx].descs;
+                       newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
+               }
+               break;
+       }
+
+       pr_vdebug("%02x -> %02x\n", *valuep, newValue);
+       *valuep = newValue;
+       return 0;
+}
+
+static int ffs_func_bind(struct usb_configuration *c,
+                        struct usb_function *f)
+{
+       struct ffs_function *func = ffs_func_from_usb(f);
+       struct ffs_data *ffs = func->ffs;
+
+       const int full = !!func->ffs->fs_descs_count;
+       const int high = gadget_is_dualspeed(func->gadget) &&
+               func->ffs->hs_descs_count;
+
+       int ret;
+
+       /* Make it a single chunk, less management later on */
+       struct {
+               struct ffs_ep eps[ffs->eps_count];
+               struct usb_descriptor_header
+                       *fs_descs[full ? ffs->fs_descs_count + 1 : 0];
+               struct usb_descriptor_header
+                       *hs_descs[high ? ffs->hs_descs_count + 1 : 0];
+               short inums[ffs->interfaces_count];
+               char raw_descs[high ? ffs->raw_descs_length
+                                   : ffs->raw_fs_descs_length];
+       } *data;
+
+       ENTER();
+
+       /* Only high speed but not supported by gadget? */
+       if (unlikely(!(full | high)))
+               return -ENOTSUPP;
+
+       /* Allocate */
+       data = kmalloc(sizeof *data, GFP_KERNEL);
+       if (unlikely(!data))
+               return -ENOMEM;
+
+       /* Zero */
+       memset(data->eps, 0, sizeof data->eps);
+       memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
+       memset(data->inums, 0xff, sizeof data->inums);
+       for (ret = ffs->eps_count; ret; --ret)
+               data->eps[ret].num = -1;
+
+       /* Save pointers */
+       func->eps             = data->eps;
+       func->interfaces_nums = data->inums;
+
+       /*
+        * Go through all the endpoint descriptors and allocate
+        * endpoints first, so that later we can rewrite the endpoint
+        * numbers without worrying that it may be described later on.
+        */
+       if (likely(full)) {
+               func->function.descriptors = data->fs_descs;
+               ret = ffs_do_descs(ffs->fs_descs_count,
+                                  data->raw_descs,
+                                  sizeof data->raw_descs,
+                                  __ffs_func_bind_do_descs, func);
+               if (unlikely(ret < 0))
+                       goto error;
+       } else {
+               ret = 0;
+       }
+
+       if (likely(high)) {
+               func->function.hs_descriptors = data->hs_descs;
+               ret = ffs_do_descs(ffs->hs_descs_count,
+                                  data->raw_descs + ret,
+                                  (sizeof data->raw_descs) - ret,
+                                  __ffs_func_bind_do_descs, func);
+       }
+
+       /*
+        * Now handle interface numbers allocation and interface and
+        * endpoint numbers rewriting.  We can do that in one go
+        * now.
+        */
+       ret = ffs_do_descs(ffs->fs_descs_count +
+                          (high ? ffs->hs_descs_count : 0),
+                          data->raw_descs, sizeof data->raw_descs,
+                          __ffs_func_bind_do_nums, func);
+       if (unlikely(ret < 0))
+               goto error;
+
+       /* And we're done */
+       ffs_event_add(ffs, FUNCTIONFS_BIND);
+       return 0;
+
+error:
+       /* XXX Do we need to release all claimed endpoints here? */
+       return ret;
+}
+
+
+/* Other USB function hooks *************************************************/
+
+static void ffs_func_unbind(struct usb_configuration *c,
+                           struct usb_function *f)
+{
+       struct ffs_function *func = ffs_func_from_usb(f);
+       struct ffs_data *ffs = func->ffs;
+
+       ENTER();
+
+       if (ffs->func == func) {
+               ffs_func_eps_disable(func);
+               ffs->func = NULL;
+       }
+
+       ffs_event_add(ffs, FUNCTIONFS_UNBIND);
+
+       ffs_func_free(func);
+}
+
+static int ffs_func_set_alt(struct usb_function *f,
+                           unsigned interface, unsigned alt)
+{
+       struct ffs_function *func = ffs_func_from_usb(f);
+       struct ffs_data *ffs = func->ffs;
+       int ret = 0, intf;
+
+       if (alt != (unsigned)-1) {
+               intf = ffs_func_revmap_intf(func, interface);
+               if (unlikely(intf < 0))
+                       return intf;
+       }
+
+       if (ffs->func)
+               ffs_func_eps_disable(ffs->func);
+
+       if (ffs->state != FFS_ACTIVE)
+               return -ENODEV;
+
+       if (alt == (unsigned)-1) {
+               ffs->func = NULL;
+               ffs_event_add(ffs, FUNCTIONFS_DISABLE);
+               return 0;
+       }
+
+       ffs->func = func;
+       ret = ffs_func_eps_enable(func);
+       if (likely(ret >= 0))
+               ffs_event_add(ffs, FUNCTIONFS_ENABLE);
+       return ret;
+}
+
+static void ffs_func_disable(struct usb_function *f)
+{
+       ffs_func_set_alt(f, 0, (unsigned)-1);
+}
+
+static int ffs_func_setup(struct usb_function *f,
+                         const struct usb_ctrlrequest *creq)
+{
+       struct ffs_function *func = ffs_func_from_usb(f);
+       struct ffs_data *ffs = func->ffs;
+       unsigned long flags;
+       int ret;
+
+       ENTER();
+
+       pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
+       pr_vdebug("creq->bRequest     = %02x\n", creq->bRequest);
+       pr_vdebug("creq->wValue       = %04x\n", le16_to_cpu(creq->wValue));
+       pr_vdebug("creq->wIndex       = %04x\n", le16_to_cpu(creq->wIndex));
+       pr_vdebug("creq->wLength      = %04x\n", le16_to_cpu(creq->wLength));
+
+       /*
+        * Most requests directed to interface go through here
+        * (notable exceptions are set/get interface) so we need to
+        * handle them.  All other either handled by composite or
+        * passed to usb_configuration->setup() (if one is set).  No
+        * matter, we will handle requests directed to endpoint here
+        * as well (as it's straightforward) but what to do with any
+        * other request?
+        */
+       if (ffs->state != FFS_ACTIVE)
+               return -ENODEV;
+
+       switch (creq->bRequestType & USB_RECIP_MASK) {
+       case USB_RECIP_INTERFACE:
+               ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
+               if (unlikely(ret < 0))
+                       return ret;
+               break;
+
+       case USB_RECIP_ENDPOINT:
+               ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
+               if (unlikely(ret < 0))
+                       return ret;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+       ffs->ev.setup = *creq;
+       ffs->ev.setup.wIndex = cpu_to_le16(ret);
+       __ffs_event_add(ffs, FUNCTIONFS_SETUP);
+       spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+
+       return 0;
+}
+
+static void ffs_func_suspend(struct usb_function *f)
+{
+       ENTER();
+       ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
+}
+
+static void ffs_func_resume(struct usb_function *f)
+{
+       ENTER();
+       ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
+}
+
+
+/* Endpoint and interface numbers reverse mapping ***************************/
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
+{
+       num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
+       return num ? num : -EDOM;
+}
+
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
+{
+       short *nums = func->interfaces_nums;
+       unsigned count = func->ffs->interfaces_count;
+
+       for (; count; --count, ++nums) {
+               if (*nums >= 0 && *nums == intf)
+                       return nums - func->interfaces_nums;
+       }
+
+       return -EDOM;
+}
+
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+{
+       return nonblock
+               ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
+               : mutex_lock_interruptible(mutex);
+}
+
+static char *ffs_prepare_buffer(const char * __user buf, size_t len)
+{
+       char *data;
+
+       if (unlikely(!len))
+               return NULL;
+
+       data = kmalloc(len, GFP_KERNEL);
+       if (unlikely(!data))
+               return ERR_PTR(-ENOMEM);
+
+       if (unlikely(__copy_from_user(data, buf, len))) {
+               kfree(data);
+               return ERR_PTR(-EFAULT);
+       }
+
+       pr_vdebug("Buffer from user space:\n");
+       ffs_dump_mem("", data, len);
+
+       return data;
+}
diff --git a/drivers/staging/ccg/f_mass_storage.c b/drivers/staging/ccg/f_mass_storage.c
new file mode 100644 (file)
index 0000000..4f1142e
--- /dev/null
@@ -0,0 +1,3135 @@
+/*
+ * f_mass_storage.c -- Mass Storage USB Composite Function
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyright (C) 2009 Samsung Electronics
+ *                    Author: Michal Nazarewicz <mina86@mina86.com>
+ * 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 Mass Storage Function 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 composite
+ * function for a USB device, it also illustrates a technique of
+ * double-buffering for increased throughput.
+ *
+ * For more information about MSF and in particular its module
+ * parameters and sysfs interface read the
+ * <Documentation/usb/mass-storage.txt> file.
+ */
+
+/*
+ * MSF is configured by specifying a fsg_config structure.  It has the
+ * following fields:
+ *
+ *     nluns           Number of LUNs function have (anywhere from 1
+ *                             to FSG_MAX_LUNS which is 8).
+ *     luns            An array of LUN configuration values.  This
+ *                             should be filled for each LUN that
+ *                             function will include (ie. for "nluns"
+ *                             LUNs).  Each element of the array has
+ *                             the following fields:
+ *     ->filename      The path to the backing file for the LUN.
+ *                             Required if LUN is not marked as
+ *                             removable.
+ *     ->ro            Flag specifying access to the LUN shall be
+ *                             read-only.  This is implied if CD-ROM
+ *                             emulation is enabled as well as when
+ *                             it was impossible to open "filename"
+ *                             in R/W mode.
+ *     ->removable     Flag specifying that LUN shall be indicated as
+ *                             being removable.
+ *     ->cdrom         Flag specifying that LUN shall be reported as
+ *                             being a CD-ROM.
+ *     ->nofua         Flag specifying that FUA flag in SCSI WRITE(10,12)
+ *                             commands for this LUN shall be ignored.
+ *
+ *     vendor_name
+ *     product_name
+ *     release         Information used as a reply to INQUIRY
+ *                             request.  To use default set to NULL,
+ *                             NULL, 0xffff respectively.  The first
+ *                             field should be 8 and the second 16
+ *                             characters or less.
+ *
+ *     can_stall       Set to permit function to halt bulk endpoints.
+ *                             Disabled on some USB devices known not
+ *                             to work correctly.  You should set it
+ *                             to true.
+ *
+ * If "removable" is not set for a LUN then a backing file must be
+ * specified.  If it is set, then NULL filename means the LUN's medium
+ * is not loaded (an empty string as "filename" in the fsg_config
+ * structure causes error).  The CD-ROM emulation includes a single
+ * data track and no audio tracks; hence there need be only one
+ * backing file per LUN.
+ *
+ * This function is heavily based on "File-backed Storage Gadget" by
+ * Alan Stern which in turn 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 MSF 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.  As of this moment, MSF
+ * provides no way to deregister the gadget when thread dies -- maybe
+ * a callback functions is needed.
+ *
+ * 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/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 <linux/usb/composite.h>
+
+#include "gadget_chips.h"
+
+
+/*------------------------------------------------------------------------*/
+
+#define FSG_DRIVER_DESC                "Mass Storage Function"
+#define FSG_DRIVER_VERSION     "2009/09/11"
+
+static const char fsg_string_interface[] = "Mass Storage";
+
+#define FSG_NO_DEVICE_STRINGS    1
+#define FSG_NO_OTG               1
+#define FSG_NO_INTR_EP           1
+
+#include "storage_common.c"
+
+
+/*-------------------------------------------------------------------------*/
+
+struct fsg_dev;
+struct fsg_common;
+
+/* FSF callback functions */
+struct fsg_operations {
+       /*
+        * Callback function to call when thread exits.  If no
+        * callback is set or it returns value lower then zero MSF
+        * will force eject all LUNs it operates on (including those
+        * marked as non-removable or with prevent_medium_removal flag
+        * set).
+        */
+       int (*thread_exits)(struct fsg_common *common);
+
+       /*
+        * Called prior to ejection.  Negative return means error,
+        * zero means to continue with ejection, positive means not to
+        * eject.
+        */
+       int (*pre_eject)(struct fsg_common *common,
+                        struct fsg_lun *lun, int num);
+       /*
+        * Called after ejection.  Negative return means error, zero
+        * or positive is just a success.
+        */
+       int (*post_eject)(struct fsg_common *common,
+                         struct fsg_lun *lun, int num);
+};
+
+/* Data shared by all the FSG instances. */
+struct fsg_common {
+       struct usb_gadget       *gadget;
+       struct usb_composite_dev *cdev;
+       struct fsg_dev          *fsg, *new_fsg;
+       wait_queue_head_t       fsg_wait;
+
+       /* filesem protects: backing files in use */
+       struct rw_semaphore     filesem;
+
+       /* lock protects: state, all the req_busy's */
+       spinlock_t              lock;
+
+       struct usb_ep           *ep0;           /* Copy of gadget->ep0 */
+       struct usb_request      *ep0req;        /* Copy of cdev->req */
+       unsigned int            ep0_req_tag;
+
+       struct fsg_buffhd       *next_buffhd_to_fill;
+       struct fsg_buffhd       *next_buffhd_to_drain;
+       struct fsg_buffhd       *buffhds;
+
+       int                     cmnd_size;
+       u8                      cmnd[MAX_COMMAND_SIZE];
+
+       unsigned int            nluns;
+       unsigned int            lun;
+       struct fsg_lun          *luns;
+       struct fsg_lun          *curlun;
+
+       unsigned int            bulk_out_maxpacket;
+       enum fsg_state          state;          /* For exception handling */
+       unsigned int            exception_req_tag;
+
+       enum data_direction     data_dir;
+       u32                     data_size;
+       u32                     data_size_from_cmnd;
+       u32                     tag;
+       u32                     residue;
+       u32                     usb_amount_left;
+
+       unsigned int            can_stall:1;
+       unsigned int            free_storage_on_release:1;
+       unsigned int            phase_error:1;
+       unsigned int            short_packet_received:1;
+       unsigned int            bad_lun_okay:1;
+       unsigned int            running:1;
+
+       int                     thread_wakeup_needed;
+       struct completion       thread_notifier;
+       struct task_struct      *thread_task;
+
+       /* Callback functions. */
+       const struct fsg_operations     *ops;
+       /* Gadget's private data. */
+       void                    *private_data;
+
+       /*
+        * Vendor (8 chars), product (16 chars), release (4
+        * hexadecimal digits) and NUL byte
+        */
+       char inquiry_string[8 + 16 + 4 + 1];
+
+       struct kref             ref;
+};
+
+struct fsg_config {
+       unsigned nluns;
+       struct fsg_lun_config {
+               const char *filename;
+               char ro;
+               char removable;
+               char cdrom;
+               char nofua;
+       } luns[FSG_MAX_LUNS];
+
+       /* Callback functions. */
+       const struct fsg_operations     *ops;
+       /* Gadget's private data. */
+       void                    *private_data;
+
+       const char *vendor_name;                /*  8 characters or less */
+       const char *product_name;               /* 16 characters or less */
+       u16 release;
+
+       char                    can_stall;
+};
+
+struct fsg_dev {
+       struct usb_function     function;
+       struct usb_gadget       *gadget;        /* Copy of cdev->gadget */
+       struct fsg_common       *common;
+
+       u16                     interface_number;
+
+       unsigned int            bulk_in_enabled:1;
+       unsigned int            bulk_out_enabled:1;
+
+       unsigned long           atomic_bitflags;
+#define IGNORE_BULK_OUT                0
+
+       struct usb_ep           *bulk_in;
+       struct usb_ep           *bulk_out;
+};
+
+static inline int __fsg_is_set(struct fsg_common *common,
+                              const char *func, unsigned line)
+{
+       if (common->fsg)
+               return 1;
+       ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
+       WARN_ON(1);
+       return 0;
+}
+
+#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
+
+static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
+{
+       return container_of(f, struct fsg_dev, function);
+}
+
+typedef void (*fsg_routine_t)(struct fsg_dev *);
+
+static int exception_in_progress(struct fsg_common *common)
+{
+       return common->state > FSG_STATE_IDLE;
+}
+
+/* Make bulk-out requests be divisible by the maxpacket size */
+static void set_bulk_out_req_length(struct fsg_common *common,
+                                   struct fsg_buffhd *bh, unsigned int length)
+{
+       unsigned int    rem;
+
+       bh->bulk_out_intended_length = length;
+       rem = length % common->bulk_out_maxpacket;
+       if (rem > 0)
+               length += common->bulk_out_maxpacket - rem;
+       bh->outreq->length = length;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+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);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* These routines may be called in process context or in_irq */
+
+/* Caller must hold fsg->lock */
+static void wakeup_thread(struct fsg_common *common)
+{
+       /* Tell the main thread that something has happened */
+       common->thread_wakeup_needed = 1;
+       if (common->thread_task)
+               wake_up_process(common->thread_task);
+}
+
+static void raise_exception(struct fsg_common *common, 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(&common->lock, flags);
+       if (common->state <= new_state) {
+               common->exception_req_tag = common->ep0_req_tag;
+               common->state = new_state;
+               if (common->thread_task)
+                       send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+                                     common->thread_task);
+       }
+       spin_unlock_irqrestore(&common->lock, flags);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int ep0_queue(struct fsg_common *common)
+{
+       int     rc;
+
+       rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC);
+       common->ep0->driver_data = common;
+       if (rc != 0 && rc != -ESHUTDOWN) {
+               /* We can't do much more than wait for a reset */
+               WARNING(common, "error in submission: %s --> %d\n",
+                       common->ep0->name, rc);
+       }
+       return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Completion handlers. These always run in_irq. */
+
+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct fsg_common       *common = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
+
+       if (req->status || req->actual != req->length)
+               DBG(common, "%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(&common->lock);
+       bh->inreq_busy = 0;
+       bh->state = BUF_STATE_EMPTY;
+       wakeup_thread(common);
+       spin_unlock(&common->lock);
+}
+
+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct fsg_common       *common = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
+
+       dump_msg(common, "bulk-out", req->buf, req->actual);
+       if (req->status || req->actual != bh->bulk_out_intended_length)
+               DBG(common, "%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(&common->lock);
+       bh->outreq_busy = 0;
+       bh->state = BUF_STATE_FULL;
+       wakeup_thread(common);
+       spin_unlock(&common->lock);
+}
+
+static int fsg_setup(struct usb_function *f,
+                    const struct usb_ctrlrequest *ctrl)
+{
+       struct fsg_dev          *fsg = fsg_from_func(f);
+       struct usb_request      *req = fsg->common->ep0req;
+       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_is_set(fsg->common))
+               return -EOPNOTSUPP;
+
+       ++fsg->common->ep0_req_tag;     /* Record arrival of a new request */
+       req->context = NULL;
+       req->length = 0;
+       dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
+
+       switch (ctrl->bRequest) {
+
+       case US_BULK_RESET_REQUEST:
+               if (ctrl->bRequestType !=
+                   (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+                       break;
+               if (w_index != fsg->interface_number || w_value != 0 ||
+                               w_length != 0)
+                       return -EDOM;
+
+               /*
+                * Raise an exception to stop the current operation
+                * and reinitialize our state.
+                */
+               DBG(fsg, "bulk reset request\n");
+               raise_exception(fsg->common, FSG_STATE_RESET);
+               return DELAYED_STATUS;
+
+       case US_BULK_GET_MAX_LUN:
+               if (ctrl->bRequestType !=
+                   (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
+                       break;
+               if (w_index != fsg->interface_number || w_value != 0 ||
+                               w_length != 1)
+                       return -EDOM;
+               VDBG(fsg, "get max LUN\n");
+               *(u8 *)req->buf = fsg->common->nluns - 1;
+
+               /* Respond with data/status */
+               req->length = min((u16)1, w_length);
+               return ep0_queue(fsg->common);
+       }
+
+       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 -EOPNOTSUPP;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* 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);
+
+       spin_lock_irq(&fsg->common->lock);
+       *pbusy = 1;
+       *state = BUF_STATE_BUSY;
+       spin_unlock_irq(&fsg->common->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 bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+       if (!fsg_is_set(common))
+               return false;
+       start_transfer(common->fsg, common->fsg->bulk_in,
+                      bh->inreq, &bh->inreq_busy, &bh->state);
+       return true;
+}
+
+static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+       if (!fsg_is_set(common))
+               return false;
+       start_transfer(common->fsg, common->fsg->bulk_out,
+                      bh->outreq, &bh->outreq_busy, &bh->state);
+       return true;
+}
+
+static int sleep_thread(struct fsg_common *common)
+{
+       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 (common->thread_wakeup_needed)
+                       break;
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+       common->thread_wakeup_needed = 0;
+       return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_read(struct fsg_common *common)
+{
+       struct fsg_lun          *curlun = common->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 (common->cmnd[0] == READ_6)
+               lba = get_unaligned_be24(&common->cmnd[1]);
+       else {
+               lba = get_unaligned_be32(&common->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 ((common->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 = common->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(amount_left, FSG_BUFLEN);
+               amount = min((loff_t)amount,
+                            curlun->file_length - file_offset);
+
+               /* Wait for the next buffer to become available */
+               bh = common->next_buffhd_to_fill;
+               while (bh->state != BUF_STATE_EMPTY) {
+                       rc = sleep_thread(common);
+                       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;
+               common->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;
+               if (!start_in_transfer(common, bh))
+                       /* Don't know what to do if common->fsg is NULL */
+                       return -EIO;
+               common->next_buffhd_to_fill = bh->next;
+       }
+
+       return -EIO;            /* No default reply */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_write(struct fsg_common *common)
+{
+       struct fsg_lun          *curlun = common->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 (common->cmnd[0] == WRITE_6)
+               lba = get_unaligned_be24(&common->cmnd[1]);
+       else {
+               lba = get_unaligned_be32(&common->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 (common->cmnd[1] & ~0x18) {
+                       curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+                       return -EINVAL;
+               }
+               if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */
+                       spin_lock(&curlun->filp->f_lock);
+                       curlun->filp->f_flags |= O_SYNC;
+                       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 = common->data_size_from_cmnd;
+       amount_left_to_write = common->data_size_from_cmnd;
+
+       while (amount_left_to_write > 0) {
+
+               /* Queue a request for more data from the host */
+               bh = common->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, FSG_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;
+                       common->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(common, bh, amount);
+                       if (!start_out_transfer(common, bh))
+                               /* Dunno what to do if common->fsg is NULL */
+                               return -EIO;
+                       common->next_buffhd_to_fill = bh->next;
+                       continue;
+               }
+
+               /* Write the received data to the backing file */
+               bh = common->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();
+                       common->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;
+                       common->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) {
+                               common->short_packet_received = 1;
+                               break;
+                       }
+                       continue;
+               }
+
+               /* Wait for something to happen */
+               rc = sleep_thread(common);
+               if (rc)
+                       return rc;
+       }
+
+       return -EIO;            /* No default reply */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int do_synchronize_cache(struct fsg_common *common)
+{
+       struct fsg_lun  *curlun = common->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_common *common)
+{
+       struct fsg_lun          *curlun = common->curlun;
+       u32                     lba;
+       u32                     verification_length;
+       struct fsg_buffhd       *bh = common->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(&common->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 (common->cmnd[1] & ~0x10) {
+               curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+               return -EINVAL;
+       }
+
+       verification_length = get_unaligned_be16(&common->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(amount_left, FSG_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_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun *curlun = common->curlun;
+       u8      *buf = (u8 *) bh->buf;
+
+       if (!curlun) {          /* Unsupported LUNs are okay */
+               common->bad_lun_okay = 1;
+               memset(buf, 0, 36);
+               buf[0] = 0x7f;          /* Unsupported, no device-type */
+               buf[4] = 31;            /* Additional length */
+               return 36;
+       }
+
+       buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK;
+       buf[1] = curlun->removable ? 0x80 : 0;
+       buf[2] = 2;             /* ANSI SCSI level 2 */
+       buf[3] = 2;             /* SCSI-2 INQUIRY data format */
+       buf[4] = 31;            /* Additional length */
+       buf[5] = 0;             /* No special options */
+       buf[6] = 0;
+       buf[7] = 0;
+       memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
+       return 36;
+}
+
+static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->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 */
+               common->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_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->curlun;
+       u32             lba = get_unaligned_be32(&common->cmnd[2]);
+       int             pmi = common->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_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->curlun;
+       int             msf = common->cmnd[1] & 0x02;
+       u32             lba = get_unaligned_be32(&common->cmnd[2]);
+       u8              *buf = (u8 *)bh->buf;
+
+       if (common->cmnd[1] & ~0x02) {          /* 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_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->curlun;
+       int             msf = common->cmnd[1] & 0x02;
+       int             start_track = common->cmnd[6];
+       u8              *buf = (u8 *)bh->buf;
+
+       if ((common->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_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->curlun;
+       int             mscmnd = common->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 ((common->cmnd[1] & ~0x08) != 0) {   /* Mask away DBD */
+               curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+               return -EINVAL;
+       }
+       pc = common->cmnd[2] >> 6;
+       page_code = common->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 FSG_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_common *common)
+{
+       struct fsg_lun  *curlun = common->curlun;
+       int             loej, start;
+
+       if (!curlun) {
+               return -EINVAL;
+       } else if (!curlun->removable) {
+               curlun->sense_data = SS_INVALID_COMMAND;
+               return -EINVAL;
+       } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
+                  (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
+               curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+               return -EINVAL;
+       }
+
+       loej  = common->cmnd[4] & 0x02;
+       start = common->cmnd[4] & 0x01;
+
+       /*
+        * Our emulation doesn't support mounting; the medium is
+        * available for use as soon as it is loaded.
+        */
+       if (start) {
+               if (!fsg_lun_is_open(curlun)) {
+                       curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+                       return -EINVAL;
+               }
+               return 0;
+       }
+
+       /* 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)
+               return 0;
+
+       /* Simulate an unload/eject */
+       if (common->ops && common->ops->pre_eject) {
+               int r = common->ops->pre_eject(common, curlun,
+                                              curlun - common->luns);
+               if (unlikely(r < 0))
+                       return r;
+               else if (r)
+                       return 0;
+       }
+
+       up_read(&common->filesem);
+       down_write(&common->filesem);
+       fsg_lun_close(curlun);
+       up_write(&common->filesem);
+       down_read(&common->filesem);
+
+       return common->ops && common->ops->post_eject
+               ? min(0, common->ops->post_eject(common, curlun,
+                                                curlun - common->luns))
+               : 0;
+}
+
+static int do_prevent_allow(struct fsg_common *common)
+{
+       struct fsg_lun  *curlun = common->curlun;
+       int             prevent;
+
+       if (!common->curlun) {
+               return -EINVAL;
+       } else if (!common->curlun->removable) {
+               common->curlun->sense_data = SS_INVALID_COMMAND;
+               return -EINVAL;
+       }
+
+       prevent = common->cmnd[4] & 0x01;
+       if ((common->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_common *common,
+                       struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->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_common *common, struct fsg_buffhd *bh)
+{
+       struct fsg_lun  *curlun = common->curlun;
+
+       /* We don't support MODE SELECT */
+       if (curlun)
+               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_common *common)
+{
+       struct fsg_buffhd       *bh;
+       u32                     amount;
+       int                     rc;
+
+       for (bh = common->next_buffhd_to_drain;
+            bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0;
+            bh = common->next_buffhd_to_drain) {
+
+               /* Throw away the data in a filled buffer */
+               if (bh->state == BUF_STATE_FULL) {
+                       smp_rmb();
+                       bh->state = BUF_STATE_EMPTY;
+                       common->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(common,
+                                               FSG_STATE_ABORT_BULK_OUT);
+                               return -EINTR;
+                       }
+                       continue;
+               }
+
+               /* Try to submit another request if we need one */
+               bh = common->next_buffhd_to_fill;
+               if (bh->state == BUF_STATE_EMPTY
+                && common->usb_amount_left > 0) {
+                       amount = min(common->usb_amount_left, FSG_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(common, bh, amount);
+                       if (!start_out_transfer(common, bh))
+                               /* Dunno what to do if common->fsg is NULL */
+                               return -EIO;
+                       common->next_buffhd_to_fill = bh->next;
+                       common->usb_amount_left -= amount;
+                       continue;
+               }
+
+               /* Otherwise wait for something to happen */
+               rc = sleep_thread(common);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
+static int finish_reply(struct fsg_common *common)
+{
+       struct fsg_buffhd       *bh = common->next_buffhd_to_fill;
+       int                     rc = 0;
+
+       switch (common->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 (!common->can_stall) {
+                       /* Nothing */
+               } else if (fsg_is_set(common)) {
+                       fsg_set_halt(common->fsg, common->fsg->bulk_out);
+                       rc = halt_bulk_in_endpoint(common->fsg);
+               } else {
+                       /* Don't know what to do if common->fsg is NULL */
+                       rc = -EIO;
+               }
+               break;
+
+       /* All but the last buffer of data must have already been sent */
+       case DATA_DIR_TO_HOST:
+               if (common->data_size == 0) {
+                       /* Nothing to send */
+
+               /* Don't know what to do if common->fsg is NULL */
+               } else if (!fsg_is_set(common)) {
+                       rc = -EIO;
+
+               /* If there's no residue, simply send the last buffer */
+               } else if (common->residue == 0) {
+                       bh->inreq->zero = 0;
+                       if (!start_in_transfer(common, bh))
+                               return -EIO;
+                       common->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;
+                       if (!start_in_transfer(common, bh))
+                               rc = -EIO;
+                       common->next_buffhd_to_fill = bh->next;
+                       if (common->can_stall)
+                               rc = halt_bulk_in_endpoint(common->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 (common->residue == 0) {
+                       /* Nothing to receive */
+
+               /* Did the host stop sending unexpectedly early? */
+               } else if (common->short_packet_received) {
+                       raise_exception(common, 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 (common->can_stall) {
+                       if (fsg_is_set(common))
+                               fsg_set_halt(common->fsg,
+                                            common->fsg->bulk_out);
+                       raise_exception(common, 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(common);
+               }
+               break;
+       }
+       return rc;
+}
+
+static int send_status(struct fsg_common *common)
+{
+       struct fsg_lun          *curlun = common->curlun;
+       struct fsg_buffhd       *bh;
+       struct bulk_cs_wrap     *csw;
+       int                     rc;
+       u8                      status = US_BULK_STAT_OK;
+       u32                     sd, sdinfo = 0;
+
+       /* Wait for the next buffer to become available */
+       bh = common->next_buffhd_to_fill;
+       while (bh->state != BUF_STATE_EMPTY) {
+               rc = sleep_thread(common);
+               if (rc)
+                       return rc;
+       }
+
+       if (curlun) {
+               sd = curlun->sense_data;
+               sdinfo = curlun->sense_data_info;
+       } else if (common->bad_lun_okay)
+               sd = SS_NO_SENSE;
+       else
+               sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
+
+       if (common->phase_error) {
+               DBG(common, "sending phase-error status\n");
+               status = US_BULK_STAT_PHASE;
+               sd = SS_INVALID_COMMAND;
+       } else if (sd != SS_NO_SENSE) {
+               DBG(common, "sending command-failure status\n");
+               status = US_BULK_STAT_FAIL;
+               VDBG(common, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
+                               "  info x%x\n",
+                               SK(sd), ASC(sd), ASCQ(sd), sdinfo);
+       }
+
+       /* Store and send the Bulk-only CSW */
+       csw = (void *)bh->buf;
+
+       csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
+       csw->Tag = common->tag;
+       csw->Residue = cpu_to_le32(common->residue);
+       csw->Status = status;
+
+       bh->inreq->length = US_BULK_CS_WRAP_LEN;
+       bh->inreq->zero = 0;
+       if (!start_in_transfer(common, bh))
+               /* Don't know what to do if common->fsg is NULL */
+               return -EIO;
+
+       common->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_common *common, int cmnd_size,
+                        enum data_direction data_dir, unsigned int mask,
+                        int needs_medium, const char *name)
+{
+       int                     i;
+       int                     lun = common->cmnd[1] >> 5;
+       static const char       dirletter[4] = {'u', 'o', 'i', 'n'};
+       char                    hdlen[20];
+       struct fsg_lun          *curlun;
+
+       hdlen[0] = 0;
+       if (common->data_dir != DATA_DIR_UNKNOWN)
+               sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
+                       common->data_size);
+       VDBG(common, "SCSI command: %s;  Dc=%d, D%c=%u;  Hc=%d%s\n",
+            name, cmnd_size, dirletter[(int) data_dir],
+            common->data_size_from_cmnd, common->cmnd_size, hdlen);
+
+       /*
+        * We can't reply at all until we know the correct data direction
+        * and size.
+        */
+       if (common->data_size_from_cmnd == 0)
+               data_dir = DATA_DIR_NONE;
+       if (common->data_size < common->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.
+                */
+               common->data_size_from_cmnd = common->data_size;
+               common->phase_error = 1;
+       }
+       common->residue = common->data_size;
+       common->usb_amount_left = common->data_size;
+
+       /* Conflicting data directions is a phase error */
+       if (common->data_dir != data_dir && common->data_size_from_cmnd > 0) {
+               common->phase_error = 1;
+               return -EINVAL;
+       }
+
+       /* Verify the length of the command itself */
+       if (cmnd_size != common->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 <= common->cmnd_size) {
+                       DBG(common, "%s is buggy! Expected length %d "
+                           "but we got %d\n", name,
+                           cmnd_size, common->cmnd_size);
+                       cmnd_size = common->cmnd_size;
+               } else {
+                       common->phase_error = 1;
+                       return -EINVAL;
+               }
+       }
+
+       /* Check that the LUN values are consistent */
+       if (common->lun != lun)
+               DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
+                   common->lun, lun);
+
+       /* Check the LUN */
+       curlun = common->curlun;
+       if (curlun) {
+               if (common->cmnd[0] != REQUEST_SENSE) {
+                       curlun->sense_data = SS_NO_SENSE;
+                       curlun->sense_data_info = 0;
+                       curlun->info_valid = 0;
+               }
+       } else {
+               common->bad_lun_okay = 0;
+
+               /*
+                * INQUIRY and REQUEST SENSE commands are explicitly allowed
+                * to use unsupported LUNs; all others may not.
+                */
+               if (common->cmnd[0] != INQUIRY &&
+                   common->cmnd[0] != REQUEST_SENSE) {
+                       DBG(common, "unsupported LUN %d\n", common->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 &&
+           common->cmnd[0] != INQUIRY &&
+           common->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 */
+       common->cmnd[1] &= 0x1f;                        /* Mask away the LUN */
+       for (i = 1; i < cmnd_size; ++i) {
+               if (common->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_common *common,
+               int cmnd_size, enum data_direction data_dir,
+               unsigned int mask, int needs_medium, const char *name)
+{
+       if (common->curlun)
+               common->data_size_from_cmnd <<= common->curlun->blkbits;
+       return check_command(common, cmnd_size, data_dir,
+                       mask, needs_medium, name);
+}
+
+static int do_scsi_command(struct fsg_common *common)
+{
+       struct fsg_buffhd       *bh;
+       int                     rc;
+       int                     reply = -EINVAL;
+       int                     i;
+       static char             unknown[16];
+
+       dump_cdb(common);
+
+       /* Wait for the next buffer to become available for data or status */
+       bh = common->next_buffhd_to_fill;
+       common->next_buffhd_to_drain = bh;
+       while (bh->state != BUF_STATE_EMPTY) {
+               rc = sleep_thread(common);
+               if (rc)
+                       return rc;
+       }
+       common->phase_error = 0;
+       common->short_packet_received = 0;
+
+       down_read(&common->filesem);    /* We're using the backing file */
+       switch (common->cmnd[0]) {
+
+       case INQUIRY:
+               common->data_size_from_cmnd = common->cmnd[4];
+               reply = check_command(common, 6, DATA_DIR_TO_HOST,
+                                     (1<<4), 0,
+                                     "INQUIRY");
+               if (reply == 0)
+                       reply = do_inquiry(common, bh);
+               break;
+
+       case MODE_SELECT:
+               common->data_size_from_cmnd = common->cmnd[4];
+               reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+                                     (1<<1) | (1<<4), 0,
+                                     "MODE SELECT(6)");
+               if (reply == 0)
+                       reply = do_mode_select(common, bh);
+               break;
+
+       case MODE_SELECT_10:
+               common->data_size_from_cmnd =
+                       get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+                                     (1<<1) | (3<<7), 0,
+                                     "MODE SELECT(10)");
+               if (reply == 0)
+                       reply = do_mode_select(common, bh);
+               break;
+
+       case MODE_SENSE:
+               common->data_size_from_cmnd = common->cmnd[4];
+               reply = check_command(common, 6, DATA_DIR_TO_HOST,
+                                     (1<<1) | (1<<2) | (1<<4), 0,
+                                     "MODE SENSE(6)");
+               if (reply == 0)
+                       reply = do_mode_sense(common, bh);
+               break;
+
+       case MODE_SENSE_10:
+               common->data_size_from_cmnd =
+                       get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command(common, 10, DATA_DIR_TO_HOST,
+                                     (1<<1) | (1<<2) | (3<<7), 0,
+                                     "MODE SENSE(10)");
+               if (reply == 0)
+                       reply = do_mode_sense(common, bh);
+               break;
+
+       case ALLOW_MEDIUM_REMOVAL:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, 6, DATA_DIR_NONE,
+                                     (1<<4), 0,
+                                     "PREVENT-ALLOW MEDIUM REMOVAL");
+               if (reply == 0)
+                       reply = do_prevent_allow(common);
+               break;
+
+       case READ_6:
+               i = common->cmnd[4];
+               common->data_size_from_cmnd = (i == 0) ? 256 : i;
+               reply = check_command_size_in_blocks(common, 6,
+                                     DATA_DIR_TO_HOST,
+                                     (7<<1) | (1<<4), 1,
+                                     "READ(6)");
+               if (reply == 0)
+                       reply = do_read(common);
+               break;
+
+       case READ_10:
+               common->data_size_from_cmnd =
+                               get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command_size_in_blocks(common, 10,
+                                     DATA_DIR_TO_HOST,
+                                     (1<<1) | (0xf<<2) | (3<<7), 1,
+                                     "READ(10)");
+               if (reply == 0)
+                       reply = do_read(common);
+               break;
+
+       case READ_12:
+               common->data_size_from_cmnd =
+                               get_unaligned_be32(&common->cmnd[6]);
+               reply = check_command_size_in_blocks(common, 12,
+                                     DATA_DIR_TO_HOST,
+                                     (1<<1) | (0xf<<2) | (0xf<<6), 1,
+                                     "READ(12)");
+               if (reply == 0)
+                       reply = do_read(common);
+               break;
+
+       case READ_CAPACITY:
+               common->data_size_from_cmnd = 8;
+               reply = check_command(common, 10, DATA_DIR_TO_HOST,
+                                     (0xf<<2) | (1<<8), 1,
+                                     "READ CAPACITY");
+               if (reply == 0)
+                       reply = do_read_capacity(common, bh);
+               break;
+
+       case READ_HEADER:
+               if (!common->curlun || !common->curlun->cdrom)
+                       goto unknown_cmnd;
+               common->data_size_from_cmnd =
+                       get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command(common, 10, DATA_DIR_TO_HOST,
+                                     (3<<7) | (0x1f<<1), 1,
+                                     "READ HEADER");
+               if (reply == 0)
+                       reply = do_read_header(common, bh);
+               break;
+
+       case READ_TOC:
+               if (!common->curlun || !common->curlun->cdrom)
+                       goto unknown_cmnd;
+               common->data_size_from_cmnd =
+                       get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command(common, 10, DATA_DIR_TO_HOST,
+                                     (7<<6) | (1<<1), 1,
+                                     "READ TOC");
+               if (reply == 0)
+                       reply = do_read_toc(common, bh);
+               break;
+
+       case READ_FORMAT_CAPACITIES:
+               common->data_size_from_cmnd =
+                       get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command(common, 10, DATA_DIR_TO_HOST,
+                                     (3<<7), 1,
+                                     "READ FORMAT CAPACITIES");
+               if (reply == 0)
+                       reply = do_read_format_capacities(common, bh);
+               break;
+
+       case REQUEST_SENSE:
+               common->data_size_from_cmnd = common->cmnd[4];
+               reply = check_command(common, 6, DATA_DIR_TO_HOST,
+                                     (1<<4), 0,
+                                     "REQUEST SENSE");
+               if (reply == 0)
+                       reply = do_request_sense(common, bh);
+               break;
+
+       case START_STOP:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, 6, DATA_DIR_NONE,
+                                     (1<<1) | (1<<4), 0,
+                                     "START-STOP UNIT");
+               if (reply == 0)
+                       reply = do_start_stop(common);
+               break;
+
+       case SYNCHRONIZE_CACHE:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, 10, DATA_DIR_NONE,
+                                     (0xf<<2) | (3<<7), 1,
+                                     "SYNCHRONIZE CACHE");
+               if (reply == 0)
+                       reply = do_synchronize_cache(common);
+               break;
+
+       case TEST_UNIT_READY:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, 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:
+               common->data_size_from_cmnd = 0;
+               reply = check_command(common, 10, DATA_DIR_NONE,
+                                     (1<<1) | (0xf<<2) | (3<<7), 1,
+                                     "VERIFY");
+               if (reply == 0)
+                       reply = do_verify(common);
+               break;
+
+       case WRITE_6:
+               i = common->cmnd[4];
+               common->data_size_from_cmnd = (i == 0) ? 256 : i;
+               reply = check_command_size_in_blocks(common, 6,
+                                     DATA_DIR_FROM_HOST,
+                                     (7<<1) | (1<<4), 1,
+                                     "WRITE(6)");
+               if (reply == 0)
+                       reply = do_write(common);
+               break;
+
+       case WRITE_10:
+               common->data_size_from_cmnd =
+                               get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command_size_in_blocks(common, 10,
+                                     DATA_DIR_FROM_HOST,
+                                     (1<<1) | (0xf<<2) | (3<<7), 1,
+                                     "WRITE(10)");
+               if (reply == 0)
+                       reply = do_write(common);
+               break;
+
+       case WRITE_12:
+               common->data_size_from_cmnd =
+                               get_unaligned_be32(&common->cmnd[6]);
+               reply = check_command_size_in_blocks(common, 12,
+                                     DATA_DIR_FROM_HOST,
+                                     (1<<1) | (0xf<<2) | (0xf<<6), 1,
+                                     "WRITE(12)");
+               if (reply == 0)
+                       reply = do_write(common);
+               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:
+               common->data_size_from_cmnd = 0;
+               sprintf(unknown, "Unknown x%02x", common->cmnd[0]);
+               reply = check_command(common, common->cmnd_size,
+                                     DATA_DIR_UNKNOWN, ~0, 0, unknown);
+               if (reply == 0) {
+                       common->curlun->sense_data = SS_INVALID_COMMAND;
+                       reply = -EINVAL;
+               }
+               break;
+       }
+       up_read(&common->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 && common->data_dir == DATA_DIR_TO_HOST) {
+               reply = min((u32)reply, common->data_size_from_cmnd);
+               bh->inreq->length = reply;
+               bh->state = BUF_STATE_FULL;
+               common->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;
+       struct fsg_common       *common = fsg->common;
+
+       /* 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 (common->can_stall) {
+                       fsg_set_halt(fsg, fsg->bulk_out);
+                       halt_bulk_in_endpoint(fsg);
+               }
+               return -EINVAL;
+       }
+
+       /* Save the command for later */
+       common->cmnd_size = cbw->Length;
+       memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
+       if (cbw->Flags & US_BULK_FLAG_IN)
+               common->data_dir = DATA_DIR_TO_HOST;
+       else
+               common->data_dir = DATA_DIR_FROM_HOST;
+       common->data_size = le32_to_cpu(cbw->DataTransferLength);
+       if (common->data_size == 0)
+               common->data_dir = DATA_DIR_NONE;
+       common->lun = cbw->Lun;
+       if (common->lun >= 0 && common->lun < common->nluns)
+               common->curlun = &common->luns[common->lun];
+       else
+               common->curlun = NULL;
+       common->tag = cbw->Tag;
+       return 0;
+}
+
+static int get_next_command(struct fsg_common *common)
+{
+       struct fsg_buffhd       *bh;
+       int                     rc = 0;
+
+       /* Wait for the next buffer to become available */
+       bh = common->next_buffhd_to_fill;
+       while (bh->state != BUF_STATE_EMPTY) {
+               rc = sleep_thread(common);
+               if (rc)
+                       return rc;
+       }
+
+       /* Queue a request to read a Bulk-only CBW */
+       set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
+       if (!start_out_transfer(common, bh))
+               /* Don't know what to do if common->fsg is NULL */
+               return -EIO;
+
+       /*
+        * 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(common);
+               if (rc)
+                       return rc;
+       }
+       smp_rmb();
+       rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
+       bh->state = BUF_STATE_EMPTY;
+
+       return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
+               struct usb_request **preq)
+{
+       *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
+       if (*preq)
+               return 0;
+       ERROR(common, "can't allocate request for %s\n", ep->name);
+       return -ENOMEM;
+}
+
+/* Reset interface setting and re-init endpoint state (toggle etc). */
+static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
+{
+       struct fsg_dev *fsg;
+       int i, rc = 0;
+
+       if (common->running)
+               DBG(common, "reset interface\n");
+
+reset:
+       /* Deallocate the requests */
+       if (common->fsg) {
+               fsg = common->fsg;
+
+               for (i = 0; i < fsg_num_buffers; ++i) {
+                       struct fsg_buffhd *bh = &common->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;
+                       }
+               }
+
+               /* 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;
+               }
+
+               common->fsg = NULL;
+               wake_up(&common->fsg_wait);
+       }
+
+       common->running = 0;
+       if (!new_fsg || rc)
+               return rc;
+
+       common->fsg = new_fsg;
+       fsg = common->fsg;
+
+       /* Enable the endpoints */
+       rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
+       if (rc)
+               goto reset;
+       rc = usb_ep_enable(fsg->bulk_in);
+       if (rc)
+               goto reset;
+       fsg->bulk_in->driver_data = common;
+       fsg->bulk_in_enabled = 1;
+
+       rc = config_ep_by_speed(common->gadget, &(fsg->function),
+                               fsg->bulk_out);
+       if (rc)
+               goto reset;
+       rc = usb_ep_enable(fsg->bulk_out);
+       if (rc)
+               goto reset;
+       fsg->bulk_out->driver_data = common;
+       fsg->bulk_out_enabled = 1;
+       common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
+       clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
+
+       /* Allocate the requests */
+       for (i = 0; i < fsg_num_buffers; ++i) {
+               struct fsg_buffhd       *bh = &common->buffhds[i];
+
+               rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
+               if (rc)
+                       goto reset;
+               rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
+               if (rc)
+                       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;
+       }
+
+       common->running = 1;
+       for (i = 0; i < common->nluns; ++i)
+               common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+       return rc;
+}
+
+
+/****************************** ALT CONFIGS ******************************/
+
+static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct fsg_dev *fsg = fsg_from_func(f);
+       fsg->common->new_fsg = fsg;
+       raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+       return USB_GADGET_DELAYED_STATUS;
+}
+
+static void fsg_disable(struct usb_function *f)
+{
+       struct fsg_dev *fsg = fsg_from_func(f);
+       fsg->common->new_fsg = NULL;
+       raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void handle_exception(struct fsg_common *common)
+{
+       siginfo_t               info;
+       int                     i;
+       struct fsg_buffhd       *bh;
+       enum fsg_state          old_state;
+       struct fsg_lun          *curlun;
+       unsigned int            exception_req_tag;
+
+       /*
+        * Clear the existing signals.  Anything but SIGUSR1 is converted
+        * into a high-priority EXIT exception.
+        */
+       for (;;) {
+               int sig =
+                       dequeue_signal_lock(current, &current->blocked, &info);
+               if (!sig)
+                       break;
+               if (sig != SIGUSR1) {
+                       if (common->state < FSG_STATE_EXIT)
+                               DBG(common, "Main thread exiting on signal\n");
+                       raise_exception(common, FSG_STATE_EXIT);
+               }
+       }
+
+       /* Cancel all the pending transfers */
+       if (likely(common->fsg)) {
+               for (i = 0; i < fsg_num_buffers; ++i) {
+                       bh = &common->buffhds[i];
+                       if (bh->inreq_busy)
+                               usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
+                       if (bh->outreq_busy)
+                               usb_ep_dequeue(common->fsg->bulk_out,
+                                              bh->outreq);
+               }
+
+               /* Wait until everything is idle */
+               for (;;) {
+                       int num_active = 0;
+                       for (i = 0; i < fsg_num_buffers; ++i) {
+                               bh = &common->buffhds[i];
+                               num_active += bh->inreq_busy + bh->outreq_busy;
+                       }
+                       if (num_active == 0)
+                               break;
+                       if (sleep_thread(common))
+                               return;
+               }
+
+               /* Clear out the controller's fifos */
+               if (common->fsg->bulk_in_enabled)
+                       usb_ep_fifo_flush(common->fsg->bulk_in);
+               if (common->fsg->bulk_out_enabled)
+                       usb_ep_fifo_flush(common->fsg->bulk_out);
+       }
+
+       /*
+        * Reset the I/O buffer states and pointers, the SCSI
+        * state, and the exception.  Then invoke the handler.
+        */
+       spin_lock_irq(&common->lock);
+
+       for (i = 0; i < fsg_num_buffers; ++i) {
+               bh = &common->buffhds[i];
+               bh->state = BUF_STATE_EMPTY;
+       }
+       common->next_buffhd_to_fill = &common->buffhds[0];
+       common->next_buffhd_to_drain = &common->buffhds[0];
+       exception_req_tag = common->exception_req_tag;
+       old_state = common->state;
+
+       if (old_state == FSG_STATE_ABORT_BULK_OUT)
+               common->state = FSG_STATE_STATUS_PHASE;
+       else {
+               for (i = 0; i < common->nluns; ++i) {
+                       curlun = &common->luns[i];
+                       curlun->prevent_medium_removal = 0;
+                       curlun->sense_data = SS_NO_SENSE;
+                       curlun->unit_attention_data = SS_NO_SENSE;
+                       curlun->sense_data_info = 0;
+                       curlun->info_valid = 0;
+               }
+               common->state = FSG_STATE_IDLE;
+       }
+       spin_unlock_irq(&common->lock);
+
+       /* Carry out any extra actions required for the exception */
+       switch (old_state) {
+       case FSG_STATE_ABORT_BULK_OUT:
+               send_status(common);
+               spin_lock_irq(&common->lock);
+               if (common->state == FSG_STATE_STATUS_PHASE)
+                       common->state = FSG_STATE_IDLE;
+               spin_unlock_irq(&common->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 (!fsg_is_set(common))
+                       break;
+               if (test_and_clear_bit(IGNORE_BULK_OUT,
+                                      &common->fsg->atomic_bitflags))
+                       usb_ep_clear_halt(common->fsg->bulk_in);
+
+               if (common->ep0_req_tag == exception_req_tag)
+                       ep0_queue(common);      /* Complete the status stage */
+
+               /*
+                * 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 < common->nluns; ++i) */
+               /*      common->luns[i].unit_attention_data = */
+               /*              SS_RESET_OCCURRED;  */
+               break;
+
+       case FSG_STATE_CONFIG_CHANGE:
+               do_set_interface(common, common->new_fsg);
+               if (common->new_fsg)
+                       usb_composite_setup_continue(common->cdev);
+               break;
+
+       case FSG_STATE_EXIT:
+       case FSG_STATE_TERMINATED:
+               do_set_interface(common, NULL);         /* Free resources */
+               spin_lock_irq(&common->lock);
+               common->state = FSG_STATE_TERMINATED;   /* Stop the thread */
+               spin_unlock_irq(&common->lock);
+               break;
+
+       case FSG_STATE_INTERFACE_CHANGE:
+       case FSG_STATE_DISCONNECT:
+       case FSG_STATE_COMMAND_PHASE:
+       case FSG_STATE_DATA_PHASE:
+       case FSG_STATE_STATUS_PHASE:
+       case FSG_STATE_IDLE:
+               break;
+       }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int fsg_main_thread(void *common_)
+{
+       struct fsg_common       *common = common_;
+
+       /*
+        * 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 (common->state != FSG_STATE_TERMINATED) {
+               if (exception_in_progress(common) || signal_pending(current)) {
+                       handle_exception(common);
+                       continue;
+               }
+
+               if (!common->running) {
+                       sleep_thread(common);
+                       continue;
+               }
+
+               if (get_next_command(common))
+                       continue;
+
+               spin_lock_irq(&common->lock);
+               if (!exception_in_progress(common))
+                       common->state = FSG_STATE_DATA_PHASE;
+               spin_unlock_irq(&common->lock);
+
+               if (do_scsi_command(common) || finish_reply(common))
+                       continue;
+
+               spin_lock_irq(&common->lock);
+               if (!exception_in_progress(common))
+                       common->state = FSG_STATE_STATUS_PHASE;
+               spin_unlock_irq(&common->lock);
+
+               if (send_status(common))
+                       continue;
+
+               spin_lock_irq(&common->lock);
+               if (!exception_in_progress(common))
+                       common->state = FSG_STATE_IDLE;
+               spin_unlock_irq(&common->lock);
+       }
+
+       spin_lock_irq(&common->lock);
+       common->thread_task = NULL;
+       spin_unlock_irq(&common->lock);
+
+       if (!common->ops || !common->ops->thread_exits
+        || common->ops->thread_exits(common) < 0) {
+               struct fsg_lun *curlun = common->luns;
+               unsigned i = common->nluns;
+
+               down_write(&common->filesem);
+               for (; i--; ++curlun) {
+                       if (!fsg_lun_is_open(curlun))
+                               continue;
+
+                       fsg_lun_close(curlun);
+                       curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+               }
+               up_write(&common->filesem);
+       }
+
+       /* Let fsg_unbind() know the thread has exited */
+       complete_and_exit(&common->thread_notifier, 0);
+}
+
+
+/*************************** DEVICE ATTRIBUTES ***************************/
+
+static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
+static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
+static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+
+static struct device_attribute dev_attr_ro_cdrom =
+       __ATTR(ro, 0444, fsg_show_ro, NULL);
+static struct device_attribute dev_attr_file_nonremovable =
+       __ATTR(file, 0444, fsg_show_file, NULL);
+
+
+/****************************** FSG COMMON ******************************/
+
+static void fsg_common_release(struct kref *ref);
+
+static void fsg_lun_release(struct device *dev)
+{
+       /* Nothing needs to be done */
+}
+
+static inline void fsg_common_get(struct fsg_common *common)
+{
+       kref_get(&common->ref);
+}
+
+static inline void fsg_common_put(struct fsg_common *common)
+{
+       kref_put(&common->ref, fsg_common_release);
+}
+
+static struct fsg_common *fsg_common_init(struct fsg_common *common,
+                                         struct usb_composite_dev *cdev,
+                                         struct fsg_config *cfg)
+{
+       struct usb_gadget *gadget = cdev->gadget;
+       struct fsg_buffhd *bh;
+       struct fsg_lun *curlun;
+       struct fsg_lun_config *lcfg;
+       int nluns, i, rc;
+       char *pathbuf;
+
+       rc = fsg_num_buffers_validate();
+       if (rc != 0)
+               return ERR_PTR(rc);
+
+       /* Find out how many LUNs there should be */
+       nluns = cfg->nluns;
+       if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+               dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
+               return ERR_PTR(-EINVAL);
+       }
+
+       /* Allocate? */
+       if (!common) {
+               common = kzalloc(sizeof *common, GFP_KERNEL);
+               if (!common)
+                       return ERR_PTR(-ENOMEM);
+               common->free_storage_on_release = 1;
+       } else {
+               memset(common, 0, sizeof *common);
+               common->free_storage_on_release = 0;
+       }
+
+       common->buffhds = kcalloc(fsg_num_buffers,
+                                 sizeof *(common->buffhds), GFP_KERNEL);
+       if (!common->buffhds) {
+               if (common->free_storage_on_release)
+                       kfree(common);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       common->ops = cfg->ops;
+       common->private_data = cfg->private_data;
+
+       common->gadget = gadget;
+       common->ep0 = gadget->ep0;
+       common->ep0req = cdev->req;
+       common->cdev = cdev;
+
+       /* Maybe allocate device-global string IDs, and patch descriptors */
+       if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+               rc = usb_string_id(cdev);
+               if (unlikely(rc < 0))
+                       goto error_release;
+               fsg_strings[FSG_STRING_INTERFACE].id = rc;
+               fsg_intf_desc.iInterface = rc;
+       }
+
+       /*
+        * Create the LUNs, open their backing files, and register the
+        * LUN devices in sysfs.
+        */
+       curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
+       if (unlikely(!curlun)) {
+               rc = -ENOMEM;
+               goto error_release;
+       }
+       common->luns = curlun;
+
+       init_rwsem(&common->filesem);
+
+       for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
+               curlun->cdrom = !!lcfg->cdrom;
+               curlun->ro = lcfg->cdrom || lcfg->ro;
+               curlun->initially_ro = curlun->ro;
+               curlun->removable = lcfg->removable;
+               curlun->dev.release = fsg_lun_release;
+               curlun->dev.parent = &gadget->dev;
+               /* curlun->dev.driver = &fsg_driver.driver; XXX */
+               dev_set_drvdata(&curlun->dev, &common->filesem);
+               dev_set_name(&curlun->dev, "lun%d", i);
+
+               rc = device_register(&curlun->dev);
+               if (rc) {
+                       INFO(common, "failed to register LUN%d: %d\n", i, rc);
+                       common->nluns = i;
+                       put_device(&curlun->dev);
+                       goto error_release;
+               }
+
+               rc = device_create_file(&curlun->dev,
+                                       curlun->cdrom
+                                     ? &dev_attr_ro_cdrom
+                                     : &dev_attr_ro);
+               if (rc)
+                       goto error_luns;
+               rc = device_create_file(&curlun->dev,
+                                       curlun->removable
+                                     ? &dev_attr_file
+                                     : &dev_attr_file_nonremovable);
+               if (rc)
+                       goto error_luns;
+               rc = device_create_file(&curlun->dev, &dev_attr_nofua);
+               if (rc)
+                       goto error_luns;
+
+               if (lcfg->filename) {
+                       rc = fsg_lun_open(curlun, lcfg->filename);
+                       if (rc)
+                               goto error_luns;
+               } else if (!curlun->removable) {
+                       ERROR(common, "no file given for LUN%d\n", i);
+                       rc = -EINVAL;
+                       goto error_luns;
+               }
+       }
+       common->nluns = nluns;
+
+       /* Data buffers cyclic list */
+       bh = common->buffhds;
+       i = fsg_num_buffers;
+       goto buffhds_first_it;
+       do {
+               bh->next = bh + 1;
+               ++bh;
+buffhds_first_it:
+               bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+               if (unlikely(!bh->buf)) {
+                       rc = -ENOMEM;
+                       goto error_release;
+               }
+       } while (--i);
+       bh->next = common->buffhds;
+
+       /* Prepare inquiryString */
+       if (cfg->release != 0xffff) {
+               i = cfg->release;
+       } else {
+               i = usb_gadget_controller_number(gadget);
+               if (i >= 0) {
+                       i = 0x0300 + i;
+               } else {
+                       WARNING(common, "controller '%s' not recognized\n",
+                               gadget->name);
+                       i = 0x0399;
+               }
+       }
+       snprintf(common->inquiry_string, sizeof common->inquiry_string,
+                "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
+                /* Assume product name dependent on the first LUN */
+                cfg->product_name ?: (common->luns->cdrom
+                                    ? "File-Stor Gadget"
+                                    : "File-CD Gadget"),
+                i);
+
+       /*
+        * Some peripheral controllers are known not to be able to
+        * halt bulk endpoints correctly.  If one of them is present,
+        * disable stalls.
+        */
+       common->can_stall = cfg->can_stall &&
+               !(gadget_is_at91(common->gadget));
+
+       spin_lock_init(&common->lock);
+       kref_init(&common->ref);
+
+       /* Tell the thread to start working */
+       common->thread_task =
+               kthread_create(fsg_main_thread, common, "file-storage");
+       if (IS_ERR(common->thread_task)) {
+               rc = PTR_ERR(common->thread_task);
+               goto error_release;
+       }
+       init_completion(&common->thread_notifier);
+       init_waitqueue_head(&common->fsg_wait);
+
+       /* Information */
+       INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+       INFO(common, "Number of LUNs=%d\n", common->nluns);
+
+       pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+       for (i = 0, nluns = common->nluns, curlun = common->luns;
+            i < nluns;
+            ++curlun, ++i) {
+               char *p = "(no medium)";
+               if (fsg_lun_is_open(curlun)) {
+                       p = "(error)";
+                       if (pathbuf) {
+                               p = d_path(&curlun->filp->f_path,
+                                          pathbuf, PATH_MAX);
+                               if (IS_ERR(p))
+                                       p = "(error)";
+                       }
+               }
+               LINFO(curlun, "LUN: %s%s%sfile: %s\n",
+                     curlun->removable ? "removable " : "",
+                     curlun->ro ? "read only " : "",
+                     curlun->cdrom ? "CD-ROM " : "",
+                     p);
+       }
+       kfree(pathbuf);
+
+       DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+
+       wake_up_process(common->thread_task);
+
+       return common;
+
+error_luns:
+       common->nluns = i + 1;
+error_release:
+       common->state = FSG_STATE_TERMINATED;   /* The thread is dead */
+       /* Call fsg_common_release() directly, ref might be not initialised. */
+       fsg_common_release(&common->ref);
+       return ERR_PTR(rc);
+}
+
+static void fsg_common_release(struct kref *ref)
+{
+       struct fsg_common *common = container_of(ref, struct fsg_common, ref);
+
+       /* If the thread isn't already dead, tell it to exit now */
+       if (common->state != FSG_STATE_TERMINATED) {
+               raise_exception(common, FSG_STATE_EXIT);
+               wait_for_completion(&common->thread_notifier);
+       }
+
+       if (likely(common->luns)) {
+               struct fsg_lun *lun = common->luns;
+               unsigned i = common->nluns;
+
+               /* In error recovery common->nluns may be zero. */
+               for (; i; --i, ++lun) {
+                       device_remove_file(&lun->dev, &dev_attr_nofua);
+                       device_remove_file(&lun->dev,
+                                          lun->cdrom
+                                        ? &dev_attr_ro_cdrom
+                                        : &dev_attr_ro);
+                       device_remove_file(&lun->dev,
+                                          lun->removable
+                                        ? &dev_attr_file
+                                        : &dev_attr_file_nonremovable);
+                       fsg_lun_close(lun);
+                       device_unregister(&lun->dev);
+               }
+
+               kfree(common->luns);
+       }
+
+       {
+               struct fsg_buffhd *bh = common->buffhds;
+               unsigned i = fsg_num_buffers;
+               do {
+                       kfree(bh->buf);
+               } while (++bh, --i);
+       }
+
+       kfree(common->buffhds);
+       if (common->free_storage_on_release)
+               kfree(common);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct fsg_dev          *fsg = fsg_from_func(f);
+       struct fsg_common       *common = fsg->common;
+
+       DBG(fsg, "unbind\n");
+       if (fsg->common->fsg == fsg) {
+               fsg->common->new_fsg = NULL;
+               raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+               /* FIXME: make interruptible or killable somehow? */
+               wait_event(common->fsg_wait, common->fsg != fsg);
+       }
+
+       fsg_common_put(common);
+       usb_free_descriptors(fsg->function.descriptors);
+       usb_free_descriptors(fsg->function.hs_descriptors);
+       usb_free_descriptors(fsg->function.ss_descriptors);
+       kfree(fsg);
+}
+
+static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct fsg_dev          *fsg = fsg_from_func(f);
+       struct usb_gadget       *gadget = c->cdev->gadget;
+       int                     i;
+       struct usb_ep           *ep;
+
+       fsg->gadget = gadget;
+
+       /* New interface */
+       i = usb_interface_id(c, f);
+       if (i < 0)
+               return i;
+       fsg_intf_desc.bInterfaceNumber = i;
+       fsg->interface_number = i;
+
+       /* Find all the endpoints we will use */
+       ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
+       if (!ep)
+               goto autoconf_fail;
+       ep->driver_data = fsg->common;  /* 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->common;  /* claim the endpoint */
+       fsg->bulk_out = ep;
+
+       /* Copy descriptors */
+       f->descriptors = usb_copy_descriptors(fsg_fs_function);
+       if (unlikely(!f->descriptors))
+               return -ENOMEM;
+
+       if (gadget_is_dualspeed(gadget)) {
+               /* 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;
+               f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
+               if (unlikely(!f->hs_descriptors)) {
+                       usb_free_descriptors(f->descriptors);
+                       return -ENOMEM;
+               }
+       }
+
+       if (gadget_is_superspeed(gadget)) {
+               unsigned        max_burst;
+
+               /* Calculate bMaxBurst, we know packet size is 1024 */
+               max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+               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;
+
+               f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+               if (unlikely(!f->ss_descriptors)) {
+                       usb_free_descriptors(f->hs_descriptors);
+                       usb_free_descriptors(f->descriptors);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+
+autoconf_fail:
+       ERROR(fsg, "unable to autoconfigure all endpoints\n");
+       return -ENOTSUPP;
+}
+
+
+/****************************** ADD FUNCTION ******************************/
+
+static struct usb_gadget_strings *fsg_strings_array[] = {
+       &fsg_stringtab,
+       NULL,
+};
+
+static int fsg_bind_config(struct usb_composite_dev *cdev,
+                          struct usb_configuration *c,
+                          struct fsg_common *common)
+{
+       struct fsg_dev *fsg;
+       int rc;
+
+       fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+       if (unlikely(!fsg))
+               return -ENOMEM;
+
+       fsg->function.name        = FSG_DRIVER_DESC;
+       fsg->function.strings     = fsg_strings_array;
+       fsg->function.bind        = fsg_bind;
+       fsg->function.unbind      = fsg_unbind;
+       fsg->function.setup       = fsg_setup;
+       fsg->function.set_alt     = fsg_set_alt;
+       fsg->function.disable     = fsg_disable;
+
+       fsg->common               = common;
+       /*
+        * Our caller holds a reference to common structure so we
+        * don't have to be worry about it being freed until we return
+        * from this function.  So instead of incrementing counter now
+        * and decrement in error recovery we increment it only when
+        * call to usb_add_function() was successful.
+        */
+
+       rc = usb_add_function(c, &fsg->function);
+       if (unlikely(rc))
+               kfree(fsg);
+       else
+               fsg_common_get(fsg->common);
+       return rc;
+}
+
+
+/************************* Module parameters *************************/
+
+struct fsg_module_parameters {
+       char            *file[FSG_MAX_LUNS];
+       bool            ro[FSG_MAX_LUNS];
+       bool            removable[FSG_MAX_LUNS];
+       bool            cdrom[FSG_MAX_LUNS];
+       bool            nofua[FSG_MAX_LUNS];
+
+       unsigned int    file_count, ro_count, removable_count, cdrom_count;
+       unsigned int    nofua_count;
+       unsigned int    luns;   /* nluns */
+       bool            stall;  /* can_stall */
+};
+
+#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)      \
+       module_param_array_named(prefix ## name, params.name, type,     \
+                                &prefix ## params.name ## _count,      \
+                                S_IRUGO);                              \
+       MODULE_PARM_DESC(prefix ## name, desc)
+
+#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)            \
+       module_param_named(prefix ## name, params.name, type,           \
+                          S_IRUGO);                                    \
+       MODULE_PARM_DESC(prefix ## name, desc)
+
+#define FSG_MODULE_PARAMETERS(prefix, params)                          \
+       _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,            \
+                               "names of backing files or devices");   \
+       _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,               \
+                               "true to force read-only");             \
+       _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,        \
+                               "true to simulate removable media");    \
+       _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,            \
+                               "true to simulate CD-ROM instead of disk"); \
+       _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool,            \
+                               "true to ignore SCSI WRITE(10,12) FUA bit"); \
+       _FSG_MODULE_PARAM(prefix, params, luns, uint,                   \
+                         "number of LUNs");                            \
+       _FSG_MODULE_PARAM(prefix, params, stall, bool,                  \
+                         "false to prevent bulk stalls")
+
+static void
+fsg_config_from_params(struct fsg_config *cfg,
+                      const struct fsg_module_parameters *params)
+{
+       struct fsg_lun_config *lun;
+       unsigned i;
+
+       /* Configure LUNs */
+       cfg->nluns =
+               min(params->luns ?: (params->file_count ?: 1u),
+                   (unsigned)FSG_MAX_LUNS);
+       for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
+               lun->ro = !!params->ro[i];
+               lun->cdrom = !!params->cdrom[i];
+               lun->removable = !!params->removable[i];
+               lun->filename =
+                       params->file_count > i && params->file[i][0]
+                       ? params->file[i]
+                       : 0;
+       }
+
+       /* Let MSF use defaults */
+       cfg->vendor_name = 0;
+       cfg->product_name = 0;
+       cfg->release = 0xffff;
+
+       cfg->ops = NULL;
+       cfg->private_data = NULL;
+
+       /* Finalise */
+       cfg->can_stall = params->stall;
+}
+
+static inline struct fsg_common *
+fsg_common_from_params(struct fsg_common *common,
+                      struct usb_composite_dev *cdev,
+                      const struct fsg_module_parameters *params)
+       __attribute__((unused));
+static inline struct fsg_common *
+fsg_common_from_params(struct fsg_common *common,
+                      struct usb_composite_dev *cdev,
+                      const struct fsg_module_parameters *params)
+{
+       struct fsg_config cfg;
+       fsg_config_from_params(&cfg, params);
+       return fsg_common_init(common, cdev, &cfg);
+}
diff --git a/drivers/staging/ccg/f_rndis.c b/drivers/staging/ccg/f_rndis.c
new file mode 100644 (file)
index 0000000..b1681e4
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ * f_rndis.c -- RNDIS link function driver
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2009 Samsung Electronics
+ *                    Author: Michal Nazarewicz (mina86@mina86.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+
+#include <linux/atomic.h>
+
+#include "u_ether.h"
+#include "rndis.h"
+
+
+/*
+ * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
+ * been promoted instead of the standard CDC Ethernet.  The published RNDIS
+ * spec is ambiguous, incomplete, and needlessly complex.  Variants such as
+ * ActiveSync have even worse status in terms of specification.
+ *
+ * In short:  it's a protocol controlled by (and for) Microsoft, not for an
+ * Open ecosystem or markets.  Linux supports it *only* because Microsoft
+ * doesn't support the CDC Ethernet standard.
+ *
+ * The RNDIS data transfer model is complex, with multiple Ethernet packets
+ * per USB message, and out of band data.  The control model is built around
+ * what's essentially an "RNDIS RPC" protocol.  It's all wrapped in a CDC ACM
+ * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
+ * useless (they're ignored).  RNDIS expects to be the only function in its
+ * configuration, so it's no real help if you need composite devices; and
+ * it expects to be the first configuration too.
+ *
+ * There is a single technical advantage of RNDIS over CDC Ethernet, if you
+ * discount the fluff that its RPC can be made to deliver: it doesn't need
+ * a NOP altsetting for the data interface.  That lets it work on some of the
+ * "so smart it's stupid" hardware which takes over configuration changes
+ * from the software, and adds restrictions like "no altsettings".
+ *
+ * Unfortunately MSFT's RNDIS drivers are buggy.  They hang or oops, and
+ * have all sorts of contrary-to-specification oddities that can prevent
+ * them from working sanely.  Since bugfixes (or accurate specs, letting
+ * Linux work around those bugs) are unlikely to ever come from MSFT, you
+ * may want to avoid using RNDIS on purely operational grounds.
+ *
+ * Omissions from the RNDIS 1.0 specification include:
+ *
+ *   - Power management ... references data that's scattered around lots
+ *     of other documentation, which is incorrect/incomplete there too.
+ *
+ *   - There are various undocumented protocol requirements, like the need
+ *     to send garbage in some control-OUT messages.
+ *
+ *   - MS-Windows drivers sometimes emit undocumented requests.
+ */
+
+struct f_rndis {
+       struct gether                   port;
+       u8                              ctrl_id, data_id;
+       u8                              ethaddr[ETH_ALEN];
+       u32                             vendorID;
+       const char                      *manufacturer;
+       int                             config;
+
+       struct usb_ep                   *notify;
+       struct usb_request              *notify_req;
+       atomic_t                        notify_count;
+};
+
+static inline struct f_rndis *func_to_rndis(struct usb_function *f)
+{
+       return container_of(f, struct f_rndis, port.func);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static unsigned int bitrate(struct usb_gadget *g)
+{
+       if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+               return 13 * 1024 * 8 * 1000 * 8;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return 13 * 512 * 8 * 1000 * 8;
+       else
+               return 19 * 64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC      5       /* 1 << 5 == 32 msec */
+#define STATUS_BYTECOUNT               8       /* 8 bytes data */
+
+
+/* interface descriptor: */
+
+static struct usb_interface_descriptor rndis_control_intf = {
+       .bLength =              sizeof rndis_control_intf,
+       .bDescriptorType =      USB_DT_INTERFACE,
+
+       /* .bInterfaceNumber = DYNAMIC */
+       /* status endpoint is optional; this could be patched later */
+       .bNumEndpoints =        1,
+       .bInterfaceClass =      USB_CLASS_COMM,
+       .bInterfaceSubClass =   USB_CDC_SUBCLASS_ACM,
+       .bInterfaceProtocol =   USB_CDC_ACM_PROTO_VENDOR,
+       /* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc header_desc = {
+       .bLength =              sizeof header_desc,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_HEADER_TYPE,
+
+       .bcdCDC =               cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
+       .bLength =              sizeof call_mgmt_descriptor,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+
+       .bmCapabilities =       0x00,
+       .bDataInterface =       0x01,
+};
+
+static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
+       .bLength =              sizeof rndis_acm_descriptor,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+
+       .bmCapabilities =       0x00,
+};
+
+static struct usb_cdc_union_desc rndis_union_desc = {
+       .bLength =              sizeof(rndis_union_desc),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_UNION_TYPE,
+       /* .bMasterInterface0 = DYNAMIC */
+       /* .bSlaveInterface0 =  DYNAMIC */
+};
+
+/* the data interface has two bulk endpoints */
+
+static struct usb_interface_descriptor rndis_data_intf = {
+       .bLength =              sizeof rndis_data_intf,
+       .bDescriptorType =      USB_DT_INTERFACE,
+
+       /* .bInterfaceNumber = DYNAMIC */
+       .bNumEndpoints =        2,
+       .bInterfaceClass =      USB_CLASS_CDC_DATA,
+       .bInterfaceSubClass =   0,
+       .bInterfaceProtocol =   0,
+       /* .iInterface = DYNAMIC */
+};
+
+
+static struct usb_interface_assoc_descriptor
+rndis_iad_descriptor = {
+       .bLength =              sizeof rndis_iad_descriptor,
+       .bDescriptorType =      USB_DT_INTERFACE_ASSOCIATION,
+
+       .bFirstInterface =      0, /* XXX, hardcoded */
+       .bInterfaceCount =      2,      // control + data
+       .bFunctionClass =       USB_CLASS_COMM,
+       .bFunctionSubClass =    USB_CDC_SUBCLASS_ETHERNET,
+       .bFunctionProtocol =    USB_CDC_PROTO_NONE,
+       /* .iFunction = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor fs_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(STATUS_BYTECOUNT),
+       .bInterval =            1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor fs_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor fs_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *eth_fs_function[] = {
+       (struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+       /* control interface matches ACM, not Ethernet */
+       (struct usb_descriptor_header *) &rndis_control_intf,
+       (struct usb_descriptor_header *) &header_desc,
+       (struct usb_descriptor_header *) &call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &rndis_acm_descriptor,
+       (struct usb_descriptor_header *) &rndis_union_desc,
+       (struct usb_descriptor_header *) &fs_notify_desc,
+
+       /* data interface has no altsetting */
+       (struct usb_descriptor_header *) &rndis_data_intf,
+       (struct usb_descriptor_header *) &fs_in_desc,
+       (struct usb_descriptor_header *) &fs_out_desc,
+       NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor hs_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(STATUS_BYTECOUNT),
+       .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_endpoint_descriptor hs_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *eth_hs_function[] = {
+       (struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+       /* control interface matches ACM, not Ethernet */
+       (struct usb_descriptor_header *) &rndis_control_intf,
+       (struct usb_descriptor_header *) &header_desc,
+       (struct usb_descriptor_header *) &call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &rndis_acm_descriptor,
+       (struct usb_descriptor_header *) &rndis_union_desc,
+       (struct usb_descriptor_header *) &hs_notify_desc,
+
+       /* data interface has no altsetting */
+       (struct usb_descriptor_header *) &rndis_data_intf,
+       (struct usb_descriptor_header *) &hs_in_desc,
+       (struct usb_descriptor_header *) &hs_out_desc,
+       NULL,
+};
+
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(STATUS_BYTECOUNT),
+       .bInterval =            LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
+       .bLength =              sizeof ss_intr_comp_desc,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /* the following 3 values can be tweaked if necessary */
+       /* .bMaxBurst =         0, */
+       /* .bmAttributes =      0, */
+       .wBytesPerInterval =    cpu_to_le16(STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
+       .bLength =              sizeof ss_bulk_comp_desc,
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /* the following 2 values can be tweaked if necessary */
+       /* .bMaxBurst =         0, */
+       /* .bmAttributes =      0, */
+};
+
+static struct usb_descriptor_header *eth_ss_function[] = {
+       (struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+       /* control interface matches ACM, not Ethernet */
+       (struct usb_descriptor_header *) &rndis_control_intf,
+       (struct usb_descriptor_header *) &header_desc,
+       (struct usb_descriptor_header *) &call_mgmt_descriptor,
+       (struct usb_descriptor_header *) &rndis_acm_descriptor,
+       (struct usb_descriptor_header *) &rndis_union_desc,
+       (struct usb_descriptor_header *) &ss_notify_desc,
+       (struct usb_descriptor_header *) &ss_intr_comp_desc,
+
+       /* data interface has no altsetting */
+       (struct usb_descriptor_header *) &rndis_data_intf,
+       (struct usb_descriptor_header *) &ss_in_desc,
+       (struct usb_descriptor_header *) &ss_bulk_comp_desc,
+       (struct usb_descriptor_header *) &ss_out_desc,
+       (struct usb_descriptor_header *) &ss_bulk_comp_desc,
+       NULL,
+};
+
+/* string descriptors: */
+
+static struct usb_string rndis_string_defs[] = {
+       [0].s = "RNDIS Communications Control",
+       [1].s = "RNDIS Ethernet Data",
+       [2].s = "RNDIS",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings rndis_string_table = {
+       .language =             0x0409, /* en-us */
+       .strings =              rndis_string_defs,
+};
+
+static struct usb_gadget_strings *rndis_strings[] = {
+       &rndis_string_table,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct sk_buff *rndis_add_header(struct gether *port,
+                                       struct sk_buff *skb)
+{
+       struct sk_buff *skb2;
+
+       skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
+       if (skb2)
+               rndis_add_hdr(skb2);
+
+       dev_kfree_skb_any(skb);
+       return skb2;
+}
+
+static void rndis_response_available(void *_rndis)
+{
+       struct f_rndis                  *rndis = _rndis;
+       struct usb_request              *req = rndis->notify_req;
+       struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
+       __le32                          *data = req->buf;
+       int                             status;
+
+       if (atomic_inc_return(&rndis->notify_count) != 1)
+               return;
+
+       /* Send RNDIS RESPONSE_AVAILABLE notification; a
+        * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
+        *
+        * This is the only notification defined by RNDIS.
+        */
+       data[0] = cpu_to_le32(1);
+       data[1] = cpu_to_le32(0);
+
+       status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+       if (status) {
+               atomic_dec(&rndis->notify_count);
+               DBG(cdev, "notify/0 --> %d\n", status);
+       }
+}
+
+static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_rndis                  *rndis = req->context;
+       struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
+       int                             status = req->status;
+
+       /* after TX:
+        *  - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
+        *  - RNDIS_RESPONSE_AVAILABLE (status/irq)
+        */
+       switch (status) {
+       case -ECONNRESET:
+       case -ESHUTDOWN:
+               /* connection gone */
+               atomic_set(&rndis->notify_count, 0);
+               break;
+       default:
+               DBG(cdev, "RNDIS %s response error %d, %d/%d\n",
+                       ep->name, status,
+                       req->actual, req->length);
+               /* FALLTHROUGH */
+       case 0:
+               if (ep != rndis->notify)
+                       break;
+
+               /* handle multiple pending RNDIS_RESPONSE_AVAILABLE
+                * notifications by resending until we're done
+                */
+               if (atomic_dec_and_test(&rndis->notify_count))
+                       break;
+               status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+               if (status) {
+                       atomic_dec(&rndis->notify_count);
+                       DBG(cdev, "notify/1 --> %d\n", status);
+               }
+               break;
+       }
+}
+
+static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_rndis                  *rndis = req->context;
+       struct usb_composite_dev        *cdev = rndis->port.func.config->cdev;
+       int                             status;
+
+       /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+//     spin_lock(&dev->lock);
+       status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
+       if (status < 0)
+               ERROR(cdev, "RNDIS command error %d, %d/%d\n",
+                       status, req->actual, req->length);
+//     spin_unlock(&dev->lock);
+}
+
+static int
+rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+       struct f_rndis          *rndis = func_to_rndis(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_request      *req = cdev->req;
+       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);
+
+       /* composite driver infrastructure handles everything except
+        * CDC class messages; interface activation uses set_alt().
+        */
+       switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+       /* RNDIS uses the CDC command encapsulation mechanism to implement
+        * an RPC scheme, with much getting/setting of attributes by OID.
+        */
+       case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+                       | USB_CDC_SEND_ENCAPSULATED_COMMAND:
+               if (w_value || w_index != rndis->ctrl_id)
+                       goto invalid;
+               /* read the request; process it later */
+               value = w_length;
+               req->complete = rndis_command_complete;
+               req->context = rndis;
+               /* later, rndis_response_available() sends a notification */
+               break;
+
+       case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+                       | USB_CDC_GET_ENCAPSULATED_RESPONSE:
+               if (w_value || w_index != rndis->ctrl_id)
+                       goto invalid;
+               else {
+                       u8 *buf;
+                       u32 n;
+
+                       /* return the result */
+                       buf = rndis_get_next_response(rndis->config, &n);
+                       if (buf) {
+                               memcpy(req->buf, buf, n);
+                               req->complete = rndis_response_complete;
+                               req->context = rndis;
+                               rndis_free_response(rndis->config, buf);
+                               value = n;
+                       }
+                       /* else stalls ... spec says to avoid that */
+               }
+               break;
+
+       default:
+invalid:
+               VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+       }
+
+       /* respond with data transfer or status phase? */
+       if (value >= 0) {
+               DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+               req->zero = (value < w_length);
+               req->length = value;
+               value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0)
+                       ERROR(cdev, "rndis response on err %d\n", value);
+       }
+
+       /* device either stalls (value < 0) or reports success */
+       return value;
+}
+
+
+static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct f_rndis          *rndis = func_to_rndis(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+
+       /* we know alt == 0 */
+
+       if (intf == rndis->ctrl_id) {
+               if (rndis->notify->driver_data) {
+                       VDBG(cdev, "reset rndis control %d\n", intf);
+                       usb_ep_disable(rndis->notify);
+               }
+               if (!rndis->notify->desc) {
+                       VDBG(cdev, "init rndis ctrl %d\n", intf);
+                       if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+                               goto fail;
+               }
+               usb_ep_enable(rndis->notify);
+               rndis->notify->driver_data = rndis;
+
+       } else if (intf == rndis->data_id) {
+               struct net_device       *net;
+
+               if (rndis->port.in_ep->driver_data) {
+                       DBG(cdev, "reset rndis\n");
+                       gether_disconnect(&rndis->port);
+               }
+
+               if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
+                       DBG(cdev, "init rndis\n");
+                       if (config_ep_by_speed(cdev->gadget, f,
+                                              rndis->port.in_ep) ||
+                           config_ep_by_speed(cdev->gadget, f,
+                                              rndis->port.out_ep)) {
+                               rndis->port.in_ep->desc = NULL;
+                               rndis->port.out_ep->desc = NULL;
+                               goto fail;
+                       }
+               }
+
+               /* Avoid ZLPs; they can be troublesome. */
+               rndis->port.is_zlp_ok = false;
+
+               /* RNDIS should be in the "RNDIS uninitialized" state,
+                * either never activated or after rndis_uninit().
+                *
+                * We don't want data to flow here until a nonzero packet
+                * filter is set, at which point it enters "RNDIS data
+                * initialized" state ... but we do want the endpoints
+                * to be activated.  It's a strange little state.
+                *
+                * REVISIT the RNDIS gadget code has done this wrong for a
+                * very long time.  We need another call to the link layer
+                * code -- gether_updown(...bool) maybe -- to do it right.
+                */
+               rndis->port.cdc_filter = 0;
+
+               DBG(cdev, "RNDIS RX/TX early activation ... \n");
+               net = gether_connect(&rndis->port);
+               if (IS_ERR(net))
+                       return PTR_ERR(net);
+
+               rndis_set_param_dev(rndis->config, net,
+                               &rndis->port.cdc_filter);
+       } else
+               goto fail;
+
+       return 0;
+fail:
+       return -EINVAL;
+}
+
+static void rndis_disable(struct usb_function *f)
+{
+       struct f_rndis          *rndis = func_to_rndis(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+
+       if (!rndis->notify->driver_data)
+               return;
+
+       DBG(cdev, "rndis deactivated\n");
+
+       rndis_uninit(rndis->config);
+       gether_disconnect(&rndis->port);
+
+       usb_ep_disable(rndis->notify);
+       rndis->notify->driver_data = NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This isn't quite the same mechanism as CDC Ethernet, since the
+ * notification scheme passes less data, but the same set of link
+ * states must be tested.  A key difference is that altsettings are
+ * not used to tell whether the link should send packets or not.
+ */
+
+static void rndis_open(struct gether *geth)
+{
+       struct f_rndis          *rndis = func_to_rndis(&geth->func);
+       struct usb_composite_dev *cdev = geth->func.config->cdev;
+
+       DBG(cdev, "%s\n", __func__);
+
+       rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
+                               bitrate(cdev->gadget) / 100);
+       rndis_signal_connect(rndis->config);
+}
+
+static void rndis_close(struct gether *geth)
+{
+       struct f_rndis          *rndis = func_to_rndis(&geth->func);
+
+       DBG(geth->func.config->cdev, "%s\n", __func__);
+
+       rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
+       rndis_signal_disconnect(rndis->config);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ethernet function driver setup/binding */
+
+static int
+rndis_bind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct usb_composite_dev *cdev = c->cdev;
+       struct f_rndis          *rndis = func_to_rndis(f);
+       int                     status;
+       struct usb_ep           *ep;
+
+       /* allocate instance-specific interface IDs */
+       status = usb_interface_id(c, f);
+       if (status < 0)
+               goto fail;
+       rndis->ctrl_id = status;
+       rndis_iad_descriptor.bFirstInterface = status;
+
+       rndis_control_intf.bInterfaceNumber = status;
+       rndis_union_desc.bMasterInterface0 = status;
+
+       status = usb_interface_id(c, f);
+       if (status < 0)
+               goto fail;
+       rndis->data_id = status;
+
+       rndis_data_intf.bInterfaceNumber = status;
+       rndis_union_desc.bSlaveInterface0 = status;
+
+       status = -ENODEV;
+
+       /* allocate instance-specific endpoints */
+       ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
+       if (!ep)
+               goto fail;
+       rndis->port.in_ep = ep;
+       ep->driver_data = cdev; /* claim */
+
+       ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
+       if (!ep)
+               goto fail;
+       rndis->port.out_ep = ep;
+       ep->driver_data = cdev; /* claim */
+
+       /* NOTE:  a status/notification endpoint is, strictly speaking,
+        * optional.  We don't treat it that way though!  It's simpler,
+        * and some newer profiles don't treat it as optional.
+        */
+       ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
+       if (!ep)
+               goto fail;
+       rndis->notify = ep;
+       ep->driver_data = cdev; /* claim */
+
+       status = -ENOMEM;
+
+       /* allocate notification request and buffer */
+       rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
+       if (!rndis->notify_req)
+               goto fail;
+       rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
+       if (!rndis->notify_req->buf)
+               goto fail;
+       rndis->notify_req->length = STATUS_BYTECOUNT;
+       rndis->notify_req->context = rndis;
+       rndis->notify_req->complete = rndis_response_complete;
+
+       /* copy descriptors, and track endpoint copies */
+       f->descriptors = usb_copy_descriptors(eth_fs_function);
+       if (!f->descriptors)
+               goto fail;
+
+       /* support all relevant hardware speeds... we expect that when
+        * hardware is dual speed, all bulk-capable endpoints work at
+        * both speeds
+        */
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
+               hs_in_desc.bEndpointAddress =
+                               fs_in_desc.bEndpointAddress;
+               hs_out_desc.bEndpointAddress =
+                               fs_out_desc.bEndpointAddress;
+               hs_notify_desc.bEndpointAddress =
+                               fs_notify_desc.bEndpointAddress;
+
+               /* copy descriptors, and track endpoint copies */
+               f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
+               if (!f->hs_descriptors)
+                       goto fail;
+       }
+
+       if (gadget_is_superspeed(c->cdev->gadget)) {
+               ss_in_desc.bEndpointAddress =
+                               fs_in_desc.bEndpointAddress;
+               ss_out_desc.bEndpointAddress =
+                               fs_out_desc.bEndpointAddress;
+               ss_notify_desc.bEndpointAddress =
+                               fs_notify_desc.bEndpointAddress;
+
+               /* copy descriptors, and track endpoint copies */
+               f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
+               if (!f->ss_descriptors)
+                       goto fail;
+       }
+
+       rndis->port.open = rndis_open;
+       rndis->port.close = rndis_close;
+
+       status = rndis_register(rndis_response_available, rndis);
+       if (status < 0)
+               goto fail;
+       rndis->config = status;
+
+       rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
+       rndis_set_host_mac(rndis->config, rndis->ethaddr);
+
+       if (rndis->manufacturer && rndis->vendorID &&
+                       rndis_set_param_vendor(rndis->config, rndis->vendorID,
+                                              rndis->manufacturer))
+               goto fail;
+
+       /* NOTE:  all that is done without knowing or caring about
+        * the network link ... which is unavailable to this code
+        * until we're activated via set_alt().
+        */
+
+       DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
+                       gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+                       rndis->port.in_ep->name, rndis->port.out_ep->name,
+                       rndis->notify->name);
+       return 0;
+
+fail:
+       if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
+               usb_free_descriptors(f->ss_descriptors);
+       if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
+               usb_free_descriptors(f->hs_descriptors);
+       if (f->descriptors)
+               usb_free_descriptors(f->descriptors);
+
+       if (rndis->notify_req) {
+               kfree(rndis->notify_req->buf);
+               usb_ep_free_request(rndis->notify, rndis->notify_req);
+       }
+
+       /* we might as well release our claims on endpoints */
+       if (rndis->notify)
+               rndis->notify->driver_data = NULL;
+       if (rndis->port.out_ep->desc)
+               rndis->port.out_ep->driver_data = NULL;
+       if (rndis->port.in_ep->desc)
+               rndis->port.in_ep->driver_data = NULL;
+
+       ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+
+       return status;
+}
+
+static void
+rndis_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct f_rndis          *rndis = func_to_rndis(f);
+
+       rndis_deregister(rndis->config);
+       rndis_exit();
+       rndis_string_defs[0].id = 0;
+
+       if (gadget_is_superspeed(c->cdev->gadget))
+               usb_free_descriptors(f->ss_descriptors);
+       if (gadget_is_dualspeed(c->cdev->gadget))
+               usb_free_descriptors(f->hs_descriptors);
+       usb_free_descriptors(f->descriptors);
+
+       kfree(rndis->notify_req->buf);
+       usb_ep_free_request(rndis->notify, rndis->notify_req);
+
+       kfree(rndis);
+}
+
+/* Some controllers can't support RNDIS ... */
+static inline bool can_support_rndis(struct usb_configuration *c)
+{
+       /* everything else is *presumably* fine */
+       return true;
+}
+
+int
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+                               u32 vendorID, const char *manufacturer)
+{
+       struct f_rndis  *rndis;
+       int             status;
+
+       if (!can_support_rndis(c) || !ethaddr)
+               return -EINVAL;
+
+       /* maybe allocate device-global string IDs */
+       if (rndis_string_defs[0].id == 0) {
+
+               /* ... and setup RNDIS itself */
+               status = rndis_init();
+               if (status < 0)
+                       return status;
+
+               /* control interface label */
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               rndis_string_defs[0].id = status;
+               rndis_control_intf.iInterface = status;
+
+               /* data interface label */
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               rndis_string_defs[1].id = status;
+               rndis_data_intf.iInterface = status;
+
+               /* IAD iFunction label */
+               status = usb_string_id(c->cdev);
+               if (status < 0)
+                       return status;
+               rndis_string_defs[2].id = status;
+               rndis_iad_descriptor.iFunction = status;
+       }
+
+       /* allocate and initialize one new instance */
+       status = -ENOMEM;
+       rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
+       if (!rndis)
+               goto fail;
+
+       memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
+       rndis->vendorID = vendorID;
+       rndis->manufacturer = manufacturer;
+
+       /* RNDIS activates when the host changes this filter */
+       rndis->port.cdc_filter = 0;
+
+       /* RNDIS has special (and complex) framing */
+       rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
+       rndis->port.wrap = rndis_add_header;
+       rndis->port.unwrap = rndis_rm_hdr;
+
+       rndis->port.func.name = "rndis";
+       rndis->port.func.strings = rndis_strings;
+       /* descriptors are per-instance copies */
+       rndis->port.func.bind = rndis_bind;
+       rndis->port.func.unbind = rndis_unbind;
+       rndis->port.func.set_alt = rndis_set_alt;
+       rndis->port.func.setup = rndis_setup;
+       rndis->port.func.disable = rndis_disable;
+
+       status = usb_add_function(c, &rndis->port.func);
+       if (status) {
+               kfree(rndis);
+fail:
+               rndis_exit();
+       }
+       return status;
+}
diff --git a/drivers/staging/ccg/gadget_chips.h b/drivers/staging/ccg/gadget_chips.h
new file mode 100644 (file)
index 0000000..0ccca58
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * USB device controllers have lots of quirks.  Use these macros in
+ * gadget drivers or other code that needs to deal with them, and which
+ * autoconfigures instead of using early binding to the hardware.
+ *
+ * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
+ * some config file that gets updated as new hardware is supported.
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
+ *
+ * NOTE:  some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
+ */
+
+#ifndef __GADGET_CHIPS_H
+#define __GADGET_CHIPS_H
+
+/*
+ * NOTICE: the entries below are alphabetical and should be kept
+ * that way.
+ *
+ * Always be sure to add new entries to the correct position or
+ * accept the bashing later.
+ *
+ * If you have forgotten the alphabetical order let VIM/EMACS
+ * do that for you.
+ */
+#define gadget_is_amd5536udc(g)                (!strcmp("amd5536udc", (g)->name))
+#define gadget_is_at91(g)              (!strcmp("at91_udc", (g)->name))
+#define gadget_is_atmel_usba(g)                (!strcmp("atmel_usba_udc", (g)->name))
+#define gadget_is_bcm63xx(g)           (!strcmp("bcm63xx_udc", (g)->name))
+#define gadget_is_ci13xxx_msm(g)       (!strcmp("ci13xxx_msm", (g)->name))
+#define gadget_is_ci13xxx_pci(g)       (!strcmp("ci13xxx_pci", (g)->name))
+#define gadget_is_dummy(g)             (!strcmp("dummy_udc", (g)->name))
+#define gadget_is_dwc3(g)              (!strcmp("dwc3-gadget", (g)->name))
+#define gadget_is_fsl_qe(g)            (!strcmp("fsl_qe_udc", (g)->name))
+#define gadget_is_fsl_usb2(g)          (!strcmp("fsl-usb2-udc", (g)->name))
+#define gadget_is_goku(g)              (!strcmp("goku_udc", (g)->name))
+#define gadget_is_imx(g)               (!strcmp("imx_udc", (g)->name))
+#define gadget_is_langwell(g)          (!strcmp("langwell_udc", (g)->name))
+#define gadget_is_lpc32xx(g)           (!strcmp("lpc32xx_udc", (g)->name))
+#define gadget_is_m66592(g)            (!strcmp("m66592_udc", (g)->name))
+#define gadget_is_musbhdrc(g)          (!strcmp("musb-hdrc", (g)->name))
+#define gadget_is_net2272(g)           (!strcmp("net2272", (g)->name))
+#define gadget_is_net2280(g)           (!strcmp("net2280", (g)->name))
+#define gadget_is_omap(g)              (!strcmp("omap_udc", (g)->name))
+#define gadget_is_pch(g)               (!strcmp("pch_udc", (g)->name))
+#define gadget_is_pxa(g)               (!strcmp("pxa25x_udc", (g)->name))
+#define gadget_is_pxa27x(g)            (!strcmp("pxa27x_udc", (g)->name))
+#define gadget_is_r8a66597(g)          (!strcmp("r8a66597_udc", (g)->name))
+#define gadget_is_renesas_usbhs(g)     (!strcmp("renesas_usbhs_udc", (g)->name))
+#define gadget_is_s3c2410(g)           (!strcmp("s3c2410_udc", (g)->name))
+#define gadget_is_s3c_hsotg(g)         (!strcmp("s3c-hsotg", (g)->name))
+#define gadget_is_s3c_hsudc(g)         (!strcmp("s3c-hsudc", (g)->name))
+
+/**
+ * usb_gadget_controller_number - support bcdDevice id convention
+ * @gadget: the controller being driven
+ *
+ * Return a 2-digit BCD value associated with the peripheral controller,
+ * suitable for use as part of a bcdDevice value, or a negative error code.
+ *
+ * NOTE:  this convention is purely optional, and has no meaning in terms of
+ * any USB specification.  If you want to use a different convention in your
+ * gadget driver firmware -- maybe a more formal revision ID -- feel free.
+ *
+ * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
+ * to change their behavior accordingly.  For example it might help avoiding
+ * some chip bug.
+ */
+static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+{
+       if (gadget_is_net2280(gadget))
+               return 0x01;
+       else if (gadget_is_dummy(gadget))
+               return 0x02;
+       else if (gadget_is_pxa(gadget))
+               return 0x03;
+       else if (gadget_is_goku(gadget))
+               return 0x06;
+       else if (gadget_is_omap(gadget))
+               return 0x08;
+       else if (gadget_is_pxa27x(gadget))
+               return 0x11;
+       else if (gadget_is_s3c2410(gadget))
+               return 0x12;
+       else if (gadget_is_at91(gadget))
+               return 0x13;
+       else if (gadget_is_imx(gadget))
+               return 0x14;
+       else if (gadget_is_musbhdrc(gadget))
+               return 0x16;
+       else if (gadget_is_atmel_usba(gadget))
+               return 0x18;
+       else if (gadget_is_fsl_usb2(gadget))
+               return 0x19;
+       else if (gadget_is_amd5536udc(gadget))
+               return 0x20;
+       else if (gadget_is_m66592(gadget))
+               return 0x21;
+       else if (gadget_is_fsl_qe(gadget))
+               return 0x22;
+       else if (gadget_is_ci13xxx_pci(gadget))
+               return 0x23;
+       else if (gadget_is_langwell(gadget))
+               return 0x24;
+       else if (gadget_is_r8a66597(gadget))
+               return 0x25;
+       else if (gadget_is_s3c_hsotg(gadget))
+               return 0x26;
+       else if (gadget_is_pch(gadget))
+               return 0x27;
+       else if (gadget_is_ci13xxx_msm(gadget))
+               return 0x28;
+       else if (gadget_is_renesas_usbhs(gadget))
+               return 0x29;
+       else if (gadget_is_s3c_hsudc(gadget))
+               return 0x30;
+       else if (gadget_is_net2272(gadget))
+               return 0x31;
+       else if (gadget_is_dwc3(gadget))
+               return 0x32;
+       else if (gadget_is_lpc32xx(gadget))
+               return 0x33;
+       else if (gadget_is_bcm63xx(gadget))
+               return 0x34;
+
+       return -ENOENT;
+}
+
+
+/**
+ * gadget_supports_altsettings - return true if altsettings work
+ * @gadget: the gadget in question
+ */
+static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
+{
+       /* PXA 21x/25x/26x has no altsettings at all */
+       if (gadget_is_pxa(gadget))
+               return false;
+
+       /* PXA 27x and 3xx have *broken* altsetting support */
+       if (gadget_is_pxa27x(gadget))
+               return false;
+
+       /* Everything else is *presumably* fine ... */
+       return true;
+}
+
+#endif /* __GADGET_CHIPS_H */
diff --git a/drivers/staging/ccg/ndis.h b/drivers/staging/ccg/ndis.h
new file mode 100644 (file)
index 0000000..a19f72d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * ndis.h
+ *
+ * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
+ *
+ * Thanks to the cygwin development team,
+ * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ */
+
+#ifndef _LINUX_NDIS_H
+#define _LINUX_NDIS_H
+
+enum NDIS_DEVICE_POWER_STATE {
+       NdisDeviceStateUnspecified = 0,
+       NdisDeviceStateD0,
+       NdisDeviceStateD1,
+       NdisDeviceStateD2,
+       NdisDeviceStateD3,
+       NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES {
+       enum NDIS_DEVICE_POWER_STATE  MinMagicPacketWakeUp;
+       enum NDIS_DEVICE_POWER_STATE  MinPatternWakeUp;
+       enum NDIS_DEVICE_POWER_STATE  MinLinkChangeWakeUp;
+};
+
+struct NDIS_PNP_CAPABILITIES {
+       __le32                                  Flags;
+       struct NDIS_PM_WAKE_UP_CAPABILITIES     WakeUpCapabilities;
+};
+
+struct NDIS_PM_PACKET_PATTERN {
+       __le32  Priority;
+       __le32  Reserved;
+       __le32  MaskSize;
+       __le32  PatternOffset;
+       __le32  PatternSize;
+       __le32  PatternFlags;
+};
+
+#endif /* _LINUX_NDIS_H */
diff --git a/drivers/staging/ccg/rndis.c b/drivers/staging/ccg/rndis.c
new file mode 100644 (file)
index 0000000..e4192b8
--- /dev/null
@@ -0,0 +1,1175 @@
+/*
+ * RNDIS MSG parser
+ *
+ * Authors:    Benedikt Spranger, Pengutronix
+ *             Robert Schwebel, Pengutronix
+ *
+ *              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.
+ *
+ *             This software was originally developed in conformance with
+ *             Microsoft's Remote NDIS Specification License Agreement.
+ *
+ * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
+ *             Fixed message length bug in init_response
+ *
+ * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
+ *             Fixed rndis_rm_hdr length bug.
+ *
+ * Copyright (C) 2004 by David Brownell
+ *             updates to merge with Linux 2.6, better match RNDIS spec
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/netdevice.h>
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+
+#undef VERBOSE_DEBUG
+
+#include "rndis.h"
+
+
+/* The driver for your USB chip needs to support ep0 OUT to work with
+ * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
+ *
+ * Windows hosts need an INF file like Documentation/usb/linux.inf
+ * and will be happier if you provide the host_addr module parameter.
+ */
+
+#if 0
+static int rndis_debug = 0;
+module_param (rndis_debug, int, 0);
+MODULE_PARM_DESC (rndis_debug, "enable debugging");
+#else
+#define rndis_debug            0
+#endif
+
+#define RNDIS_MAX_CONFIGS      1
+
+
+static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
+
+/* Driver Version */
+static const __le32 rndis_driver_version = cpu_to_le32(1);
+
+/* Function Prototypes */
+static rndis_resp_t *rndis_add_response(int configNr, u32 length);
+
+
+/* supported OIDs */
+static const u32 oid_supported_list[] =
+{
+       /* the general stuff */
+       RNDIS_OID_GEN_SUPPORTED_LIST,
+       RNDIS_OID_GEN_HARDWARE_STATUS,
+       RNDIS_OID_GEN_MEDIA_SUPPORTED,
+       RNDIS_OID_GEN_MEDIA_IN_USE,
+       RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
+       RNDIS_OID_GEN_LINK_SPEED,
+       RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
+       RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
+       RNDIS_OID_GEN_VENDOR_ID,
+       RNDIS_OID_GEN_VENDOR_DESCRIPTION,
+       RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
+       RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
+       RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
+       RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
+       RNDIS_OID_GEN_PHYSICAL_MEDIUM,
+
+       /* the statistical stuff */
+       RNDIS_OID_GEN_XMIT_OK,
+       RNDIS_OID_GEN_RCV_OK,
+       RNDIS_OID_GEN_XMIT_ERROR,
+       RNDIS_OID_GEN_RCV_ERROR,
+       RNDIS_OID_GEN_RCV_NO_BUFFER,
+#ifdef RNDIS_OPTIONAL_STATS
+       RNDIS_OID_GEN_DIRECTED_BYTES_XMIT,
+       RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT,
+       RNDIS_OID_GEN_MULTICAST_BYTES_XMIT,
+       RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT,
+       RNDIS_OID_GEN_BROADCAST_BYTES_XMIT,
+       RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT,
+       RNDIS_OID_GEN_DIRECTED_BYTES_RCV,
+       RNDIS_OID_GEN_DIRECTED_FRAMES_RCV,
+       RNDIS_OID_GEN_MULTICAST_BYTES_RCV,
+       RNDIS_OID_GEN_MULTICAST_FRAMES_RCV,
+       RNDIS_OID_GEN_BROADCAST_BYTES_RCV,
+       RNDIS_OID_GEN_BROADCAST_FRAMES_RCV,
+       RNDIS_OID_GEN_RCV_CRC_ERROR,
+       RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif /* RNDIS_OPTIONAL_STATS */
+
+       /* mandatory 802.3 */
+       /* the general stuff */
+       RNDIS_OID_802_3_PERMANENT_ADDRESS,
+       RNDIS_OID_802_3_CURRENT_ADDRESS,
+       RNDIS_OID_802_3_MULTICAST_LIST,
+       RNDIS_OID_802_3_MAC_OPTIONS,
+       RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
+
+       /* the statistical stuff */
+       RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
+       RNDIS_OID_802_3_XMIT_ONE_COLLISION,
+       RNDIS_OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef RNDIS_OPTIONAL_STATS
+       RNDIS_OID_802_3_XMIT_DEFERRED,
+       RNDIS_OID_802_3_XMIT_MAX_COLLISIONS,
+       RNDIS_OID_802_3_RCV_OVERRUN,
+       RNDIS_OID_802_3_XMIT_UNDERRUN,
+       RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE,
+       RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST,
+       RNDIS_OID_802_3_XMIT_LATE_COLLISIONS,
+#endif /* RNDIS_OPTIONAL_STATS */
+
+#ifdef RNDIS_PM
+       /* PM and wakeup are "mandatory" for USB, but the RNDIS specs
+        * don't say what they mean ... and the NDIS specs are often
+        * confusing and/or ambiguous in this context.  (That is, more
+        * so than their specs for the other OIDs.)
+        *
+        * FIXME someone who knows what these should do, please
+        * implement them!
+        */
+
+       /* power management */
+       OID_PNP_CAPABILITIES,
+       OID_PNP_QUERY_POWER,
+       OID_PNP_SET_POWER,
+
+#ifdef RNDIS_WAKEUP
+       /* wake up host */
+       OID_PNP_ENABLE_WAKE_UP,
+       OID_PNP_ADD_WAKE_UP_PATTERN,
+       OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif /* RNDIS_WAKEUP */
+#endif /* RNDIS_PM */
+};
+
+
+/* NDIS Functions */
+static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
+                              unsigned buf_len, rndis_resp_t *r)
+{
+       int retval = -ENOTSUPP;
+       u32 length = 4; /* usually */
+       __le32 *outbuf;
+       int i, count;
+       rndis_query_cmplt_type *resp;
+       struct net_device *net;
+       struct rtnl_link_stats64 temp;
+       const struct rtnl_link_stats64 *stats;
+
+       if (!r) return -ENOMEM;
+       resp = (rndis_query_cmplt_type *)r->buf;
+
+       if (!resp) return -ENOMEM;
+
+       if (buf_len && rndis_debug > 1) {
+               pr_debug("query OID %08x value, len %d:\n", OID, buf_len);
+               for (i = 0; i < buf_len; i += 16) {
+                       pr_debug("%03d: %08x %08x %08x %08x\n", i,
+                               get_unaligned_le32(&buf[i]),
+                               get_unaligned_le32(&buf[i + 4]),
+                               get_unaligned_le32(&buf[i + 8]),
+                               get_unaligned_le32(&buf[i + 12]));
+               }
+       }
+
+       /* response goes here, right after the header */
+       outbuf = (__le32 *)&resp[1];
+       resp->InformationBufferOffset = cpu_to_le32(16);
+
+       net = rndis_per_dev_params[configNr].dev;
+       stats = dev_get_stats(net, &temp);
+
+       switch (OID) {
+
+       /* general oids (table 4-1) */
+
+       /* mandatory */
+       case RNDIS_OID_GEN_SUPPORTED_LIST:
+               pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__);
+               length = sizeof(oid_supported_list);
+               count  = length / sizeof(u32);
+               for (i = 0; i < count; i++)
+                       outbuf[i] = cpu_to_le32(oid_supported_list[i]);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_HARDWARE_STATUS:
+               pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__);
+               /* Bogus question!
+                * Hardware must be ready to receive high level protocols.
+                * BTW:
+                * reddite ergo quae sunt Caesaris Caesari
+                * et quae sunt Dei Deo!
+                */
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_MEDIA_SUPPORTED:
+               pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__);
+               *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_MEDIA_IN_USE:
+               pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__);
+               /* one medium, one transport... (maybe you do it better) */
+               *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
+               pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
+               if (rndis_per_dev_params[configNr].dev) {
+                       *outbuf = cpu_to_le32(
+                               rndis_per_dev_params[configNr].dev->mtu);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_LINK_SPEED:
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__);
+               if (rndis_per_dev_params[configNr].media_state
+                               == RNDIS_MEDIA_STATE_DISCONNECTED)
+                       *outbuf = cpu_to_le32(0);
+               else
+                       *outbuf = cpu_to_le32(
+                               rndis_per_dev_params[configNr].speed);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
+               pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
+               if (rndis_per_dev_params[configNr].dev) {
+                       *outbuf = cpu_to_le32(
+                               rndis_per_dev_params[configNr].dev->mtu);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
+               pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
+               if (rndis_per_dev_params[configNr].dev) {
+                       *outbuf = cpu_to_le32(
+                               rndis_per_dev_params[configNr].dev->mtu);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_VENDOR_ID:
+               pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__);
+               *outbuf = cpu_to_le32(
+                       rndis_per_dev_params[configNr].vendorID);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_VENDOR_DESCRIPTION:
+               pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__);
+               if (rndis_per_dev_params[configNr].vendorDescr) {
+                       length = strlen(rndis_per_dev_params[configNr].
+                                       vendorDescr);
+                       memcpy(outbuf,
+                               rndis_per_dev_params[configNr].vendorDescr,
+                               length);
+               } else {
+                       outbuf[0] = 0;
+               }
+               retval = 0;
+               break;
+
+       case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION:
+               pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
+               /* Created as LE */
+               *outbuf = rndis_driver_version;
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
+               pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
+               *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE:
+               pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
+               *outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
+               *outbuf = cpu_to_le32(rndis_per_dev_params[configNr]
+                                               .media_state);
+               retval = 0;
+               break;
+
+       case RNDIS_OID_GEN_PHYSICAL_MEDIUM:
+               pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__);
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
+               break;
+
+       /* The RNDIS specification is incomplete/wrong.   Some versions
+        * of MS-Windows expect OIDs that aren't specified there.  Other
+        * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
+        */
+       case RNDIS_OID_GEN_MAC_OPTIONS:         /* from WinME */
+               pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__);
+               *outbuf = cpu_to_le32(
+                         RNDIS_MAC_OPTION_RECEIVE_SERIALIZED
+                       | RNDIS_MAC_OPTION_FULL_DUPLEX);
+               retval = 0;
+               break;
+
+       /* statistics OIDs (table 4-2) */
+
+       /* mandatory */
+       case RNDIS_OID_GEN_XMIT_OK:
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__);
+               if (stats) {
+                       *outbuf = cpu_to_le32(stats->tx_packets
+                               - stats->tx_errors - stats->tx_dropped);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_RCV_OK:
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__);
+               if (stats) {
+                       *outbuf = cpu_to_le32(stats->rx_packets
+                               - stats->rx_errors - stats->rx_dropped);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_XMIT_ERROR:
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__);
+               if (stats) {
+                       *outbuf = cpu_to_le32(stats->tx_errors);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_RCV_ERROR:
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__);
+               if (stats) {
+                       *outbuf = cpu_to_le32(stats->rx_errors);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_GEN_RCV_NO_BUFFER:
+               pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__);
+               if (stats) {
+                       *outbuf = cpu_to_le32(stats->rx_dropped);
+                       retval = 0;
+               }
+               break;
+
+       /* ieee802.3 OIDs (table 4-3) */
+
+       /* mandatory */
+       case RNDIS_OID_802_3_PERMANENT_ADDRESS:
+               pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__);
+               if (rndis_per_dev_params[configNr].dev) {
+                       length = ETH_ALEN;
+                       memcpy(outbuf,
+                               rndis_per_dev_params[configNr].host_mac,
+                               length);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_802_3_CURRENT_ADDRESS:
+               pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__);
+               if (rndis_per_dev_params[configNr].dev) {
+                       length = ETH_ALEN;
+                       memcpy(outbuf,
+                               rndis_per_dev_params [configNr].host_mac,
+                               length);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_802_3_MULTICAST_LIST:
+               pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
+               /* Multicast base address only */
+               *outbuf = cpu_to_le32(0xE0000000);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE:
+               pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
+               /* Multicast base address only */
+               *outbuf = cpu_to_le32(1);
+               retval = 0;
+               break;
+
+       case RNDIS_OID_802_3_MAC_OPTIONS:
+               pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__);
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
+               break;
+
+       /* ieee802.3 statistics OIDs (table 4-4) */
+
+       /* mandatory */
+       case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT:
+               pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
+               if (stats) {
+                       *outbuf = cpu_to_le32(stats->rx_frame_errors);
+                       retval = 0;
+               }
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_802_3_XMIT_ONE_COLLISION:
+               pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__);
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
+               break;
+
+       /* mandatory */
+       case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS:
+               pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
+               *outbuf = cpu_to_le32(0);
+               retval = 0;
+               break;
+
+       default:
+               pr_warning("%s: query unknown OID 0x%08X\n",
+                        __func__, OID);
+       }
+       if (retval < 0)
+               length = 0;
+
+       resp->InformationBufferLength = cpu_to_le32(length);
+       r->length = length + sizeof(*resp);
+       resp->MessageLength = cpu_to_le32(r->length);
+       return retval;
+}
+
+static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
+                            rndis_resp_t *r)
+{
+       rndis_set_cmplt_type *resp;
+       int i, retval = -ENOTSUPP;
+       struct rndis_params *params;
+
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_set_cmplt_type *)r->buf;
+       if (!resp)
+               return -ENOMEM;
+
+       if (buf_len && rndis_debug > 1) {
+               pr_debug("set OID %08x value, len %d:\n", OID, buf_len);
+               for (i = 0; i < buf_len; i += 16) {
+                       pr_debug("%03d: %08x %08x %08x %08x\n", i,
+                               get_unaligned_le32(&buf[i]),
+                               get_unaligned_le32(&buf[i + 4]),
+                               get_unaligned_le32(&buf[i + 8]),
+                               get_unaligned_le32(&buf[i + 12]));
+               }
+       }
+
+       params = &rndis_per_dev_params[configNr];
+       switch (OID) {
+       case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
+
+               /* these NDIS_PACKET_TYPE_* bitflags are shared with
+                * cdc_filter; it's not RNDIS-specific
+                * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
+                *      PROMISCUOUS, DIRECTED,
+                *      MULTICAST, ALL_MULTICAST, BROADCAST
+                */
+               *params->filter = (u16)get_unaligned_le32(buf);
+               pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
+                       __func__, *params->filter);
+
+               /* this call has a significant side effect:  it's
+                * what makes the packet flow start and stop, like
+                * activating the CDC Ethernet altsetting.
+                */
+               retval = 0;
+               if (*params->filter) {
+                       params->state = RNDIS_DATA_INITIALIZED;
+                       netif_carrier_on(params->dev);
+                       if (netif_running(params->dev))
+                               netif_wake_queue(params->dev);
+               } else {
+                       params->state = RNDIS_INITIALIZED;
+                       netif_carrier_off(params->dev);
+                       netif_stop_queue(params->dev);
+               }
+               break;
+
+       case RNDIS_OID_802_3_MULTICAST_LIST:
+               /* I think we can ignore this */
+               pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
+               retval = 0;
+               break;
+
+       default:
+               pr_warning("%s: set unknown OID 0x%08X, size %d\n",
+                        __func__, OID, buf_len);
+       }
+
+       return retval;
+}
+
+/*
+ * Response Functions
+ */
+
+static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
+{
+       rndis_init_cmplt_type *resp;
+       rndis_resp_t *r;
+       struct rndis_params *params = rndis_per_dev_params + configNr;
+
+       if (!params->dev)
+               return -ENOTSUPP;
+
+       r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_init_cmplt_type *)r->buf;
+
+       resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C);
+       resp->MessageLength = cpu_to_le32(52);
+       resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+       resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+       resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
+       resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
+       resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
+       resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
+       resp->MaxPacketsPerTransfer = cpu_to_le32(1);
+       resp->MaxTransferSize = cpu_to_le32(
+                 params->dev->mtu
+               + sizeof(struct ethhdr)
+               + sizeof(struct rndis_packet_msg_type)
+               + 22);
+       resp->PacketAlignmentFactor = cpu_to_le32(0);
+       resp->AFListOffset = cpu_to_le32(0);
+       resp->AFListSize = cpu_to_le32(0);
+
+       params->resp_avail(params->v);
+       return 0;
+}
+
+static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
+{
+       rndis_query_cmplt_type *resp;
+       rndis_resp_t *r;
+       struct rndis_params *params = rndis_per_dev_params + configNr;
+
+       /* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
+       if (!params->dev)
+               return -ENOTSUPP;
+
+       /*
+        * we need more memory:
+        * gen_ndis_query_resp expects enough space for
+        * rndis_query_cmplt_type followed by data.
+        * oid_supported_list is the largest data reply
+        */
+       r = rndis_add_response(configNr,
+               sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_query_cmplt_type *)r->buf;
+
+       resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
+       resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+
+       if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID),
+                       le32_to_cpu(buf->InformationBufferOffset)
+                                       + 8 + (u8 *)buf,
+                       le32_to_cpu(buf->InformationBufferLength),
+                       r)) {
+               /* OID not supported */
+               resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
+               resp->MessageLength = cpu_to_le32(sizeof *resp);
+               resp->InformationBufferLength = cpu_to_le32(0);
+               resp->InformationBufferOffset = cpu_to_le32(0);
+       } else
+               resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+       params->resp_avail(params->v);
+       return 0;
+}
+
+static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
+{
+       u32 BufLength, BufOffset;
+       rndis_set_cmplt_type *resp;
+       rndis_resp_t *r;
+       struct rndis_params *params = rndis_per_dev_params + configNr;
+
+       r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_set_cmplt_type *)r->buf;
+
+       BufLength = le32_to_cpu(buf->InformationBufferLength);
+       BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+
+#ifdef VERBOSE_DEBUG
+       pr_debug("%s: Length: %d\n", __func__, BufLength);
+       pr_debug("%s: Offset: %d\n", __func__, BufOffset);
+       pr_debug("%s: InfoBuffer: ", __func__);
+
+       for (i = 0; i < BufLength; i++) {
+               pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
+       }
+
+       pr_debug("\n");
+#endif
+
+       resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
+       resp->MessageLength = cpu_to_le32(16);
+       resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+       if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID),
+                       ((u8 *)buf) + 8 + BufOffset, BufLength, r))
+               resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
+       else
+               resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+       params->resp_avail(params->v);
+       return 0;
+}
+
+static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
+{
+       rndis_reset_cmplt_type *resp;
+       rndis_resp_t *r;
+       struct rndis_params *params = rndis_per_dev_params + configNr;
+
+       r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_reset_cmplt_type *)r->buf;
+
+       resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C);
+       resp->MessageLength = cpu_to_le32(16);
+       resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+       /* resent information */
+       resp->AddressingReset = cpu_to_le32(1);
+
+       params->resp_avail(params->v);
+       return 0;
+}
+
+static int rndis_keepalive_response(int configNr,
+                                   rndis_keepalive_msg_type *buf)
+{
+       rndis_keepalive_cmplt_type *resp;
+       rndis_resp_t *r;
+       struct rndis_params *params = rndis_per_dev_params + configNr;
+
+       /* host "should" check only in RNDIS_DATA_INITIALIZED state */
+
+       r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_keepalive_cmplt_type *)r->buf;
+
+       resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C);
+       resp->MessageLength = cpu_to_le32(16);
+       resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+       resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
+
+       params->resp_avail(params->v);
+       return 0;
+}
+
+
+/*
+ * Device to Host Comunication
+ */
+static int rndis_indicate_status_msg(int configNr, u32 status)
+{
+       rndis_indicate_status_msg_type *resp;
+       rndis_resp_t *r;
+       struct rndis_params *params = rndis_per_dev_params + configNr;
+
+       if (params->state == RNDIS_UNINITIALIZED)
+               return -ENOTSUPP;
+
+       r = rndis_add_response(configNr,
+                               sizeof(rndis_indicate_status_msg_type));
+       if (!r)
+               return -ENOMEM;
+       resp = (rndis_indicate_status_msg_type *)r->buf;
+
+       resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE);
+       resp->MessageLength = cpu_to_le32(20);
+       resp->Status = cpu_to_le32(status);
+       resp->StatusBufferLength = cpu_to_le32(0);
+       resp->StatusBufferOffset = cpu_to_le32(0);
+
+       params->resp_avail(params->v);
+       return 0;
+}
+
+int rndis_signal_connect(int configNr)
+{
+       rndis_per_dev_params[configNr].media_state
+                       = RNDIS_MEDIA_STATE_CONNECTED;
+       return rndis_indicate_status_msg(configNr,
+                                         RNDIS_STATUS_MEDIA_CONNECT);
+}
+
+int rndis_signal_disconnect(int configNr)
+{
+       rndis_per_dev_params[configNr].media_state
+                       = RNDIS_MEDIA_STATE_DISCONNECTED;
+       return rndis_indicate_status_msg(configNr,
+                                         RNDIS_STATUS_MEDIA_DISCONNECT);
+}
+
+void rndis_uninit(int configNr)
+{
+       u8 *buf;
+       u32 length;
+
+       if (configNr >= RNDIS_MAX_CONFIGS)
+               return;
+       rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
+
+       /* drain the response queue */
+       while ((buf = rndis_get_next_response(configNr, &length)))
+               rndis_free_response(configNr, buf);
+}
+
+void rndis_set_host_mac(int configNr, const u8 *addr)
+{
+       rndis_per_dev_params[configNr].host_mac = addr;
+}
+
+/*
+ * Message Parser
+ */
+int rndis_msg_parser(u8 configNr, u8 *buf)
+{
+       u32 MsgType, MsgLength;
+       __le32 *tmp;
+       struct rndis_params *params;
+
+       if (!buf)
+               return -ENOMEM;
+
+       tmp = (__le32 *)buf;
+       MsgType   = get_unaligned_le32(tmp++);
+       MsgLength = get_unaligned_le32(tmp++);
+
+       if (configNr >= RNDIS_MAX_CONFIGS)
+               return -ENOTSUPP;
+       params = &rndis_per_dev_params[configNr];
+
+       /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+        * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+        * and normal HC level polling to see if there's any IN traffic.
+        */
+
+       /* For USB: responses may take up to 10 seconds */
+       switch (MsgType) {
+       case RNDIS_MSG_INIT:
+               pr_debug("%s: RNDIS_MSG_INIT\n",
+                       __func__);
+               params->state = RNDIS_INITIALIZED;
+               return rndis_init_response(configNr,
+                                       (rndis_init_msg_type *)buf);
+
+       case RNDIS_MSG_HALT:
+               pr_debug("%s: RNDIS_MSG_HALT\n",
+                       __func__);
+               params->state = RNDIS_UNINITIALIZED;
+               if (params->dev) {
+                       netif_carrier_off(params->dev);
+                       netif_stop_queue(params->dev);
+               }
+               return 0;
+
+       case RNDIS_MSG_QUERY:
+               return rndis_query_response(configNr,
+                                       (rndis_query_msg_type *)buf);
+
+       case RNDIS_MSG_SET:
+               return rndis_set_response(configNr,
+                                       (rndis_set_msg_type *)buf);
+
+       case RNDIS_MSG_RESET:
+               pr_debug("%s: RNDIS_MSG_RESET\n",
+                       __func__);
+               return rndis_reset_response(configNr,
+                                       (rndis_reset_msg_type *)buf);
+
+       case RNDIS_MSG_KEEPALIVE:
+               /* For USB: host does this every 5 seconds */
+               if (rndis_debug > 1)
+                       pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
+                               __func__);
+               return rndis_keepalive_response(configNr,
+                                                (rndis_keepalive_msg_type *)
+                                                buf);
+
+       default:
+               /* At least Windows XP emits some undefined RNDIS messages.
+                * In one case those messages seemed to relate to the host
+                * suspending itself.
+                */
+               pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
+                       __func__, MsgType, MsgLength);
+               print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
+                                    buf, MsgLength);
+               break;
+       }
+
+       return -ENOTSUPP;
+}
+
+int rndis_register(void (*resp_avail)(void *v), void *v)
+{
+       u8 i;
+
+       if (!resp_avail)
+               return -EINVAL;
+
+       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+               if (!rndis_per_dev_params[i].used) {
+                       rndis_per_dev_params[i].used = 1;
+                       rndis_per_dev_params[i].resp_avail = resp_avail;
+                       rndis_per_dev_params[i].v = v;
+                       pr_debug("%s: configNr = %d\n", __func__, i);
+                       return i;
+               }
+       }
+       pr_debug("failed\n");
+
+       return -ENODEV;
+}
+
+void rndis_deregister(int configNr)
+{
+       pr_debug("%s:\n", __func__);
+
+       if (configNr >= RNDIS_MAX_CONFIGS) return;
+       rndis_per_dev_params[configNr].used = 0;
+}
+
+int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
+{
+       pr_debug("%s:\n", __func__);
+       if (!dev)
+               return -EINVAL;
+       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+
+       rndis_per_dev_params[configNr].dev = dev;
+       rndis_per_dev_params[configNr].filter = cdc_filter;
+
+       return 0;
+}
+
+int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
+{
+       pr_debug("%s:\n", __func__);
+       if (!vendorDescr) return -1;
+       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+
+       rndis_per_dev_params[configNr].vendorID = vendorID;
+       rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
+
+       return 0;
+}
+
+int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
+{
+       pr_debug("%s: %u %u\n", __func__, medium, speed);
+       if (configNr >= RNDIS_MAX_CONFIGS) return -1;
+
+       rndis_per_dev_params[configNr].medium = medium;
+       rndis_per_dev_params[configNr].speed = speed;
+
+       return 0;
+}
+
+void rndis_add_hdr(struct sk_buff *skb)
+{
+       struct rndis_packet_msg_type *header;
+
+       if (!skb)
+               return;
+       header = (void *)skb_push(skb, sizeof(*header));
+       memset(header, 0, sizeof *header);
+       header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
+       header->MessageLength = cpu_to_le32(skb->len);
+       header->DataOffset = cpu_to_le32(36);
+       header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
+}
+
+void rndis_free_response(int configNr, u8 *buf)
+{
+       rndis_resp_t *r;
+       struct list_head *act, *tmp;
+
+       list_for_each_safe(act, tmp,
+                       &(rndis_per_dev_params[configNr].resp_queue))
+       {
+               r = list_entry(act, rndis_resp_t, list);
+               if (r && r->buf == buf) {
+                       list_del(&r->list);
+                       kfree(r);
+               }
+       }
+}
+
+u8 *rndis_get_next_response(int configNr, u32 *length)
+{
+       rndis_resp_t *r;
+       struct list_head *act, *tmp;
+
+       if (!length) return NULL;
+
+       list_for_each_safe(act, tmp,
+                       &(rndis_per_dev_params[configNr].resp_queue))
+       {
+               r = list_entry(act, rndis_resp_t, list);
+               if (!r->send) {
+                       r->send = 1;
+                       *length = r->length;
+                       return r->buf;
+               }
+       }
+
+       return NULL;
+}
+
+static rndis_resp_t *rndis_add_response(int configNr, u32 length)
+{
+       rndis_resp_t *r;
+
+       /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
+       r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
+       if (!r) return NULL;
+
+       r->buf = (u8 *)(r + 1);
+       r->length = length;
+       r->send = 0;
+
+       list_add_tail(&r->list,
+               &(rndis_per_dev_params[configNr].resp_queue));
+       return r;
+}
+
+int rndis_rm_hdr(struct gether *port,
+                       struct sk_buff *skb,
+                       struct sk_buff_head *list)
+{
+       /* tmp points to a struct rndis_packet_msg_type */
+       __le32 *tmp = (void *)skb->data;
+
+       /* MessageType, MessageLength */
+       if (cpu_to_le32(RNDIS_MSG_PACKET)
+                       != get_unaligned(tmp++)) {
+               dev_kfree_skb_any(skb);
+               return -EINVAL;
+       }
+       tmp++;
+
+       /* DataOffset, DataLength */
+       if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
+               dev_kfree_skb_any(skb);
+               return -EOVERFLOW;
+       }
+       skb_trim(skb, get_unaligned_le32(tmp++));
+
+       skb_queue_tail(list, skb);
+       return 0;
+}
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static int rndis_proc_show(struct seq_file *m, void *v)
+{
+       rndis_params *param = m->private;
+
+       seq_printf(m,
+                        "Config Nr. %d\n"
+                        "used      : %s\n"
+                        "state     : %s\n"
+                        "medium    : 0x%08X\n"
+                        "speed     : %d\n"
+                        "cable     : %s\n"
+                        "vendor ID : 0x%08X\n"
+                        "vendor    : %s\n",
+                        param->confignr, (param->used) ? "y" : "n",
+                        ({ char *s = "?";
+                        switch (param->state) {
+                        case RNDIS_UNINITIALIZED:
+                               s = "RNDIS_UNINITIALIZED"; break;
+                        case RNDIS_INITIALIZED:
+                               s = "RNDIS_INITIALIZED"; break;
+                        case RNDIS_DATA_INITIALIZED:
+                               s = "RNDIS_DATA_INITIALIZED"; break;
+                       }; s; }),
+                        param->medium,
+                        (param->media_state) ? 0 : param->speed*100,
+                        (param->media_state) ? "disconnected" : "connected",
+                        param->vendorID, param->vendorDescr);
+       return 0;
+}
+
+static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
+                               size_t count, loff_t *ppos)
+{
+       rndis_params *p = PDE(file->f_path.dentry->d_inode)->data;
+       u32 speed = 0;
+       int i, fl_speed = 0;
+
+       for (i = 0; i < count; i++) {
+               char c;
+               if (get_user(c, buffer))
+                       return -EFAULT;
+               switch (c) {
+               case '0':
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       fl_speed = 1;
+                       speed = speed * 10 + c - '0';
+                       break;
+               case 'C':
+               case 'c':
+                       rndis_signal_connect(p->confignr);
+                       break;
+               case 'D':
+               case 'd':
+                       rndis_signal_disconnect(p->confignr);
+                       break;
+               default:
+                       if (fl_speed) p->speed = speed;
+                       else pr_debug("%c is not valid\n", c);
+                       break;
+               }
+
+               buffer++;
+       }
+
+       return count;
+}
+
+static int rndis_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rndis_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations rndis_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rndis_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = rndis_proc_write,
+};
+
+#define        NAME_TEMPLATE "driver/rndis-%03d"
+
+static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+
+int rndis_init(void)
+{
+       u8 i;
+
+       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+               char name [20];
+
+               sprintf(name, NAME_TEMPLATE, i);
+               rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
+                                       &rndis_proc_fops,
+                                       (void *)(rndis_per_dev_params + i));
+               if (!rndis_connect_state[i]) {
+                       pr_debug("%s: remove entries", __func__);
+                       while (i) {
+                               sprintf(name, NAME_TEMPLATE, --i);
+                               remove_proc_entry(name, NULL);
+                       }
+                       pr_debug("\n");
+                       return -EIO;
+               }
+#endif
+               rndis_per_dev_params[i].confignr = i;
+               rndis_per_dev_params[i].used = 0;
+               rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
+               rndis_per_dev_params[i].media_state
+                               = RNDIS_MEDIA_STATE_DISCONNECTED;
+               INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
+       }
+
+       return 0;
+}
+
+void rndis_exit(void)
+{
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+       u8 i;
+       char name[20];
+
+       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+               sprintf(name, NAME_TEMPLATE, i);
+               remove_proc_entry(name, NULL);
+       }
+#endif
+}
diff --git a/drivers/staging/ccg/rndis.h b/drivers/staging/ccg/rndis.h
new file mode 100644 (file)
index 0000000..0647f2f
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * RNDIS       Definitions for Remote NDIS
+ *
+ * Authors:    Benedikt Spranger, Pengutronix
+ *             Robert Schwebel, Pengutronix
+ *
+ *             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.
+ *
+ *             This software was originally developed in conformance with
+ *             Microsoft's Remote NDIS Specification License Agreement.
+ */
+
+#ifndef _LINUX_RNDIS_H
+#define _LINUX_RNDIS_H
+
+#include <linux/rndis.h>
+#include "ndis.h"
+
+#define RNDIS_MAXIMUM_FRAME_SIZE       1518
+#define RNDIS_MAX_TOTAL_SIZE           1558
+
+typedef struct rndis_init_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  MajorVersion;
+       __le32  MinorVersion;
+       __le32  MaxTransferSize;
+} rndis_init_msg_type;
+
+typedef struct rndis_init_cmplt_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  Status;
+       __le32  MajorVersion;
+       __le32  MinorVersion;
+       __le32  DeviceFlags;
+       __le32  Medium;
+       __le32  MaxPacketsPerTransfer;
+       __le32  MaxTransferSize;
+       __le32  PacketAlignmentFactor;
+       __le32  AFListOffset;
+       __le32  AFListSize;
+} rndis_init_cmplt_type;
+
+typedef struct rndis_halt_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+} rndis_halt_msg_type;
+
+typedef struct rndis_query_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  OID;
+       __le32  InformationBufferLength;
+       __le32  InformationBufferOffset;
+       __le32  DeviceVcHandle;
+} rndis_query_msg_type;
+
+typedef struct rndis_query_cmplt_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  Status;
+       __le32  InformationBufferLength;
+       __le32  InformationBufferOffset;
+} rndis_query_cmplt_type;
+
+typedef struct rndis_set_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  OID;
+       __le32  InformationBufferLength;
+       __le32  InformationBufferOffset;
+       __le32  DeviceVcHandle;
+} rndis_set_msg_type;
+
+typedef struct rndis_set_cmplt_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  Status;
+} rndis_set_cmplt_type;
+
+typedef struct rndis_reset_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  Reserved;
+} rndis_reset_msg_type;
+
+typedef struct rndis_reset_cmplt_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  Status;
+       __le32  AddressingReset;
+} rndis_reset_cmplt_type;
+
+typedef struct rndis_indicate_status_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  Status;
+       __le32  StatusBufferLength;
+       __le32  StatusBufferOffset;
+} rndis_indicate_status_msg_type;
+
+typedef struct rndis_keepalive_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+} rndis_keepalive_msg_type;
+
+typedef struct rndis_keepalive_cmplt_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  RequestID;
+       __le32  Status;
+} rndis_keepalive_cmplt_type;
+
+struct rndis_packet_msg_type
+{
+       __le32  MessageType;
+       __le32  MessageLength;
+       __le32  DataOffset;
+       __le32  DataLength;
+       __le32  OOBDataOffset;
+       __le32  OOBDataLength;
+       __le32  NumOOBDataElements;
+       __le32  PerPacketInfoOffset;
+       __le32  PerPacketInfoLength;
+       __le32  VcHandle;
+       __le32  Reserved;
+} __attribute__ ((packed));
+
+struct rndis_config_parameter
+{
+       __le32  ParameterNameOffset;
+       __le32  ParameterNameLength;
+       __le32  ParameterType;
+       __le32  ParameterValueOffset;
+       __le32  ParameterValueLength;
+};
+
+/* implementation specific */
+enum rndis_state
+{
+       RNDIS_UNINITIALIZED,
+       RNDIS_INITIALIZED,
+       RNDIS_DATA_INITIALIZED,
+};
+
+typedef struct rndis_resp_t
+{
+       struct list_head        list;
+       u8                      *buf;
+       u32                     length;
+       int                     send;
+} rndis_resp_t;
+
+typedef struct rndis_params
+{
+       u8                      confignr;
+       u8                      used;
+       u16                     saved_filter;
+       enum rndis_state        state;
+       u32                     medium;
+       u32                     speed;
+       u32                     media_state;
+
+       const u8                *host_mac;
+       u16                     *filter;
+       struct net_device       *dev;
+
+       u32                     vendorID;
+       const char              *vendorDescr;
+       void                    (*resp_avail)(void *v);
+       void                    *v;
+       struct list_head        resp_queue;
+} rndis_params;
+
+/* RNDIS Message parser and other useless functions */
+int  rndis_msg_parser (u8 configNr, u8 *buf);
+int  rndis_register(void (*resp_avail)(void *v), void *v);
+void rndis_deregister (int configNr);
+int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
+                        u16 *cdc_filter);
+int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
+                           const char *vendorDescr);
+int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
+void rndis_add_hdr (struct sk_buff *skb);
+int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
+                       struct sk_buff_head *list);
+u8   *rndis_get_next_response (int configNr, u32 *length);
+void rndis_free_response (int configNr, u8 *buf);
+
+void rndis_uninit (int configNr);
+int  rndis_signal_connect (int configNr);
+int  rndis_signal_disconnect (int configNr);
+int  rndis_state (int configNr);
+extern void rndis_set_host_mac (int configNr, const u8 *addr);
+
+int rndis_init(void);
+void rndis_exit (void);
+
+#endif  /* _LINUX_RNDIS_H */
diff --git a/drivers/staging/ccg/storage_common.c b/drivers/staging/ccg/storage_common.c
new file mode 100644 (file)
index 0000000..8d9bcd8
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * storage_common.c -- Common definitions for mass storage functionality
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyeight (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz (mina86@mina86.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+/*
+ * This file requires the following identifiers used in USB strings to
+ * be defined (each of type pointer to char):
+ *  - fsg_string_manufacturer -- name of the manufacturer
+ *  - fsg_string_product      -- name of the product
+ *  - fsg_string_config       -- name of the configuration
+ *  - fsg_string_interface    -- name of the interface
+ * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
+ * macro is defined prior to including this file.
+ */
+
+/*
+ * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
+ * fsg_hs_intr_in_desc objects as well as
+ * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
+ * macros are not defined.
+ *
+ * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
+ * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
+ * defined (as well as corresponding entries in string tables are
+ * missing) and FSG_STRING_INTERFACE has value of zero.
+ *
+ * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
+ */
+
+/*
+ * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
+ * sets the number of pipeline buffers (length of the fsg_buffhd array).
+ * The valid range of num_buffers is: num >= 2 && num <= 4.
+ */
+
+
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <asm/unaligned.h>
+
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define FSG_VENDOR_ID  0x0525  /* NetChip */
+#define FSG_PRODUCT_ID 0xa4a5  /* Linux-USB File-backed Storage Gadget */
+
+
+/*-------------------------------------------------------------------------*/
+
+
+#ifndef DEBUG
+#undef VERBOSE_DEBUG
+#undef DUMP_MSGS
+#endif /* !DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#define VLDBG  LDBG
+#else
+#define VLDBG(lun, fmt, args...) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args)
+#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
+#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args)
+#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)
+
+/*
+ * Keep those macros in sync with those in
+ * include/linux/usb/composite.h or else GCC will complain.  If they
+ * are identical (the same names of arguments, white spaces in the
+ * same places) GCC will allow redefinition otherwise (even if some
+ * white space is removed or added) warning will be issued.
+ *
+ * Those macros are needed here because File Storage Gadget does not
+ * include the composite.h header.  For composite gadgets those macros
+ * are redundant since composite.h is included any way.
+ *
+ * One could check whether those macros are already defined (which
+ * would indicate composite.h had been included) or not (which would
+ * indicate we were in FSG) but this is not done because a warning is
+ * desired if definitions here differ from the ones in composite.h.
+ *
+ * We want the definitions to match and be the same in File Storage
+ * Gadget as well as Mass Storage Function (and so composite gadgets
+ * using MSF).  If someone changes them in composite.h it will produce
+ * a warning in this file when building MSF.
+ */
+#define DBG(d, fmt, args...)     dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...)    dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...)   dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...)    dev_info(&(d)->gadget->dev , fmt , ## args)
+
+
+
+#ifdef DUMP_MSGS
+
+#  define dump_msg(fsg, /* const char * */ label,                      \
+                  /* const u8 * */ buf, /* unsigned */ length) do {    \
+       if (length < 512) {                                             \
+               DBG(fsg, "%s, length %u:\n", label, length);            \
+               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,      \
+                              16, 1, buf, length, 0);                  \
+       }                                                               \
+} while (0)
+
+#  define dump_cdb(fsg) do { } while (0)
+
+#else
+
+#  define dump_msg(fsg, /* const char * */ label, \
+                  /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
+
+#  ifdef VERBOSE_DEBUG
+
+#    define dump_cdb(fsg)                                              \
+       print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,      \
+                      16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)         \
+
+#  else
+
+#    define dump_cdb(fsg) do { } while (0)
+
+#  endif /* VERBOSE_DEBUG */
+
+#endif /* DUMP_MSGS */
+
+/*-------------------------------------------------------------------------*/
+
+/* CBI Interrupt data structure */
+struct interrupt_data {
+       u8      bType;
+       u8      bValue;
+};
+
+#define CBI_INTERRUPT_DATA_LEN         2
+
+/* CBI Accept Device-Specific Command request */
+#define USB_CBI_ADSC_REQUEST           0x00
+
+
+/* Length of a SCSI Command Data Block */
+#define MAX_COMMAND_SIZE       16
+
+/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
+#define SS_NO_SENSE                            0
+#define SS_COMMUNICATION_FAILURE               0x040800
+#define SS_INVALID_COMMAND                     0x052000
+#define SS_INVALID_FIELD_IN_CDB                        0x052400
+#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE  0x052100
+#define SS_LOGICAL_UNIT_NOT_SUPPORTED          0x052500
+#define SS_MEDIUM_NOT_PRESENT                  0x023a00
+#define SS_MEDIUM_REMOVAL_PREVENTED            0x055302
+#define SS_NOT_READY_TO_READY_TRANSITION       0x062800
+#define SS_RESET_OCCURRED                      0x062900
+#define SS_SAVING_PARAMETERS_NOT_SUPPORTED     0x053900
+#define SS_UNRECOVERED_READ_ERROR              0x031100
+#define SS_WRITE_ERROR                         0x030c02
+#define SS_WRITE_PROTECTED                     0x072700
+
+#define SK(x)          ((u8) ((x) >> 16))      /* Sense Key byte, etc. */
+#define ASC(x)         ((u8) ((x) >> 8))
+#define ASCQ(x)                ((u8) (x))
+
+
+/*-------------------------------------------------------------------------*/
+
+
+struct fsg_lun {
+       struct file     *filp;
+       loff_t          file_length;
+       loff_t          num_sectors;
+
+       unsigned int    initially_ro:1;
+       unsigned int    ro:1;
+       unsigned int    removable:1;
+       unsigned int    cdrom:1;
+       unsigned int    prevent_medium_removal:1;
+       unsigned int    registered:1;
+       unsigned int    info_valid:1;
+       unsigned int    nofua:1;
+
+       u32             sense_data;
+       u32             sense_data_info;
+       u32             unit_attention_data;
+
+       unsigned int    blkbits;        /* Bits of logical block size of bound block device */
+       unsigned int    blksize;        /* logical block size of bound block device */
+       struct device   dev;
+};
+
+#define fsg_lun_is_open(curlun)        ((curlun)->filp != NULL)
+
+static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
+{
+       return container_of(dev, struct fsg_lun, dev);
+}
+
+
+/* Big enough to hold our biggest descriptor */
+#define EP0_BUFSIZE    256
+#define DELAYED_STATUS (EP0_BUFSIZE + 999)     /* An impossibly large value */
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);
+MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_DEBUG */
+
+/* check if fsg_num_buffers is within a valid range */
+static inline int fsg_num_buffers_validate(void)
+{
+       if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
+               return 0;
+       pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
+              fsg_num_buffers, 2 ,4);
+       return -EINVAL;
+}
+
+/* Default size of buffer length. */
+#define FSG_BUFLEN     ((u32)16384)
+
+/* Maximal number of LUNs supported in mass storage function */
+#define FSG_MAX_LUNS   8
+
+enum fsg_buffer_state {
+       BUF_STATE_EMPTY = 0,
+       BUF_STATE_FULL,
+       BUF_STATE_BUSY
+};
+
+struct fsg_buffhd {
+       void                            *buf;
+       enum fsg_buffer_state           state;
+       struct fsg_buffhd               *next;
+
+       /*
+        * The NetChip 2280 is faster, and handles some protocol faults
+        * better, if we don't submit any short bulk-out read requests.
+        * So we will record the intended request length here.
+        */
+       unsigned int                    bulk_out_intended_length;
+
+       struct usb_request              *inreq;
+       int                             inreq_busy;
+       struct usb_request              *outreq;
+       int                             outreq_busy;
+};
+
+enum fsg_state {
+       /* This one isn't used anywhere */
+       FSG_STATE_COMMAND_PHASE = -10,
+       FSG_STATE_DATA_PHASE,
+       FSG_STATE_STATUS_PHASE,
+
+       FSG_STATE_IDLE = 0,
+       FSG_STATE_ABORT_BULK_OUT,
+       FSG_STATE_RESET,
+       FSG_STATE_INTERFACE_CHANGE,
+       FSG_STATE_CONFIG_CHANGE,
+       FSG_STATE_DISCONNECT,
+       FSG_STATE_EXIT,
+       FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+       DATA_DIR_UNKNOWN = 0,
+       DATA_DIR_FROM_HOST,
+       DATA_DIR_TO_HOST,
+       DATA_DIR_NONE
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+
+static inline u32 get_unaligned_be24(u8 *buf)
+{
+       return 0xffffff & (u32) get_unaligned_be32(buf - 1);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+enum {
+#ifndef FSG_NO_DEVICE_STRINGS
+       FSG_STRING_MANUFACTURER = 1,
+       FSG_STRING_PRODUCT,
+       FSG_STRING_SERIAL,
+       FSG_STRING_CONFIG,
+#endif
+       FSG_STRING_INTERFACE
+};
+
+
+#ifndef FSG_NO_OTG
+static struct usb_otg_descriptor
+fsg_otg_desc = {
+       .bLength =              sizeof fsg_otg_desc,
+       .bDescriptorType =      USB_DT_OTG,
+
+       .bmAttributes =         USB_OTG_SRP,
+};
+#endif
+
+/* There is only one interface. */
+
+static struct usb_interface_descriptor
+fsg_intf_desc = {
+       .bLength =              sizeof fsg_intf_desc,
+       .bDescriptorType =      USB_DT_INTERFACE,
+
+       .bNumEndpoints =        2,              /* Adjusted during fsg_bind() */
+       .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
+       .bInterfaceSubClass =   USB_SC_SCSI,    /* Adjusted during fsg_bind() */
+       .bInterfaceProtocol =   USB_PR_BULK,    /* Adjusted during fsg_bind() */
+       .iInterface =           FSG_STRING_INTERFACE,
+};
+
+/*
+ * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
+ * interrupt-in.
+ */
+
+static struct usb_endpoint_descriptor
+fsg_fs_bulk_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       /* wMaxPacketSize set by autoconfiguration */
+};
+
+static struct usb_endpoint_descriptor
+fsg_fs_bulk_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       /* wMaxPacketSize set by autoconfiguration */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_fs_intr_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(2),
+       .bInterval =            32,     /* frames -> 32 ms */
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES       2
+#else
+#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES       1
+#endif
+
+#endif
+
+static struct usb_descriptor_header *fsg_fs_function[] = {
+#ifndef FSG_NO_OTG
+       (struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+       (struct usb_descriptor_header *) &fsg_intf_desc,
+       (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
+       (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
+#ifndef FSG_NO_INTR_EP
+       (struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
+#endif
+       NULL,
+};
+
+
+/*
+ * 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 configuration descriptor.
+ */
+static struct usb_endpoint_descriptor
+fsg_hs_bulk_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor
+fsg_hs_bulk_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+       .bInterval =            1,      /* NAK every 1 uframe */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_hs_intr_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(2),
+       .bInterval =            9,      /* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES       2
+#else
+#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES       1
+#endif
+
+#endif
+
+static struct usb_descriptor_header *fsg_hs_function[] = {
+#ifndef FSG_NO_OTG
+       (struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+       (struct usb_descriptor_header *) &fsg_intf_desc,
+       (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
+       (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
+#ifndef FSG_NO_INTR_EP
+       (struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
+#endif
+       NULL,
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
+       .bLength =              sizeof(fsg_ss_bulk_in_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /*.bMaxBurst =          DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
+       .bLength =              sizeof(fsg_ss_bulk_in_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /*.bMaxBurst =          DYNAMIC, */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_ss_intr_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(2),
+       .bInterval =            9,      /* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
+       .bLength =              sizeof(fsg_ss_bulk_in_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       .wBytesPerInterval =    cpu_to_le16(2),
+};
+
+#ifndef FSG_NO_OTG
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES       2
+#else
+#  define FSG_SS_FUNCTION_PRE_EP_ENTRIES       1
+#endif
+
+#endif
+
+static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
+       .bLength =              USB_DT_USB_EXT_CAP_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE_CAPABILITY,
+       .bDevCapabilityType =   USB_CAP_TYPE_EXT,
+
+       .bmAttributes =         cpu_to_le32(USB_LPM_SUPPORT),
+};
+
+static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
+       .bLength =              USB_DT_USB_SS_CAP_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE_CAPABILITY,
+       .bDevCapabilityType =   USB_SS_CAP_TYPE,
+
+       /* .bmAttributes = LTM is not supported yet */
+
+       .wSpeedSupported =      cpu_to_le16(USB_LOW_SPEED_OPERATION
+               | USB_FULL_SPEED_OPERATION
+               | USB_HIGH_SPEED_OPERATION
+               | USB_5GBPS_OPERATION),
+       .bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
+       .bU1devExitLat =        USB_DEFAULT_U1_DEV_EXIT_LAT,
+       .bU2DevExitLat =        cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT),
+};
+
+static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
+       .bLength =              USB_DT_BOS_SIZE,
+       .bDescriptorType =      USB_DT_BOS,
+
+       .wTotalLength =         cpu_to_le16(USB_DT_BOS_SIZE
+                               + USB_DT_USB_EXT_CAP_SIZE
+                               + USB_DT_USB_SS_CAP_SIZE),
+
+       .bNumDeviceCaps =       2,
+};
+
+static struct usb_descriptor_header *fsg_ss_function[] = {
+#ifndef FSG_NO_OTG
+       (struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+       (struct usb_descriptor_header *) &fsg_intf_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
+       (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
+#ifndef FSG_NO_INTR_EP
+       (struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
+       (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
+#endif
+       NULL,
+};
+
+/* Maxpacket and other transfer characteristics vary by speed. */
+static __maybe_unused struct usb_endpoint_descriptor *
+fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+               struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *ss)
+{
+       if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+               return ss;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
+
+
+/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
+static struct usb_string               fsg_strings[] = {
+#ifndef FSG_NO_DEVICE_STRINGS
+       {FSG_STRING_MANUFACTURER,       fsg_string_manufacturer},
+       {FSG_STRING_PRODUCT,            fsg_string_product},
+       {FSG_STRING_SERIAL,             ""},
+       {FSG_STRING_CONFIG,             fsg_string_config},
+#endif
+       {FSG_STRING_INTERFACE,          fsg_string_interface},
+       {}
+};
+
+static struct usb_gadget_strings       fsg_stringtab = {
+       .language       = 0x0409,               /* en-us */
+       .strings        = fsg_strings,
+};
+
+
+ /*-------------------------------------------------------------------------*/
+
+/*
+ * If the next two routines are called while the gadget is registered,
+ * the caller must own fsg->filesem for writing.
+ */
+
+static void fsg_lun_close(struct fsg_lun *curlun)
+{
+       if (curlun->filp) {
+               LDBG(curlun, "close backing file\n");
+               fput(curlun->filp);
+               curlun->filp = NULL;
+       }
+}
+
+
+static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
+{
+       int                             ro;
+       struct file                     *filp = NULL;
+       int                             rc = -EINVAL;
+       struct inode                    *inode = NULL;
+       loff_t                          size;
+       loff_t                          num_sectors;
+       loff_t                          min_sectors;
+       unsigned int                    blkbits;
+       unsigned int                    blksize;
+
+       /* R/W if we can, R/O if we must */
+       ro = curlun->initially_ro;
+       if (!ro) {
+               filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
+               if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
+                       ro = 1;
+       }
+       if (ro)
+               filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
+       if (IS_ERR(filp)) {
+               LINFO(curlun, "unable to open backing file: %s\n", filename);
+               return PTR_ERR(filp);
+       }
+
+       if (!(filp->f_mode & FMODE_WRITE))
+               ro = 1;
+
+       inode = filp->f_path.dentry->d_inode;
+       if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
+               LINFO(curlun, "invalid file type: %s\n", filename);
+               goto out;
+       }
+
+       /*
+        * If we can't read the file, it's no good.
+        * If we can't write the file, use it read-only.
+        */
+       if (!(filp->f_op->read || filp->f_op->aio_read)) {
+               LINFO(curlun, "file not readable: %s\n", filename);
+               goto out;
+       }
+       if (!(filp->f_op->write || filp->f_op->aio_write))
+               ro = 1;
+
+       size = i_size_read(inode->i_mapping->host);
+       if (size < 0) {
+               LINFO(curlun, "unable to find file size: %s\n", filename);
+               rc = (int) size;
+               goto out;
+       }
+
+       if (curlun->cdrom) {
+               blksize = 2048;
+               blkbits = 11;
+       } else if (inode->i_bdev) {
+               blksize = bdev_logical_block_size(inode->i_bdev);
+               blkbits = blksize_bits(blksize);
+       } else {
+               blksize = 512;
+               blkbits = 9;
+       }
+
+       num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
+       min_sectors = 1;
+       if (curlun->cdrom) {
+               min_sectors = 300;      /* Smallest track is 300 frames */
+               if (num_sectors >= 256*60*75) {
+                       num_sectors = 256*60*75 - 1;
+                       LINFO(curlun, "file too big: %s\n", filename);
+                       LINFO(curlun, "using only first %d blocks\n",
+                                       (int) num_sectors);
+               }
+       }
+       if (num_sectors < min_sectors) {
+               LINFO(curlun, "file too small: %s\n", filename);
+               rc = -ETOOSMALL;
+               goto out;
+       }
+
+       if (fsg_lun_is_open(curlun))
+               fsg_lun_close(curlun);
+
+       curlun->blksize = blksize;
+       curlun->blkbits = blkbits;
+       curlun->ro = ro;
+       curlun->filp = filp;
+       curlun->file_length = size;
+       curlun->num_sectors = num_sectors;
+       LDBG(curlun, "open backing file: %s\n", filename);
+       return 0;
+
+out:
+       fput(filp);
+       return rc;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sync the file data, don't bother with the metadata.
+ * This code was copied from fs/buffer.c:sys_fdatasync().
+ */
+static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
+{
+       struct file     *filp = curlun->filp;
+
+       if (curlun->ro || !filp)
+               return 0;
+       return vfs_fsync(filp, 1);
+}
+
+static void store_cdrom_address(u8 *dest, int msf, u32 addr)
+{
+       if (msf) {
+               /* Convert to Minutes-Seconds-Frames */
+               addr >>= 2;             /* Convert to 2048-byte frames */
+               addr += 2*75;           /* Lead-in occupies 2 seconds */
+               dest[3] = addr % 75;    /* Frames */
+               addr /= 75;
+               dest[2] = addr % 60;    /* Seconds */
+               addr /= 60;
+               dest[1] = addr;         /* Minutes */
+               dest[0] = 0;            /* Reserved */
+       } else {
+               /* Absolute sector */
+               put_unaligned_be32(addr, dest);
+       }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct fsg_lun  *curlun = fsg_lun_from_dev(dev);
+
+       return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
+                                 ? curlun->ro
+                                 : curlun->initially_ro);
+}
+
+static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
+                             char *buf)
+{
+       struct fsg_lun  *curlun = fsg_lun_from_dev(dev);
+
+       return sprintf(buf, "%u\n", curlun->nofua);
+}
+
+static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct fsg_lun  *curlun = fsg_lun_from_dev(dev);
+       struct rw_semaphore     *filesem = dev_get_drvdata(dev);
+       char            *p;
+       ssize_t         rc;
+
+       down_read(filesem);
+       if (fsg_lun_is_open(curlun)) {  /* Get the complete pathname */
+               p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
+               if (IS_ERR(p))
+                       rc = PTR_ERR(p);
+               else {
+                       rc = strlen(p);
+                       memmove(buf, p, rc);
+                       buf[rc] = '\n';         /* Add a newline */
+                       buf[++rc] = 0;
+               }
+       } else {                                /* No file, return 0 bytes */
+               *buf = 0;
+               rc = 0;
+       }
+       up_read(filesem);
+       return rc;
+}
+
+
+static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       ssize_t         rc;
+       struct fsg_lun  *curlun = fsg_lun_from_dev(dev);
+       struct rw_semaphore     *filesem = dev_get_drvdata(dev);
+       unsigned        ro;
+
+       rc = kstrtouint(buf, 2, &ro);
+       if (rc)
+               return rc;
+
+       /*
+        * Allow the write-enable status to change only while the
+        * backing file is closed.
+        */
+       down_read(filesem);
+       if (fsg_lun_is_open(curlun)) {
+               LDBG(curlun, "read-only status change prevented\n");
+               rc = -EBUSY;
+       } else {
+               curlun->ro = ro;
+               curlun->initially_ro = ro;
+               LDBG(curlun, "read-only status set to %d\n", curlun->ro);
+               rc = count;
+       }
+       up_read(filesem);
+       return rc;
+}
+
+static ssize_t fsg_store_nofua(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct fsg_lun  *curlun = fsg_lun_from_dev(dev);
+       unsigned        nofua;
+       int             ret;
+
+       ret = kstrtouint(buf, 2, &nofua);
+       if (ret)
+               return ret;
+
+       /* Sync data when switching from async mode to sync */
+       if (!nofua && curlun->nofua)
+               fsg_lun_fsync_sub(curlun);
+
+       curlun->nofua = nofua;
+
+       return count;
+}
+
+static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct fsg_lun  *curlun = fsg_lun_from_dev(dev);
+       struct rw_semaphore     *filesem = dev_get_drvdata(dev);
+       int             rc = 0;
+
+       if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
+               LDBG(curlun, "eject attempt prevented\n");
+               return -EBUSY;                          /* "Door is locked" */
+       }
+
+       /* Remove a trailing newline */
+       if (count > 0 && buf[count-1] == '\n')
+               ((char *) buf)[count-1] = 0;            /* Ugh! */
+
+       /* Load new medium */
+       down_write(filesem);
+       if (count > 0 && buf[0]) {
+               /* fsg_lun_open() will close existing file if any. */
+               rc = fsg_lun_open(curlun, buf);
+               if (rc == 0)
+                       curlun->unit_attention_data =
+                                       SS_NOT_READY_TO_READY_TRANSITION;
+       } else if (fsg_lun_is_open(curlun)) {
+               fsg_lun_close(curlun);
+               curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+       }
+       up_write(filesem);
+       return (rc < 0 ? rc : count);
+}
diff --git a/drivers/staging/ccg/u_ether.c b/drivers/staging/ccg/u_ether.c
new file mode 100644 (file)
index 0000000..1154a99
--- /dev/null
@@ -0,0 +1,986 @@
+/*
+ * u_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+
+#include "u_ether.h"
+
+
+/*
+ * This component encapsulates the Ethernet link glue needed to provide
+ * one (!) network link through the USB gadget stack, normally "usb0".
+ *
+ * The control and data models are handled by the function driver which
+ * connects to this code; such as CDC Ethernet (ECM or EEM),
+ * "CDC Subset", or RNDIS.  That includes all descriptor and endpoint
+ * management.
+ *
+ * Link level addressing is handled by this component using module
+ * parameters; if no such parameters are provided, random link level
+ * addresses are used.  Each end of the link uses one address.  The
+ * host end address is exported in various ways, and is often recorded
+ * in configuration databases.
+ *
+ * The driver which assembles each configuration using such a link is
+ * responsible for ensuring that each configuration includes at most one
+ * instance of is network link.  (The network layer provides ways for
+ * this single "physical" link to be used by multiple virtual links.)
+ */
+
+#define UETH__VERSION  "29-May-2008"
+
+struct eth_dev {
+       /* lock is held while accessing port_usb
+        * or updating its backlink port_usb->ioport
+        */
+       spinlock_t              lock;
+       struct gether           *port_usb;
+
+       struct net_device       *net;
+       struct usb_gadget       *gadget;
+
+       spinlock_t              req_lock;       /* guard {rx,tx}_reqs */
+       struct list_head        tx_reqs, rx_reqs;
+       atomic_t                tx_qlen;
+
+       struct sk_buff_head     rx_frames;
+
+       unsigned                header_len;
+       struct sk_buff          *(*wrap)(struct gether *, struct sk_buff *skb);
+       int                     (*unwrap)(struct gether *,
+                                               struct sk_buff *skb,
+                                               struct sk_buff_head *list);
+
+       struct work_struct      work;
+
+       unsigned long           todo;
+#define        WORK_RX_MEMORY          0
+
+       bool                    zlp;
+       u8                      host_mac[ETH_ALEN];
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define RX_EXTRA       20      /* bytes guarding against rx overflows */
+
+#define DEFAULT_QLEN   2       /* double buffering by default */
+
+static unsigned qmult = 5;
+module_param(qmult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
+
+/* for dual-speed hardware, use deeper queues at high/super speed */
+static inline int qlen(struct usb_gadget *gadget)
+{
+       if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
+                                           gadget->speed == USB_SPEED_SUPER))
+               return qmult * DEFAULT_QLEN;
+       else
+               return DEFAULT_QLEN;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* REVISIT there must be a better way than having two sets
+ * of debug calls ...
+ */
+
+#undef DBG
+#undef VDBG
+#undef ERROR
+#undef INFO
+
+#define xprintk(d, level, fmt, args...) \
+       printk(level "%s: " fmt , (d)->net->name , ## args)
+
+#ifdef DEBUG
+#undef 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_DEBUG
+#define VDBG   DBG
+#else
+#define VDBG(dev, fmt, args...) \
+       do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev, fmt, args...) \
+       xprintk(dev , KERN_ERR , fmt , ## args)
+#define INFO(dev, fmt, args...) \
+       xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
+
+static int ueth_change_mtu(struct net_device *net, int new_mtu)
+{
+       struct eth_dev  *dev = netdev_priv(net);
+       unsigned long   flags;
+       int             status = 0;
+
+       /* don't change MTU on "live" link (peer won't know) */
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->port_usb)
+               status = -EBUSY;
+       else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
+               status = -ERANGE;
+       else
+               net->mtu = new_mtu;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return status;
+}
+
+static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+{
+       struct eth_dev  *dev = netdev_priv(net);
+
+       strlcpy(p->driver, "g_ether", sizeof p->driver);
+       strlcpy(p->version, UETH__VERSION, sizeof p->version);
+       strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
+       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+}
+
+/* REVISIT can also support:
+ *   - WOL (by tracking suspends and issuing remote wakeup)
+ *   - msglevel (implies updated messaging)
+ *   - ... probably more ethtool ops
+ */
+
+static const struct ethtool_ops ops = {
+       .get_drvinfo = eth_get_drvinfo,
+       .get_link = ethtool_op_get_link,
+};
+
+static void defer_kevent(struct eth_dev *dev, int flag)
+{
+       if (test_and_set_bit(flag, &dev->todo))
+               return;
+       if (!schedule_work(&dev->work))
+               ERROR(dev, "kevent %d may have been dropped\n", flag);
+       else
+               DBG(dev, "kevent %d scheduled\n", flag);
+}
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+
+static int
+rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
+{
+       struct sk_buff  *skb;
+       int             retval = -ENOMEM;
+       size_t          size = 0;
+       struct usb_ep   *out;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->port_usb)
+               out = dev->port_usb->out_ep;
+       else
+               out = NULL;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (!out)
+               return -ENOTCONN;
+
+
+       /* Padding up to RX_EXTRA handles minor disagreements with host.
+        * Normally we use the USB "terminate on short read" convention;
+        * so allow up to (N*maxpacket), since that memory is normally
+        * already allocated.  Some hardware doesn't deal well with short
+        * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
+        * byte off the end (to force hardware errors on overflow).
+        *
+        * RNDIS uses internal framing, and explicitly allows senders to
+        * pad to end-of-packet.  That's potentially nice for speed, but
+        * means receivers can't recover lost synch on their own (because
+        * new packets don't only start after a short RX).
+        */
+       size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
+       size += dev->port_usb->header_len;
+       size += out->maxpacket - 1;
+       size -= size % out->maxpacket;
+
+       if (dev->port_usb->is_fixed)
+               size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+
+       skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+       if (skb == NULL) {
+               DBG(dev, "no rx skb\n");
+               goto enomem;
+       }
+
+       /* Some platforms perform better when IP packets are aligned,
+        * but on at least one, checksumming fails otherwise.  Note:
+        * RNDIS headers involve variable numbers of LE32 values.
+        */
+       skb_reserve(skb, NET_IP_ALIGN);
+
+       req->buf = skb->data;
+       req->length = size;
+       req->complete = rx_complete;
+       req->context = skb;
+
+       retval = usb_ep_queue(out, req, gfp_flags);
+       if (retval == -ENOMEM)
+enomem:
+               defer_kevent(dev, WORK_RX_MEMORY);
+       if (retval) {
+               DBG(dev, "rx submit --> %d\n", retval);
+               if (skb)
+                       dev_kfree_skb_any(skb);
+               spin_lock_irqsave(&dev->req_lock, flags);
+               list_add(&req->list, &dev->rx_reqs);
+               spin_unlock_irqrestore(&dev->req_lock, flags);
+       }
+       return retval;
+}
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct sk_buff  *skb = req->context, *skb2;
+       struct eth_dev  *dev = ep->driver_data;
+       int             status = req->status;
+
+       switch (status) {
+
+       /* normal completion */
+       case 0:
+               skb_put(skb, req->actual);
+
+               if (dev->unwrap) {
+                       unsigned long   flags;
+
+                       spin_lock_irqsave(&dev->lock, flags);
+                       if (dev->port_usb) {
+                               status = dev->unwrap(dev->port_usb,
+                                                       skb,
+                                                       &dev->rx_frames);
+                       } else {
+                               dev_kfree_skb_any(skb);
+                               status = -ENOTCONN;
+                       }
+                       spin_unlock_irqrestore(&dev->lock, flags);
+               } else {
+                       skb_queue_tail(&dev->rx_frames, skb);
+               }
+               skb = NULL;
+
+               skb2 = skb_dequeue(&dev->rx_frames);
+               while (skb2) {
+                       if (status < 0
+                                       || ETH_HLEN > skb2->len
+                                       || skb2->len > ETH_FRAME_LEN) {
+                               dev->net->stats.rx_errors++;
+                               dev->net->stats.rx_length_errors++;
+                               DBG(dev, "rx length %d\n", skb2->len);
+                               dev_kfree_skb_any(skb2);
+                               goto next_frame;
+                       }
+                       skb2->protocol = eth_type_trans(skb2, dev->net);
+                       dev->net->stats.rx_packets++;
+                       dev->net->stats.rx_bytes += skb2->len;
+
+                       /* no buffer copies needed, unless hardware can't
+                        * use skb buffers.
+                        */
+                       status = netif_rx(skb2);
+next_frame:
+                       skb2 = skb_dequeue(&dev->rx_frames);
+               }
+               break;
+
+       /* software-driven interface shutdown */
+       case -ECONNRESET:               /* unlink */
+       case -ESHUTDOWN:                /* disconnect etc */
+               VDBG(dev, "rx shutdown, code %d\n", status);
+               goto quiesce;
+
+       /* for hardware automagic (such as pxa) */
+       case -ECONNABORTED:             /* endpoint reset */
+               DBG(dev, "rx %s reset\n", ep->name);
+               defer_kevent(dev, WORK_RX_MEMORY);
+quiesce:
+               dev_kfree_skb_any(skb);
+               goto clean;
+
+       /* data overrun */
+       case -EOVERFLOW:
+               dev->net->stats.rx_over_errors++;
+               /* FALLTHROUGH */
+
+       default:
+               dev->net->stats.rx_errors++;
+               DBG(dev, "rx status %d\n", status);
+               break;
+       }
+
+       if (skb)
+               dev_kfree_skb_any(skb);
+       if (!netif_running(dev->net)) {
+clean:
+               spin_lock(&dev->req_lock);
+               list_add(&req->list, &dev->rx_reqs);
+               spin_unlock(&dev->req_lock);
+               req = NULL;
+       }
+       if (req)
+               rx_submit(dev, req, GFP_ATOMIC);
+}
+
+static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
+{
+       unsigned                i;
+       struct usb_request      *req;
+
+       if (!n)
+               return -ENOMEM;
+
+       /* queue/recycle up to N requests */
+       i = n;
+       list_for_each_entry(req, list, list) {
+               if (i-- == 0)
+                       goto extra;
+       }
+       while (i--) {
+               req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+               if (!req)
+                       return list_empty(list) ? -ENOMEM : 0;
+               list_add(&req->list, list);
+       }
+       return 0;
+
+extra:
+       /* free extras */
+       for (;;) {
+               struct list_head        *next;
+
+               next = req->list.next;
+               list_del(&req->list);
+               usb_ep_free_request(ep, req);
+
+               if (next == list)
+                       break;
+
+               req = container_of(next, struct usb_request, list);
+       }
+       return 0;
+}
+
+static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
+{
+       int     status;
+
+       spin_lock(&dev->req_lock);
+       status = prealloc(&dev->tx_reqs, link->in_ep, n);
+       if (status < 0)
+               goto fail;
+       status = prealloc(&dev->rx_reqs, link->out_ep, n);
+       if (status < 0)
+               goto fail;
+       goto done;
+fail:
+       DBG(dev, "can't alloc requests\n");
+done:
+       spin_unlock(&dev->req_lock);
+       return status;
+}
+
+static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
+{
+       struct usb_request      *req;
+       unsigned long           flags;
+
+       /* fill unused rxq slots with some skb */
+       spin_lock_irqsave(&dev->req_lock, flags);
+       while (!list_empty(&dev->rx_reqs)) {
+               req = container_of(dev->rx_reqs.next,
+                               struct usb_request, list);
+               list_del_init(&req->list);
+               spin_unlock_irqrestore(&dev->req_lock, flags);
+
+               if (rx_submit(dev, req, gfp_flags) < 0) {
+                       defer_kevent(dev, WORK_RX_MEMORY);
+                       return;
+               }
+
+               spin_lock_irqsave(&dev->req_lock, flags);
+       }
+       spin_unlock_irqrestore(&dev->req_lock, flags);
+}
+
+static void eth_work(struct work_struct *work)
+{
+       struct eth_dev  *dev = container_of(work, struct eth_dev, work);
+
+       if (test_and_clear_bit(WORK_RX_MEMORY, &dev->todo)) {
+               if (netif_running(dev->net))
+                       rx_fill(dev, GFP_KERNEL);
+       }
+
+       if (dev->todo)
+               DBG(dev, "work done, flags = 0x%lx\n", dev->todo);
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct sk_buff  *skb = req->context;
+       struct eth_dev  *dev = ep->driver_data;
+
+       switch (req->status) {
+       default:
+               dev->net->stats.tx_errors++;
+               VDBG(dev, "tx err %d\n", req->status);
+               /* FALLTHROUGH */
+       case -ECONNRESET:               /* unlink */
+       case -ESHUTDOWN:                /* disconnect etc */
+               break;
+       case 0:
+               dev->net->stats.tx_bytes += skb->len;
+       }
+       dev->net->stats.tx_packets++;
+
+       spin_lock(&dev->req_lock);
+       list_add(&req->list, &dev->tx_reqs);
+       spin_unlock(&dev->req_lock);
+       dev_kfree_skb_any(skb);
+
+       atomic_dec(&dev->tx_qlen);
+       if (netif_carrier_ok(dev->net))
+               netif_wake_queue(dev->net);
+}
+
+static inline int is_promisc(u16 cdc_filter)
+{
+       return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
+}
+
+static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
+                                       struct net_device *net)
+{
+       struct eth_dev          *dev = netdev_priv(net);
+       int                     length = skb->len;
+       int                     retval;
+       struct usb_request      *req = NULL;
+       unsigned long           flags;
+       struct usb_ep           *in;
+       u16                     cdc_filter;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->port_usb) {
+               in = dev->port_usb->in_ep;
+               cdc_filter = dev->port_usb->cdc_filter;
+       } else {
+               in = NULL;
+               cdc_filter = 0;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (!in) {
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       /* apply outgoing CDC or RNDIS filters */
+       if (!is_promisc(cdc_filter)) {
+               u8              *dest = skb->data;
+
+               if (is_multicast_ether_addr(dest)) {
+                       u16     type;
+
+                       /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
+                        * SET_ETHERNET_MULTICAST_FILTERS requests
+                        */
+                       if (is_broadcast_ether_addr(dest))
+                               type = USB_CDC_PACKET_TYPE_BROADCAST;
+                       else
+                               type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+                       if (!(cdc_filter & type)) {
+                               dev_kfree_skb_any(skb);
+                               return NETDEV_TX_OK;
+                       }
+               }
+               /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
+       }
+
+       spin_lock_irqsave(&dev->req_lock, flags);
+       /*
+        * this freelist can be empty if an interrupt triggered disconnect()
+        * and reconfigured the gadget (shutting down this queue) after the
+        * network stack decided to xmit but before we got the spinlock.
+        */
+       if (list_empty(&dev->tx_reqs)) {
+               spin_unlock_irqrestore(&dev->req_lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+
+       req = container_of(dev->tx_reqs.next, struct usb_request, list);
+       list_del(&req->list);
+
+       /* temporarily stop TX queue when the freelist empties */
+       if (list_empty(&dev->tx_reqs))
+               netif_stop_queue(net);
+       spin_unlock_irqrestore(&dev->req_lock, flags);
+
+       /* no buffer copies needed, unless the network stack did it
+        * or the hardware can't use skb buffers.
+        * or there's not enough space for extra headers we need
+        */
+       if (dev->wrap) {
+               unsigned long   flags;
+
+               spin_lock_irqsave(&dev->lock, flags);
+               if (dev->port_usb)
+                       skb = dev->wrap(dev->port_usb, skb);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               if (!skb)
+                       goto drop;
+
+               length = skb->len;
+       }
+       req->buf = skb->data;
+       req->context = skb;
+       req->complete = tx_complete;
+
+       /* NCM requires no zlp if transfer is dwNtbInMaxSize */
+       if (dev->port_usb->is_fixed &&
+           length == dev->port_usb->fixed_in_len &&
+           (length % in->maxpacket) == 0)
+               req->zero = 0;
+       else
+               req->zero = 1;
+
+       /* use zlp framing on tx for strict CDC-Ether conformance,
+        * though any robust network rx path ignores extra padding.
+        * and some hardware doesn't like to write zlps.
+        */
+       if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
+               length++;
+
+       req->length = length;
+
+       /* throttle high/super speed IRQ rate back slightly */
+       if (gadget_is_dualspeed(dev->gadget))
+               req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
+                                    dev->gadget->speed == USB_SPEED_SUPER)
+                       ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+                       : 0;
+
+       retval = usb_ep_queue(in, req, GFP_ATOMIC);
+       switch (retval) {
+       default:
+               DBG(dev, "tx queue err %d\n", retval);
+               break;
+       case 0:
+               net->trans_start = jiffies;
+               atomic_inc(&dev->tx_qlen);
+       }
+
+       if (retval) {
+               dev_kfree_skb_any(skb);
+drop:
+               dev->net->stats.tx_dropped++;
+               spin_lock_irqsave(&dev->req_lock, flags);
+               if (list_empty(&dev->tx_reqs))
+                       netif_start_queue(net);
+               list_add(&req->list, &dev->tx_reqs);
+               spin_unlock_irqrestore(&dev->req_lock, flags);
+       }
+       return NETDEV_TX_OK;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
+{
+       DBG(dev, "%s\n", __func__);
+
+       /* fill the rx queue */
+       rx_fill(dev, gfp_flags);
+
+       /* and open the tx floodgates */
+       atomic_set(&dev->tx_qlen, 0);
+       netif_wake_queue(dev->net);
+}
+
+static int eth_open(struct net_device *net)
+{
+       struct eth_dev  *dev = netdev_priv(net);
+       struct gether   *link;
+
+       DBG(dev, "%s\n", __func__);
+       if (netif_carrier_ok(dev->net))
+               eth_start(dev, GFP_KERNEL);
+
+       spin_lock_irq(&dev->lock);
+       link = dev->port_usb;
+       if (link && link->open)
+               link->open(link);
+       spin_unlock_irq(&dev->lock);
+
+       return 0;
+}
+
+static int eth_stop(struct net_device *net)
+{
+       struct eth_dev  *dev = netdev_priv(net);
+       unsigned long   flags;
+
+       VDBG(dev, "%s\n", __func__);
+       netif_stop_queue(net);
+
+       DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+               dev->net->stats.rx_packets, dev->net->stats.tx_packets,
+               dev->net->stats.rx_errors, dev->net->stats.tx_errors
+               );
+
+       /* ensure there are no more active requests */
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->port_usb) {
+               struct gether   *link = dev->port_usb;
+
+               if (link->close)
+                       link->close(link);
+
+               /* NOTE:  we have no abort-queue primitive we could use
+                * to cancel all pending I/O.  Instead, we disable then
+                * reenable the endpoints ... this idiom may leave toggle
+                * wrong, but that's a self-correcting error.
+                *
+                * REVISIT:  we *COULD* just let the transfers complete at
+                * their own pace; the network stack can handle old packets.
+                * For the moment we leave this here, since it works.
+                */
+               usb_ep_disable(link->in_ep);
+               usb_ep_disable(link->out_ep);
+               if (netif_carrier_ok(net)) {
+                       DBG(dev, "host still using in/out endpoints\n");
+                       usb_ep_enable(link->in_ep);
+                       usb_ep_enable(link->out_ep);
+               }
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
+static char *dev_addr;
+module_param(dev_addr, charp, S_IRUGO);
+MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
+
+/* this address is invisible to ifconfig */
+static char *host_addr;
+module_param(host_addr, charp, S_IRUGO);
+MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
+
+static int get_ether_addr(const char *str, u8 *dev_addr)
+{
+       if (str) {
+               unsigned        i;
+
+               for (i = 0; i < 6; i++) {
+                       unsigned char num;
+
+                       if ((*str == '.') || (*str == ':'))
+                               str++;
+                       num = hex_to_bin(*str++) << 4;
+                       num |= hex_to_bin(*str++);
+                       dev_addr [i] = num;
+               }
+               if (is_valid_ether_addr(dev_addr))
+                       return 0;
+       }
+       eth_random_addr(dev_addr);
+       return 1;
+}
+
+static struct eth_dev *the_dev;
+
+static const struct net_device_ops eth_netdev_ops = {
+       .ndo_open               = eth_open,
+       .ndo_stop               = eth_stop,
+       .ndo_start_xmit         = eth_start_xmit,
+       .ndo_change_mtu         = ueth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static struct device_type gadget_type = {
+       .name   = "gadget",
+};
+
+/**
+ * gether_setup_name - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ *     host side of the link is recorded
+ * @netname: name for network device (for example, "usb")
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework.  The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+               const char *netname)
+{
+       struct eth_dev          *dev;
+       struct net_device       *net;
+       int                     status;
+
+       if (the_dev)
+               return -EBUSY;
+
+       net = alloc_etherdev(sizeof *dev);
+       if (!net)
+               return -ENOMEM;
+
+       dev = netdev_priv(net);
+       spin_lock_init(&dev->lock);
+       spin_lock_init(&dev->req_lock);
+       INIT_WORK(&dev->work, eth_work);
+       INIT_LIST_HEAD(&dev->tx_reqs);
+       INIT_LIST_HEAD(&dev->rx_reqs);
+
+       skb_queue_head_init(&dev->rx_frames);
+
+       /* network device setup */
+       dev->net = net;
+       snprintf(net->name, sizeof(net->name), "%s%%d", netname);
+
+       if (get_ether_addr(dev_addr, net->dev_addr))
+               dev_warn(&g->dev,
+                       "using random %s ethernet address\n", "self");
+       if (get_ether_addr(host_addr, dev->host_mac))
+               dev_warn(&g->dev,
+                       "using random %s ethernet address\n", "host");
+
+       if (ethaddr)
+               memcpy(ethaddr, dev->host_mac, ETH_ALEN);
+
+       net->netdev_ops = &eth_netdev_ops;
+
+       SET_ETHTOOL_OPS(net, &ops);
+
+       dev->gadget = g;
+       SET_NETDEV_DEV(net, &g->dev);
+       SET_NETDEV_DEVTYPE(net, &gadget_type);
+
+       status = register_netdev(net);
+       if (status < 0) {
+               dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
+               free_netdev(net);
+       } else {
+               INFO(dev, "MAC %pM\n", net->dev_addr);
+               INFO(dev, "HOST MAC %pM\n", dev->host_mac);
+
+               the_dev = dev;
+
+               /* two kinds of host-initiated state changes:
+                *  - iff DATA transfer is active, carrier is "on"
+                *  - tx queueing enabled if open *and* carrier is "on"
+                */
+               netif_carrier_off(net);
+       }
+
+       return status;
+}
+
+/**
+ * gether_cleanup - remove Ethernet-over-USB device
+ * Context: may sleep
+ *
+ * This is called to free all resources allocated by @gether_setup().
+ */
+void gether_cleanup(void)
+{
+       if (!the_dev)
+               return;
+
+       unregister_netdev(the_dev->net);
+       flush_work_sync(&the_dev->work);
+       free_netdev(the_dev->net);
+
+       the_dev = NULL;
+}
+
+
+/**
+ * gether_connect - notify network layer that USB link is active
+ * @link: the USB link, set up with endpoints, descriptors matching
+ *     current device speed, and any framing wrapper(s) set up.
+ * Context: irqs blocked
+ *
+ * This is called to activate endpoints and let the network layer know
+ * the connection is active ("carrier detect").  It may cause the I/O
+ * queues to open and start letting network packets flow, but will in
+ * any case activate the endpoints so that they respond properly to the
+ * USB host.
+ *
+ * Verify net_device pointer returned using IS_ERR().  If it doesn't
+ * indicate some error code (negative errno), ep->driver_data values
+ * have been overwritten.
+ */
+struct net_device *gether_connect(struct gether *link)
+{
+       struct eth_dev          *dev = the_dev;
+       int                     result = 0;
+
+       if (!dev)
+               return ERR_PTR(-EINVAL);
+
+       link->in_ep->driver_data = dev;
+       result = usb_ep_enable(link->in_ep);
+       if (result != 0) {
+               DBG(dev, "enable %s --> %d\n",
+                       link->in_ep->name, result);
+               goto fail0;
+       }
+
+       link->out_ep->driver_data = dev;
+       result = usb_ep_enable(link->out_ep);
+       if (result != 0) {
+               DBG(dev, "enable %s --> %d\n",
+                       link->out_ep->name, result);
+               goto fail1;
+       }
+
+       if (result == 0)
+               result = alloc_requests(dev, link, qlen(dev->gadget));
+
+       if (result == 0) {
+               dev->zlp = link->is_zlp_ok;
+               DBG(dev, "qlen %d\n", qlen(dev->gadget));
+
+               dev->header_len = link->header_len;
+               dev->unwrap = link->unwrap;
+               dev->wrap = link->wrap;
+
+               spin_lock(&dev->lock);
+               dev->port_usb = link;
+               link->ioport = dev;
+               if (netif_running(dev->net)) {
+                       if (link->open)
+                               link->open(link);
+               } else {
+                       if (link->close)
+                               link->close(link);
+               }
+               spin_unlock(&dev->lock);
+
+               netif_carrier_on(dev->net);
+               if (netif_running(dev->net))
+                       eth_start(dev, GFP_ATOMIC);
+
+       /* on error, disable any endpoints  */
+       } else {
+               (void) usb_ep_disable(link->out_ep);
+fail1:
+               (void) usb_ep_disable(link->in_ep);
+       }
+fail0:
+       /* caller is responsible for cleanup on error */
+       if (result < 0)
+               return ERR_PTR(result);
+       return dev->net;
+}
+
+/**
+ * gether_disconnect - notify network layer that USB link is inactive
+ * @link: the USB link, on which gether_connect() was called
+ * Context: irqs blocked
+ *
+ * This is called to deactivate endpoints and let the network layer know
+ * the connection went inactive ("no carrier").
+ *
+ * On return, the state is as if gether_connect() had never been called.
+ * The endpoints are inactive, and accordingly without active USB I/O.
+ * Pointers to endpoint descriptors and endpoint private data are nulled.
+ */
+void gether_disconnect(struct gether *link)
+{
+       struct eth_dev          *dev = link->ioport;
+       struct usb_request      *req;
+
+       WARN_ON(!dev);
+       if (!dev)
+               return;
+
+       DBG(dev, "%s\n", __func__);
+
+       netif_stop_queue(dev->net);
+       netif_carrier_off(dev->net);
+
+       /* disable endpoints, forcing (synchronous) completion
+        * of all pending i/o.  then free the request objects
+        * and forget about the endpoints.
+        */
+       usb_ep_disable(link->in_ep);
+       spin_lock(&dev->req_lock);
+       while (!list_empty(&dev->tx_reqs)) {
+               req = container_of(dev->tx_reqs.next,
+                                       struct usb_request, list);
+               list_del(&req->list);
+
+               spin_unlock(&dev->req_lock);
+               usb_ep_free_request(link->in_ep, req);
+               spin_lock(&dev->req_lock);
+       }
+       spin_unlock(&dev->req_lock);
+       link->in_ep->driver_data = NULL;
+       link->in_ep->desc = NULL;
+
+       usb_ep_disable(link->out_ep);
+       spin_lock(&dev->req_lock);
+       while (!list_empty(&dev->rx_reqs)) {
+               req = container_of(dev->rx_reqs.next,
+                                       struct usb_request, list);
+               list_del(&req->list);
+
+               spin_unlock(&dev->req_lock);
+               usb_ep_free_request(link->out_ep, req);
+               spin_lock(&dev->req_lock);
+       }
+       spin_unlock(&dev->req_lock);
+       link->out_ep->driver_data = NULL;
+       link->out_ep->desc = NULL;
+
+       /* finish forgetting about this USB link episode */
+       dev->header_len = 0;
+       dev->unwrap = NULL;
+       dev->wrap = NULL;
+
+       spin_lock(&dev->lock);
+       dev->port_usb = NULL;
+       link->ioport = NULL;
+       spin_unlock(&dev->lock);
+}
diff --git a/drivers/staging/ccg/u_ether.h b/drivers/staging/ccg/u_ether.h
new file mode 100644 (file)
index 0000000..6f4a162
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * u_ether.h -- interface to USB gadget "ethernet link" utilities
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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.
+ */
+
+#ifndef __U_ETHER_H
+#define __U_ETHER_H
+
+#include <linux/err.h>
+#include <linux/if_ether.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+
+#include "gadget_chips.h"
+
+
+/*
+ * This represents the USB side of an "ethernet" link, managed by a USB
+ * function which provides control and (maybe) framing.  Two functions
+ * in different configurations could share the same ethernet link/netdev,
+ * using different host interaction models.
+ *
+ * There is a current limitation that only one instance of this link may
+ * be present in any given configuration.  When that's a problem, network
+ * layer facilities can be used to package multiple logical links on this
+ * single "physical" one.
+ */
+struct gether {
+       struct usb_function             func;
+
+       /* updated by gether_{connect,disconnect} */
+       struct eth_dev                  *ioport;
+
+       /* endpoints handle full and/or high speeds */
+       struct usb_ep                   *in_ep;
+       struct usb_ep                   *out_ep;
+
+       bool                            is_zlp_ok;
+
+       u16                             cdc_filter;
+
+       /* hooks for added framing, as needed for RNDIS and EEM. */
+       u32                             header_len;
+       /* NCM requires fixed size bundles */
+       bool                            is_fixed;
+       u32                             fixed_out_len;
+       u32                             fixed_in_len;
+       struct sk_buff                  *(*wrap)(struct gether *port,
+                                               struct sk_buff *skb);
+       int                             (*unwrap)(struct gether *port,
+                                               struct sk_buff *skb,
+                                               struct sk_buff_head *list);
+
+       /* called on network open/close */
+       void                            (*open)(struct gether *);
+       void                            (*close)(struct gether *);
+};
+
+#define        DEFAULT_FILTER  (USB_CDC_PACKET_TYPE_BROADCAST \
+                       |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+                       |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+                       |USB_CDC_PACKET_TYPE_DIRECTED)
+
+/* variant of gether_setup that allows customizing network device name */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+               const char *netname);
+
+/* netdev setup/teardown as directed by the gadget driver */
+/* gether_setup - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ *     host side of the link is recorded
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework.  The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+{
+       return gether_setup_name(g, ethaddr, "usb");
+}
+
+void gether_cleanup(void);
+
+/* connect/disconnect is handled by individual functions */
+struct net_device *gether_connect(struct gether *);
+void gether_disconnect(struct gether *);
+
+/* Some controllers can't support CDC Ethernet (ECM) ... */
+static inline bool can_support_ecm(struct usb_gadget *gadget)
+{
+       if (!gadget_supports_altsettings(gadget))
+               return false;
+
+       /* Everything else is *presumably* fine ... but this is a bit
+        * chancy, so be **CERTAIN** there are no hardware issues with
+        * your controller.  Add it above if it can't handle CDC.
+        */
+       return true;
+}
+
+/* each configuration may bind one instance of an ethernet link */
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int eem_bind_config(struct usb_configuration *c);
+
+#ifdef USB_ETH_RNDIS
+
+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+                               u32 vendorID, const char *manufacturer);
+
+#else
+
+static inline int
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+                               u32 vendorID, const char *manufacturer)
+{
+       return 0;
+}
+
+#endif
+
+/**
+ * rndis_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ *     side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup().  Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+static inline int rndis_bind_config(struct usb_configuration *c,
+                                   u8 ethaddr[ETH_ALEN])
+{
+       return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+}
+
+
+#endif /* __U_ETHER_H */
diff --git a/drivers/staging/ccg/u_serial.c b/drivers/staging/ccg/u_serial.c
new file mode 100644 (file)
index 0000000..5b3f5ff
--- /dev/null
@@ -0,0 +1,1341 @@
+/*
+ * u_serial.c - utilities for USB gadget "serial port"/TTY support
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This code also borrows from usbserial.c, which is
+ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
+ * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com)
+ *
+ * This software is 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.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "u_serial.h"
+
+
+/*
+ * This component encapsulates the TTY layer glue needed to provide basic
+ * "serial port" functionality through the USB gadget stack.  Each such
+ * port is exposed through a /dev/ttyGS* node.
+ *
+ * After initialization (gserial_setup), these TTY port devices stay
+ * available until they are removed (gserial_cleanup).  Each one may be
+ * connected to a USB function (gserial_connect), or disconnected (with
+ * gserial_disconnect) when the USB host issues a config change event.
+ * Data can only flow when the port is connected to the host.
+ *
+ * A given TTY port can be made available in multiple configurations.
+ * For example, each one might expose a ttyGS0 node which provides a
+ * login application.  In one case that might use CDC ACM interface 0,
+ * while another configuration might use interface 3 for that.  The
+ * work to handle that (including descriptor management) is not part
+ * of this component.
+ *
+ * Configurations may expose more than one TTY port.  For example, if
+ * ttyGS0 provides login service, then ttyGS1 might provide dialer access
+ * for a telephone or fax link.  And ttyGS2 might be something that just
+ * needs a simple byte stream interface for some messaging protocol that
+ * is managed in userspace ... OBEX, PTP, and MTP have been mentioned.
+ */
+
+#define PREFIX "ttyGS"
+
+/*
+ * gserial is the lifecycle interface, used by USB functions
+ * gs_port is the I/O nexus, used by the tty driver
+ * tty_struct links to the tty/filesystem framework
+ *
+ * gserial <---> gs_port ... links will be null when the USB link is
+ * inactive; managed by gserial_{connect,disconnect}().  each gserial
+ * instance can wrap its own USB control protocol.
+ *     gserial->ioport == usb_ep->driver_data ... gs_port
+ *     gs_port->port_usb ... gserial
+ *
+ * gs_port <---> tty_struct ... links will be null when the TTY file
+ * isn't opened; managed by gs_open()/gs_close()
+ *     gserial->port_tty ... tty_struct
+ *     tty_struct->driver_data ... gserial
+ */
+
+/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the
+ * next layer of buffering.  For TX that's a circular buffer; for RX
+ * consider it a NOP.  A third layer is provided by the TTY code.
+ */
+#define QUEUE_SIZE             16
+#define WRITE_BUF_SIZE         8192            /* TX only */
+
+/* circular buffer */
+struct gs_buf {
+       unsigned                buf_size;
+       char                    *buf_buf;
+       char                    *buf_get;
+       char                    *buf_put;
+};
+
+/*
+ * The port structure holds info for each port, one for each minor number
+ * (and thus for each /dev/ node).
+ */
+struct gs_port {
+       struct tty_port         port;
+       spinlock_t              port_lock;      /* guard port_* access */
+
+       struct gserial          *port_usb;
+
+       bool                    openclose;      /* open/close in progress */
+       u8                      port_num;
+
+       struct list_head        read_pool;
+       int read_started;
+       int read_allocated;
+       struct list_head        read_queue;
+       unsigned                n_read;
+       struct tasklet_struct   push;
+
+       struct list_head        write_pool;
+       int write_started;
+       int write_allocated;
+       struct gs_buf           port_write_buf;
+       wait_queue_head_t       drain_wait;     /* wait while writes drain */
+
+       /* REVISIT this state ... */
+       struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
+};
+
+/* increase N_PORTS if you need more */
+#define N_PORTS                4
+static struct portmaster {
+       struct mutex    lock;                   /* protect open/close */
+       struct gs_port  *port;
+} ports[N_PORTS];
+static unsigned        n_ports;
+
+#define GS_CLOSE_TIMEOUT               15              /* seconds */
+
+
+
+#ifdef VERBOSE_DEBUG
+#define pr_vdebug(fmt, arg...) \
+       pr_debug(fmt, ##arg)
+#else
+#define pr_vdebug(fmt, arg...) \
+       ({ if (0) pr_debug(fmt, ##arg); })
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* Circular Buffer */
+
+/*
+ * gs_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
+{
+       gb->buf_buf = kmalloc(size, GFP_KERNEL);
+       if (gb->buf_buf == NULL)
+               return -ENOMEM;
+
+       gb->buf_size = size;
+       gb->buf_put = gb->buf_buf;
+       gb->buf_get = gb->buf_buf;
+
+       return 0;
+}
+
+/*
+ * gs_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void gs_buf_free(struct gs_buf *gb)
+{
+       kfree(gb->buf_buf);
+       gb->buf_buf = NULL;
+}
+
+/*
+ * gs_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void gs_buf_clear(struct gs_buf *gb)
+{
+       gb->buf_get = gb->buf_put;
+       /* equivalent to a get of all data available */
+}
+
+/*
+ * gs_buf_data_avail
+ *
+ * Return the number of bytes of data written into the circular
+ * buffer.
+ */
+static unsigned gs_buf_data_avail(struct gs_buf *gb)
+{
+       return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
+}
+
+/*
+ * gs_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+static unsigned gs_buf_space_avail(struct gs_buf *gb)
+{
+       return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
+}
+
+/*
+ * gs_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned
+gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
+{
+       unsigned len;
+
+       len  = gs_buf_space_avail(gb);
+       if (count > len)
+               count = len;
+
+       if (count == 0)
+               return 0;
+
+       len = gb->buf_buf + gb->buf_size - gb->buf_put;
+       if (count > len) {
+               memcpy(gb->buf_put, buf, len);
+               memcpy(gb->buf_buf, buf+len, count - len);
+               gb->buf_put = gb->buf_buf + count - len;
+       } else {
+               memcpy(gb->buf_put, buf, count);
+               if (count < len)
+                       gb->buf_put += count;
+               else /* count == len */
+                       gb->buf_put = gb->buf_buf;
+       }
+
+       return count;
+}
+
+/*
+ * gs_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned
+gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
+{
+       unsigned len;
+
+       len = gs_buf_data_avail(gb);
+       if (count > len)
+               count = len;
+
+       if (count == 0)
+               return 0;
+
+       len = gb->buf_buf + gb->buf_size - gb->buf_get;
+       if (count > len) {
+               memcpy(buf, gb->buf_get, len);
+               memcpy(buf+len, gb->buf_buf, count - len);
+               gb->buf_get = gb->buf_buf + count - len;
+       } else {
+               memcpy(buf, gb->buf_get, count);
+               if (count < len)
+                       gb->buf_get += count;
+               else /* count == len */
+                       gb->buf_get = gb->buf_buf;
+       }
+
+       return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* I/O glue between TTY (upper) and USB function (lower) driver layers */
+
+/*
+ * gs_alloc_req
+ *
+ * Allocate a usb_request and its buffer.  Returns a pointer to the
+ * usb_request or NULL if there is an error.
+ */
+struct usb_request *
+gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
+{
+       struct usb_request *req;
+
+       req = usb_ep_alloc_request(ep, kmalloc_flags);
+
+       if (req != NULL) {
+               req->length = len;
+               req->buf = kmalloc(len, kmalloc_flags);
+               if (req->buf == NULL) {
+                       usb_ep_free_request(ep, req);
+                       return NULL;
+               }
+       }
+
+       return req;
+}
+
+/*
+ * gs_free_req
+ *
+ * Free a usb_request and its buffer.
+ */
+void gs_free_req(struct usb_ep *ep, struct usb_request *req)
+{
+       kfree(req->buf);
+       usb_ep_free_request(ep, req);
+}
+
+/*
+ * gs_send_packet
+ *
+ * If there is data to send, a packet is built in the given
+ * buffer and the size is returned.  If there is no data to
+ * send, 0 is returned.
+ *
+ * Called with port_lock held.
+ */
+static unsigned
+gs_send_packet(struct gs_port *port, char *packet, unsigned size)
+{
+       unsigned len;
+
+       len = gs_buf_data_avail(&port->port_write_buf);
+       if (len < size)
+               size = len;
+       if (size != 0)
+               size = gs_buf_get(&port->port_write_buf, packet, size);
+       return size;
+}
+
+/*
+ * gs_start_tx
+ *
+ * This function finds available write requests, calls
+ * gs_send_packet to fill these packets with data, and
+ * continues until either there are no more write requests
+ * available or no more data to send.  This function is
+ * run whenever data arrives or write requests are available.
+ *
+ * Context: caller owns port_lock; port_usb is non-null.
+ */
+static int gs_start_tx(struct gs_port *port)
+/*
+__releases(&port->port_lock)
+__acquires(&port->port_lock)
+*/
+{
+       struct list_head        *pool = &port->write_pool;
+       struct usb_ep           *in = port->port_usb->in;
+       int                     status = 0;
+       bool                    do_tty_wake = false;
+
+       while (!list_empty(pool)) {
+               struct usb_request      *req;
+               int                     len;
+
+               if (port->write_started >= QUEUE_SIZE)
+                       break;
+
+               req = list_entry(pool->next, struct usb_request, list);
+               len = gs_send_packet(port, req->buf, in->maxpacket);
+               if (len == 0) {
+                       wake_up_interruptible(&port->drain_wait);
+                       break;
+               }
+               do_tty_wake = true;
+
+               req->length = len;
+               list_del(&req->list);
+               req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0);
+
+               pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
+                               port->port_num, len, *((u8 *)req->buf),
+                               *((u8 *)req->buf+1), *((u8 *)req->buf+2));
+
+               /* Drop lock while we call out of driver; completions
+                * could be issued while we do so.  Disconnection may
+                * happen too; maybe immediately before we queue this!
+                *
+                * NOTE that we may keep sending data for a while after
+                * the TTY closed (dev->ioport->port_tty is NULL).
+                */
+               spin_unlock(&port->port_lock);
+               status = usb_ep_queue(in, req, GFP_ATOMIC);
+               spin_lock(&port->port_lock);
+
+               if (status) {
+                       pr_debug("%s: %s %s err %d\n",
+                                       __func__, "queue", in->name, status);
+                       list_add(&req->list, pool);
+                       break;
+               }
+
+               port->write_started++;
+
+               /* abort immediately after disconnect */
+               if (!port->port_usb)
+                       break;
+       }
+
+       if (do_tty_wake && port->port.tty)
+               tty_wakeup(port->port.tty);
+       return status;
+}
+
+/*
+ * Context: caller owns port_lock, and port_usb is set
+ */
+static unsigned gs_start_rx(struct gs_port *port)
+/*
+__releases(&port->port_lock)
+__acquires(&port->port_lock)
+*/
+{
+       struct list_head        *pool = &port->read_pool;
+       struct usb_ep           *out = port->port_usb->out;
+
+       while (!list_empty(pool)) {
+               struct usb_request      *req;
+               int                     status;
+               struct tty_struct       *tty;
+
+               /* no more rx if closed */
+               tty = port->port.tty;
+               if (!tty)
+                       break;
+
+               if (port->read_started >= QUEUE_SIZE)
+                       break;
+
+               req = list_entry(pool->next, struct usb_request, list);
+               list_del(&req->list);
+               req->length = out->maxpacket;
+
+               /* drop lock while we call out; the controller driver
+                * may need to call us back (e.g. for disconnect)
+                */
+               spin_unlock(&port->port_lock);
+               status = usb_ep_queue(out, req, GFP_ATOMIC);
+               spin_lock(&port->port_lock);
+
+               if (status) {
+                       pr_debug("%s: %s %s err %d\n",
+                                       __func__, "queue", out->name, status);
+                       list_add(&req->list, pool);
+                       break;
+               }
+               port->read_started++;
+
+               /* abort immediately after disconnect */
+               if (!port->port_usb)
+                       break;
+       }
+       return port->read_started;
+}
+
+/*
+ * RX tasklet takes data out of the RX queue and hands it up to the TTY
+ * layer until it refuses to take any more data (or is throttled back).
+ * Then it issues reads for any further data.
+ *
+ * If the RX queue becomes full enough that no usb_request is queued,
+ * the OUT endpoint may begin NAKing as soon as its FIFO fills up.
+ * So QUEUE_SIZE packets plus however many the FIFO holds (usually two)
+ * can be buffered before the TTY layer's buffers (currently 64 KB).
+ */
+static void gs_rx_push(unsigned long _port)
+{
+       struct gs_port          *port = (void *)_port;
+       struct tty_struct       *tty;
+       struct list_head        *queue = &port->read_queue;
+       bool                    disconnect = false;
+       bool                    do_push = false;
+
+       /* hand any queued data to the tty */
+       spin_lock_irq(&port->port_lock);
+       tty = port->port.tty;
+       while (!list_empty(queue)) {
+               struct usb_request      *req;
+
+               req = list_first_entry(queue, struct usb_request, list);
+
+               /* discard data if tty was closed */
+               if (!tty)
+                       goto recycle;
+
+               /* leave data queued if tty was rx throttled */
+               if (test_bit(TTY_THROTTLED, &tty->flags))
+                       break;
+
+               switch (req->status) {
+               case -ESHUTDOWN:
+                       disconnect = true;
+                       pr_vdebug(PREFIX "%d: shutdown\n", port->port_num);
+                       break;
+
+               default:
+                       /* presumably a transient fault */
+                       pr_warning(PREFIX "%d: unexpected RX status %d\n",
+                                       port->port_num, req->status);
+                       /* FALLTHROUGH */
+               case 0:
+                       /* normal completion */
+                       break;
+               }
+
+               /* push data to (open) tty */
+               if (req->actual) {
+                       char            *packet = req->buf;
+                       unsigned        size = req->actual;
+                       unsigned        n;
+                       int             count;
+
+                       /* we may have pushed part of this packet already... */
+                       n = port->n_read;
+                       if (n) {
+                               packet += n;
+                               size -= n;
+                       }
+
+                       count = tty_insert_flip_string(tty, packet, size);
+                       if (count)
+                               do_push = true;
+                       if (count != size) {
+                               /* stop pushing; TTY layer can't handle more */
+                               port->n_read += count;
+                               pr_vdebug(PREFIX "%d: rx block %d/%d\n",
+                                               port->port_num,
+                                               count, req->actual);
+                               break;
+                       }
+                       port->n_read = 0;
+               }
+recycle:
+               list_move(&req->list, &port->read_pool);
+               port->read_started--;
+       }
+
+       /* Push from tty to ldisc; without low_latency set this is handled by
+        * a workqueue, so we won't get callbacks and can hold port_lock
+        */
+       if (tty && do_push)
+               tty_flip_buffer_push(tty);
+
+
+       /* We want our data queue to become empty ASAP, keeping data
+        * in the tty and ldisc (not here).  If we couldn't push any
+        * this time around, there may be trouble unless there's an
+        * implicit tty_unthrottle() call on its way...
+        *
+        * REVISIT we should probably add a timer to keep the tasklet
+        * from starving ... but it's not clear that case ever happens.
+        */
+       if (!list_empty(queue) && tty) {
+               if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+                       if (do_push)
+                               tasklet_schedule(&port->push);
+                       else
+                               pr_warning(PREFIX "%d: RX not scheduled?\n",
+                                       port->port_num);
+               }
+       }
+
+       /* If we're still connected, refill the USB RX queue. */
+       if (!disconnect && port->port_usb)
+               gs_start_rx(port);
+
+       spin_unlock_irq(&port->port_lock);
+}
+
+static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct gs_port  *port = ep->driver_data;
+
+       /* Queue all received data until the tty layer is ready for it. */
+       spin_lock(&port->port_lock);
+       list_add_tail(&req->list, &port->read_queue);
+       tasklet_schedule(&port->push);
+       spin_unlock(&port->port_lock);
+}
+
+static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct gs_port  *port = ep->driver_data;
+
+       spin_lock(&port->port_lock);
+       list_add(&req->list, &port->write_pool);
+       port->write_started--;
+
+       switch (req->status) {
+       default:
+               /* presumably a transient fault */
+               pr_warning("%s: unexpected %s status %d\n",
+                               __func__, ep->name, req->status);
+               /* FALL THROUGH */
+       case 0:
+               /* normal completion */
+               gs_start_tx(port);
+               break;
+
+       case -ESHUTDOWN:
+               /* disconnect */
+               pr_vdebug("%s: %s shutdown\n", __func__, ep->name);
+               break;
+       }
+
+       spin_unlock(&port->port_lock);
+}
+
+static void gs_free_requests(struct usb_ep *ep, struct list_head *head,
+                                                        int *allocated)
+{
+       struct usb_request      *req;
+
+       while (!list_empty(head)) {
+               req = list_entry(head->next, struct usb_request, list);
+               list_del(&req->list);
+               gs_free_req(ep, req);
+               if (allocated)
+                       (*allocated)--;
+       }
+}
+
+static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
+               void (*fn)(struct usb_ep *, struct usb_request *),
+               int *allocated)
+{
+       int                     i;
+       struct usb_request      *req;
+       int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE;
+
+       /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
+        * do quite that many this time, don't fail ... we just won't
+        * be as speedy as we might otherwise be.
+        */
+       for (i = 0; i < n; i++) {
+               req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
+               if (!req)
+                       return list_empty(head) ? -ENOMEM : 0;
+               req->complete = fn;
+               list_add_tail(&req->list, head);
+               if (allocated)
+                       (*allocated)++;
+       }
+       return 0;
+}
+
+/**
+ * gs_start_io - start USB I/O streams
+ * @dev: encapsulates endpoints to use
+ * Context: holding port_lock; port_tty and port_usb are non-null
+ *
+ * We only start I/O when something is connected to both sides of
+ * this port.  If nothing is listening on the host side, we may
+ * be pointlessly filling up our TX buffers and FIFO.
+ */
+static int gs_start_io(struct gs_port *port)
+{
+       struct list_head        *head = &port->read_pool;
+       struct usb_ep           *ep = port->port_usb->out;
+       int                     status;
+       unsigned                started;
+
+       /* Allocate RX and TX I/O buffers.  We can't easily do this much
+        * earlier (with GFP_KERNEL) because the requests are coupled to
+        * endpoints, as are the packet sizes we'll be using.  Different
+        * configurations may use different endpoints with a given port;
+        * and high speed vs full speed changes packet sizes too.
+        */
+       status = gs_alloc_requests(ep, head, gs_read_complete,
+               &port->read_allocated);
+       if (status)
+               return status;
+
+       status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
+                       gs_write_complete, &port->write_allocated);
+       if (status) {
+               gs_free_requests(ep, head, &port->read_allocated);
+               return status;
+       }
+
+       /* queue read requests */
+       port->n_read = 0;
+       started = gs_start_rx(port);
+
+       /* unblock any pending writes into our circular buffer */
+       if (started) {
+               tty_wakeup(port->port.tty);
+       } else {
+               gs_free_requests(ep, head, &port->read_allocated);
+               gs_free_requests(port->port_usb->in, &port->write_pool,
+                       &port->write_allocated);
+               status = -EIO;
+       }
+
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* TTY Driver */
+
+/*
+ * gs_open sets up the link between a gs_port and its associated TTY.
+ * That link is broken *only* by TTY close(), and all driver methods
+ * know that.
+ */
+static int gs_open(struct tty_struct *tty, struct file *file)
+{
+       int             port_num = tty->index;
+       struct gs_port  *port;
+       int             status;
+
+       do {
+               mutex_lock(&ports[port_num].lock);
+               port = ports[port_num].port;
+               if (!port)
+                       status = -ENODEV;
+               else {
+                       spin_lock_irq(&port->port_lock);
+
+                       /* already open?  Great. */
+                       if (port->port.count) {
+                               status = 0;
+                               port->port.count++;
+
+                       /* currently opening/closing? wait ... */
+                       } else if (port->openclose) {
+                               status = -EBUSY;
+
+                       /* ... else we do the work */
+                       } else {
+                               status = -EAGAIN;
+                               port->openclose = true;
+                       }
+                       spin_unlock_irq(&port->port_lock);
+               }
+               mutex_unlock(&ports[port_num].lock);
+
+               switch (status) {
+               default:
+                       /* fully handled */
+                       return status;
+               case -EAGAIN:
+                       /* must do the work */
+                       break;
+               case -EBUSY:
+                       /* wait for EAGAIN task to finish */
+                       msleep(1);
+                       /* REVISIT could have a waitchannel here, if
+                        * concurrent open performance is important
+                        */
+                       break;
+               }
+       } while (status != -EAGAIN);
+
+       /* Do the "real open" */
+       spin_lock_irq(&port->port_lock);
+
+       /* allocate circular buffer on first open */
+       if (port->port_write_buf.buf_buf == NULL) {
+
+               spin_unlock_irq(&port->port_lock);
+               status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE);
+               spin_lock_irq(&port->port_lock);
+
+               if (status) {
+                       pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n",
+                               port->port_num, tty, file);
+                       port->openclose = false;
+                       goto exit_unlock_port;
+               }
+       }
+
+       /* REVISIT if REMOVED (ports[].port NULL), abort the open
+        * to let rmmod work faster (but this way isn't wrong).
+        */
+
+       /* REVISIT maybe wait for "carrier detect" */
+
+       tty->driver_data = port;
+       port->port.tty = tty;
+
+       port->port.count = 1;
+       port->openclose = false;
+
+       /* if connected, start the I/O stream */
+       if (port->port_usb) {
+               struct gserial  *gser = port->port_usb;
+
+               pr_debug("gs_open: start ttyGS%d\n", port->port_num);
+               gs_start_io(port);
+
+               if (gser->connect)
+                       gser->connect(gser);
+       }
+
+       pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
+
+       status = 0;
+
+exit_unlock_port:
+       spin_unlock_irq(&port->port_lock);
+       return status;
+}
+
+static int gs_writes_finished(struct gs_port *p)
+{
+       int cond;
+
+       /* return true on disconnect or empty buffer */
+       spin_lock_irq(&p->port_lock);
+       cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf);
+       spin_unlock_irq(&p->port_lock);
+
+       return cond;
+}
+
+static void gs_close(struct tty_struct *tty, struct file *file)
+{
+       struct gs_port *port = tty->driver_data;
+       struct gserial  *gser;
+
+       spin_lock_irq(&port->port_lock);
+
+       if (port->port.count != 1) {
+               if (port->port.count == 0)
+                       WARN_ON(1);
+               else
+                       --port->port.count;
+               goto exit;
+       }
+
+       pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file);
+
+       /* mark port as closing but in use; we can drop port lock
+        * and sleep if necessary
+        */
+       port->openclose = true;
+       port->port.count = 0;
+
+       gser = port->port_usb;
+       if (gser && gser->disconnect)
+               gser->disconnect(gser);
+
+       /* wait for circular write buffer to drain, disconnect, or at
+        * most GS_CLOSE_TIMEOUT seconds; then discard the rest
+        */
+       if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) {
+               spin_unlock_irq(&port->port_lock);
+               wait_event_interruptible_timeout(port->drain_wait,
+                                       gs_writes_finished(port),
+                                       GS_CLOSE_TIMEOUT * HZ);
+               spin_lock_irq(&port->port_lock);
+               gser = port->port_usb;
+       }
+
+       /* Iff we're disconnected, there can be no I/O in flight so it's
+        * ok to free the circular buffer; else just scrub it.  And don't
+        * let the push tasklet fire again until we're re-opened.
+        */
+       if (gser == NULL)
+               gs_buf_free(&port->port_write_buf);
+       else
+               gs_buf_clear(&port->port_write_buf);
+
+       tty->driver_data = NULL;
+       port->port.tty = NULL;
+
+       port->openclose = false;
+
+       pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
+                       port->port_num, tty, file);
+
+       wake_up_interruptible(&port->port.close_wait);
+exit:
+       spin_unlock_irq(&port->port_lock);
+}
+
+static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       struct gs_port  *port = tty->driver_data;
+       unsigned long   flags;
+       int             status;
+
+       pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
+                       port->port_num, tty, count);
+
+       spin_lock_irqsave(&port->port_lock, flags);
+       if (count)
+               count = gs_buf_put(&port->port_write_buf, buf, count);
+       /* treat count == 0 as flush_chars() */
+       if (port->port_usb)
+               status = gs_start_tx(port);
+       spin_unlock_irqrestore(&port->port_lock, flags);
+
+       return count;
+}
+
+static int gs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       struct gs_port  *port = tty->driver_data;
+       unsigned long   flags;
+       int             status;
+
+       pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
+               port->port_num, tty, ch, __builtin_return_address(0));
+
+       spin_lock_irqsave(&port->port_lock, flags);
+       status = gs_buf_put(&port->port_write_buf, &ch, 1);
+       spin_unlock_irqrestore(&port->port_lock, flags);
+
+       return status;
+}
+
+static void gs_flush_chars(struct tty_struct *tty)
+{
+       struct gs_port  *port = tty->driver_data;
+       unsigned long   flags;
+
+       pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty);
+
+       spin_lock_irqsave(&port->port_lock, flags);
+       if (port->port_usb)
+               gs_start_tx(port);
+       spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static int gs_write_room(struct tty_struct *tty)
+{
+       struct gs_port  *port = tty->driver_data;
+       unsigned long   flags;
+       int             room = 0;
+
+       spin_lock_irqsave(&port->port_lock, flags);
+       if (port->port_usb)
+               room = gs_buf_space_avail(&port->port_write_buf);
+       spin_unlock_irqrestore(&port->port_lock, flags);
+
+       pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
+               port->port_num, tty, room);
+
+       return room;
+}
+
+static int gs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct gs_port  *port = tty->driver_data;
+       unsigned long   flags;
+       int             chars = 0;
+
+       spin_lock_irqsave(&port->port_lock, flags);
+       chars = gs_buf_data_avail(&port->port_write_buf);
+       spin_unlock_irqrestore(&port->port_lock, flags);
+
+       pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
+               port->port_num, tty, chars);
+
+       return chars;
+}
+
+/* undo side effects of setting TTY_THROTTLED */
+static void gs_unthrottle(struct tty_struct *tty)
+{
+       struct gs_port          *port = tty->driver_data;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&port->port_lock, flags);
+       if (port->port_usb) {
+               /* Kickstart read queue processing.  We don't do xon/xoff,
+                * rts/cts, or other handshaking with the host, but if the
+                * read queue backs up enough we'll be NAKing OUT packets.
+                */
+               tasklet_schedule(&port->push);
+               pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num);
+       }
+       spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static int gs_break_ctl(struct tty_struct *tty, int duration)
+{
+       struct gs_port  *port = tty->driver_data;
+       int             status = 0;
+       struct gserial  *gser;
+
+       pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n",
+                       port->port_num, duration);
+
+       spin_lock_irq(&port->port_lock);
+       gser = port->port_usb;
+       if (gser && gser->send_break)
+               status = gser->send_break(gser, duration);
+       spin_unlock_irq(&port->port_lock);
+
+       return status;
+}
+
+static const struct tty_operations gs_tty_ops = {
+       .open =                 gs_open,
+       .close =                gs_close,
+       .write =                gs_write,
+       .put_char =             gs_put_char,
+       .flush_chars =          gs_flush_chars,
+       .write_room =           gs_write_room,
+       .chars_in_buffer =      gs_chars_in_buffer,
+       .unthrottle =           gs_unthrottle,
+       .break_ctl =            gs_break_ctl,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct tty_driver *gs_tty_driver;
+
+static int
+gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
+{
+       struct gs_port  *port;
+
+       port = kzalloc(sizeof(struct gs_port), GFP_KERNEL);
+       if (port == NULL)
+               return -ENOMEM;
+
+       tty_port_init(&port->port);
+       spin_lock_init(&port->port_lock);
+       init_waitqueue_head(&port->drain_wait);
+
+       tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
+
+       INIT_LIST_HEAD(&port->read_pool);
+       INIT_LIST_HEAD(&port->read_queue);
+       INIT_LIST_HEAD(&port->write_pool);
+
+       port->port_num = port_num;
+       port->port_line_coding = *coding;
+
+       ports[port_num].port = port;
+
+       return 0;
+}
+
+/**
+ * gserial_setup - initialize TTY driver for one or more ports
+ * @g: gadget to associate with these ports
+ * @count: how many ports to support
+ * Context: may sleep
+ *
+ * The TTY stack needs to know in advance how many devices it should
+ * plan to manage.  Use this call to set up the ports you will be
+ * exporting through USB.  Later, connect them to functions based
+ * on what configuration is activated by the USB host; and disconnect
+ * them as appropriate.
+ *
+ * An example would be a two-configuration device in which both
+ * configurations expose port 0, but through different functions.
+ * One configuration could even expose port 1 while the other
+ * one doesn't.
+ *
+ * Returns negative errno or zero.
+ */
+int gserial_setup(struct usb_gadget *g, unsigned count)
+{
+       unsigned                        i;
+       struct usb_cdc_line_coding      coding;
+       int                             status;
+
+       if (count == 0 || count > N_PORTS)
+               return -EINVAL;
+
+       gs_tty_driver = alloc_tty_driver(count);
+       if (!gs_tty_driver)
+               return -ENOMEM;
+
+       gs_tty_driver->driver_name = "g_serial";
+       gs_tty_driver->name = PREFIX;
+       /* uses dynamically assigned dev_t values */
+
+       gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       gs_tty_driver->init_termios = tty_std_termios;
+
+       /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
+        * MS-Windows.  Otherwise, most of these flags shouldn't affect
+        * anything unless we were to actually hook up to a serial line.
+        */
+       gs_tty_driver->init_termios.c_cflag =
+                       B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       gs_tty_driver->init_termios.c_ispeed = 9600;
+       gs_tty_driver->init_termios.c_ospeed = 9600;
+
+       coding.dwDTERate = cpu_to_le32(9600);
+       coding.bCharFormat = 8;
+       coding.bParityType = USB_CDC_NO_PARITY;
+       coding.bDataBits = USB_CDC_1_STOP_BITS;
+
+       tty_set_operations(gs_tty_driver, &gs_tty_ops);
+
+       /* make devices be openable */
+       for (i = 0; i < count; i++) {
+               mutex_init(&ports[i].lock);
+               status = gs_port_alloc(i, &coding);
+               if (status) {
+                       count = i;
+                       goto fail;
+               }
+       }
+       n_ports = count;
+
+       /* export the driver ... */
+       status = tty_register_driver(gs_tty_driver);
+       if (status) {
+               pr_err("%s: cannot register, err %d\n",
+                               __func__, status);
+               goto fail;
+       }
+
+       /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
+       for (i = 0; i < count; i++) {
+               struct device   *tty_dev;
+
+               tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
+               if (IS_ERR(tty_dev))
+                       pr_warning("%s: no classdev for port %d, err %ld\n",
+                               __func__, i, PTR_ERR(tty_dev));
+       }
+
+       pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
+                       count, (count == 1) ? "" : "s");
+
+       return status;
+fail:
+       while (count--)
+               kfree(ports[count].port);
+       put_tty_driver(gs_tty_driver);
+       gs_tty_driver = NULL;
+       return status;
+}
+
+static int gs_closed(struct gs_port *port)
+{
+       int cond;
+
+       spin_lock_irq(&port->port_lock);
+       cond = (port->port.count == 0) && !port->openclose;
+       spin_unlock_irq(&port->port_lock);
+       return cond;
+}
+
+/**
+ * gserial_cleanup - remove TTY-over-USB driver and devices
+ * Context: may sleep
+ *
+ * This is called to free all resources allocated by @gserial_setup().
+ * Accordingly, it may need to wait until some open /dev/ files have
+ * closed.
+ *
+ * The caller must have issued @gserial_disconnect() for any ports
+ * that had previously been connected, so that there is never any
+ * I/O pending when it's called.
+ */
+void gserial_cleanup(void)
+{
+       unsigned        i;
+       struct gs_port  *port;
+
+       if (!gs_tty_driver)
+               return;
+
+       /* start sysfs and /dev/ttyGS* node removal */
+       for (i = 0; i < n_ports; i++)
+               tty_unregister_device(gs_tty_driver, i);
+
+       for (i = 0; i < n_ports; i++) {
+               /* prevent new opens */
+               mutex_lock(&ports[i].lock);
+               port = ports[i].port;
+               ports[i].port = NULL;
+               mutex_unlock(&ports[i].lock);
+
+               tasklet_kill(&port->push);
+
+               /* wait for old opens to finish */
+               wait_event(port->port.close_wait, gs_closed(port));
+
+               WARN_ON(port->port_usb != NULL);
+
+               kfree(port);
+       }
+       n_ports = 0;
+
+       tty_unregister_driver(gs_tty_driver);
+       put_tty_driver(gs_tty_driver);
+       gs_tty_driver = NULL;
+
+       pr_debug("%s: cleaned up ttyGS* support\n", __func__);
+}
+
+/**
+ * gserial_connect - notify TTY I/O glue that USB link is active
+ * @gser: the function, set up with endpoints and descriptors
+ * @port_num: which port is active
+ * Context: any (usually from irq)
+ *
+ * This is called activate endpoints and let the TTY layer know that
+ * the connection is active ... not unlike "carrier detect".  It won't
+ * necessarily start I/O queues; unless the TTY is held open by any
+ * task, there would be no point.  However, the endpoints will be
+ * activated so the USB host can perform I/O, subject to basic USB
+ * hardware flow control.
+ *
+ * Caller needs to have set up the endpoints and USB function in @dev
+ * before calling this, as well as the appropriate (speed-specific)
+ * endpoint descriptors, and also have set up the TTY driver by calling
+ * @gserial_setup().
+ *
+ * Returns negative errno or zero.
+ * On success, ep->driver_data will be overwritten.
+ */
+int gserial_connect(struct gserial *gser, u8 port_num)
+{
+       struct gs_port  *port;
+       unsigned long   flags;
+       int             status;
+
+       if (!gs_tty_driver || port_num >= n_ports)
+               return -ENXIO;
+
+       /* we "know" gserial_cleanup() hasn't been called */
+       port = ports[port_num].port;
+
+       /* activate the endpoints */
+       status = usb_ep_enable(gser->in);
+       if (status < 0)
+               return status;
+       gser->in->driver_data = port;
+
+       status = usb_ep_enable(gser->out);
+       if (status < 0)
+               goto fail_out;
+       gser->out->driver_data = port;
+
+       /* then tell the tty glue that I/O can work */
+       spin_lock_irqsave(&port->port_lock, flags);
+       gser->ioport = port;
+       port->port_usb = gser;
+
+       /* REVISIT unclear how best to handle this state...
+        * we don't really couple it with the Linux TTY.
+        */
+       gser->port_line_coding = port->port_line_coding;
+
+       /* REVISIT if waiting on "carrier detect", signal. */
+
+       /* if it's already open, start I/O ... and notify the serial
+        * protocol about open/close status (connect/disconnect).
+        */
+       if (port->port.count) {
+               pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
+               gs_start_io(port);
+               if (gser->connect)
+                       gser->connect(gser);
+       } else {
+               if (gser->disconnect)
+                       gser->disconnect(gser);
+       }
+
+       spin_unlock_irqrestore(&port->port_lock, flags);
+
+       return status;
+
+fail_out:
+       usb_ep_disable(gser->in);
+       gser->in->driver_data = NULL;
+       return status;
+}
+
+/**
+ * gserial_disconnect - notify TTY I/O glue that USB link is inactive
+ * @gser: the function, on which gserial_connect() was called
+ * Context: any (usually from irq)
+ *
+ * This is called to deactivate endpoints and let the TTY layer know
+ * that the connection went inactive ... not unlike "hangup".
+ *
+ * On return, the state is as if gserial_connect() had never been called;
+ * there is no active USB I/O on these endpoints.
+ */
+void gserial_disconnect(struct gserial *gser)
+{
+       struct gs_port  *port = gser->ioport;
+       unsigned long   flags;
+
+       if (!port)
+               return;
+
+       /* tell the TTY glue not to do I/O here any more */
+       spin_lock_irqsave(&port->port_lock, flags);
+
+       /* REVISIT as above: how best to track this? */
+       port->port_line_coding = gser->port_line_coding;
+
+       port->port_usb = NULL;
+       gser->ioport = NULL;
+       if (port->port.count > 0 || port->openclose) {
+               wake_up_interruptible(&port->drain_wait);
+               if (port->port.tty)
+                       tty_hangup(port->port.tty);
+       }
+       spin_unlock_irqrestore(&port->port_lock, flags);
+
+       /* disable endpoints, aborting down any active I/O */
+       usb_ep_disable(gser->out);
+       gser->out->driver_data = NULL;
+
+       usb_ep_disable(gser->in);
+       gser->in->driver_data = NULL;
+
+       /* finally, free any unused/unusable I/O buffers */
+       spin_lock_irqsave(&port->port_lock, flags);
+       if (port->port.count == 0 && !port->openclose)
+               gs_buf_free(&port->port_write_buf);
+       gs_free_requests(gser->out, &port->read_pool, NULL);
+       gs_free_requests(gser->out, &port->read_queue, NULL);
+       gs_free_requests(gser->in, &port->write_pool, NULL);
+
+       port->read_allocated = port->read_started =
+               port->write_allocated = port->write_started = 0;
+
+       spin_unlock_irqrestore(&port->port_lock, flags);
+}
diff --git a/drivers/staging/ccg/u_serial.h b/drivers/staging/ccg/u_serial.h
new file mode 100644 (file)
index 0000000..9b0fe64
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * u_serial.h - interface to USB gadget "serial port"/TTY utilities
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is 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.
+ */
+
+#ifndef __U_SERIAL_H
+#define __U_SERIAL_H
+
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+
+/*
+ * One non-multiplexed "serial" I/O port ... there can be several of these
+ * on any given USB peripheral device, if it provides enough endpoints.
+ *
+ * The "u_serial" utility component exists to do one thing:  manage TTY
+ * style I/O using the USB peripheral endpoints listed here, including
+ * hookups to sysfs and /dev for each logical "tty" device.
+ *
+ * REVISIT at least ACM could support tiocmget() if needed.
+ *
+ * REVISIT someday, allow multiplexing several TTYs over these endpoints.
+ */
+struct gserial {
+       struct usb_function             func;
+
+       /* port is managed by gserial_{connect,disconnect} */
+       struct gs_port                  *ioport;
+
+       struct usb_ep                   *in;
+       struct usb_ep                   *out;
+
+       /* REVISIT avoid this CDC-ACM support harder ... */
+       struct usb_cdc_line_coding port_line_coding;    /* 9600-8-N-1 etc */
+
+       /* notification callbacks */
+       void (*connect)(struct gserial *p);
+       void (*disconnect)(struct gserial *p);
+       int (*send_break)(struct gserial *p, int duration);
+};
+
+/* utilities to allocate/free request and buffer */
+struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
+void gs_free_req(struct usb_ep *, struct usb_request *req);
+
+/* port setup/teardown is handled by gadget driver */
+int gserial_setup(struct usb_gadget *g, unsigned n_ports);
+void gserial_cleanup(void);
+
+/* connect/disconnect is handled by individual functions */
+int gserial_connect(struct gserial *, u8 port_num);
+void gserial_disconnect(struct gserial *);
+
+/* functions are bound to configurations by a config or gadget driver */
+int acm_bind_config(struct usb_configuration *c, u8 port_num);
+int gser_bind_config(struct usb_configuration *c, u8 port_num);
+int obex_bind_config(struct usb_configuration *c, u8 port_num);
+
+#endif /* __U_SERIAL_H */
diff --git a/drivers/staging/ccg/usbstring.c b/drivers/staging/ccg/usbstring.c
new file mode 100644 (file)
index 0000000..4d25b90
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/nls.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+
+/**
+ * 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, must be 16-bit aligned
+ *
+ * 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));
+       len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
+                       (wchar_t *) &buf[2], 126);
+       if (len < 0)
+               return -EINVAL;
+       buf [0] = (len + 1) * 2;
+       buf [1] = USB_DT_STRING;
+       return buf [0];
+}
+
index c0fdb00783edbf8583e1e0e0a7f5ab32dbf56dda..2359151af7e107925edd58bbd96203a15057ca31 100644 (file)
@@ -168,7 +168,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                        dev->board_ptr = comedi_recognize(driv, it->board_name);
                        if (dev->board_ptr)
                                break;
-               } else if (strcmp(driv->driver_name, it->board_name))
+               } else if (strcmp(driv->driver_name, it->board_name) == 0)
                        break;
                module_put(driv->module);
        }
index 31986608eaf1e932f25f77bcde3685ef66a891a2..6b4d0d68e6372ea1c4d51ac0ebc71e7b78522875 100644 (file)
@@ -1349,9 +1349,6 @@ static struct pci_dev *pci1710_find_pci_dev(struct comedi_device *dev,
                }
                if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
                        continue;
-               if (pci_is_enabled(pcidev))
-                       continue;
-
                if (strcmp(this_board->name, DRV_NAME) == 0) {
                        for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
                                if (pcidev->device == boardtypes[i].device_id) {
index da5ee69d2c9da856d2c46740288f72812ac41eef..dfde0f6328dd82b29403c54aba0b5a73d4f603e2 100644 (file)
@@ -301,8 +301,6 @@ static struct pci_dev *pci1723_find_pci_dev(struct comedi_device *dev,
                }
                if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
                        continue;
-               if (pci_is_enabled(pcidev))
-                       continue;
                return pcidev;
        }
        dev_err(dev->class_dev,
index 97f06dc8e48d002e00d053f068dccdad69310bbe..2d4cb7f638b2a0eeb6df6c371367ba3ac084b9a4 100644 (file)
@@ -1064,8 +1064,6 @@ static struct pci_dev *pci_dio_find_pci_dev(struct comedi_device *dev,
                            slot != PCI_SLOT(pcidev->devfn))
                                continue;
                }
-               if (pci_is_enabled(pcidev))
-                       continue;
                for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
                        if (boardtypes[i].vendor_id != pcidev->vendor)
                                continue;
index ef28385c14825808a88181ec2e3ad8cee7cbca10..cad559a1a730775c1d3d1589b995f6381ac28cb7 100644 (file)
@@ -718,7 +718,8 @@ static struct pci_dev *daqboard2000_find_pci_dev(struct comedi_device *dev,
                                continue;
                }
                if (pcidev->vendor != PCI_VENDOR_ID_IOTECH ||
-                   pcidev->device != 0x0409)
+                   pcidev->device != 0x0409 ||
+                   pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
                        continue;
 
                for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
@@ -739,6 +740,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
 {
        struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       resource_size_t pci_base;
        void *aux_data;
        unsigned int aux_len;
        int result;
@@ -758,11 +760,12 @@ static int daqboard2000_attach(struct comedi_device *dev,
                        "failed to enable PCI device and request regions\n");
                return -EIO;
        }
-       dev->iobase = pci_resource_start(pcidev, 2);
+       dev->iobase = 1;        /* the "detach" needs this */
 
-       devpriv->plx =
-           ioremap(pci_resource_start(pcidev, 0), DAQBOARD2000_PLX_SIZE);
-       devpriv->daq = ioremap(dev->iobase, DAQBOARD2000_DAQ_SIZE);
+       pci_base = pci_resource_start(pcidev, 0);
+       devpriv->plx = ioremap(pci_base, DAQBOARD2000_PLX_SIZE);
+       pci_base = pci_resource_start(pcidev, 2);
+       devpriv->daq = ioremap(pci_base, DAQBOARD2000_DAQ_SIZE);
        if (!devpriv->plx || !devpriv->daq)
                return -ENOMEM;
 
@@ -799,8 +802,6 @@ static int daqboard2000_attach(struct comedi_device *dev,
           printk("Interrupt after is: %x\n", interrupt);
         */
 
-       dev->iobase = (unsigned long)devpriv->daq;
-
        dev->board_name = this_board->name;
 
        s = dev->subdevices + 0;
@@ -824,7 +825,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
 
        s = dev->subdevices + 2;
        result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
-                                 (unsigned long)(dev->iobase + 0x40));
+                                 (unsigned long)(devpriv->daq + 0x40));
 
 out:
        return result;
index a6fe6c9be87eb1599e59f995245f0958095be5a5..3476cda0fff04e8e7df1f3f716f94a2406c799e5 100644 (file)
@@ -804,6 +804,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
        struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       resource_size_t pci_base;
        int ret = 0;
 
        dev_dbg(dev->class_dev, "dt3000:\n");
@@ -820,9 +821,10 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        ret = comedi_pci_enable(pcidev, "dt3000");
        if (ret < 0)
                return ret;
+       dev->iobase = 1;        /* the "detach" needs this */
 
-       dev->iobase = pci_resource_start(pcidev, 0);
-       devpriv->io_addr = ioremap(dev->iobase, DT3000_SIZE);
+       pci_base  = pci_resource_start(pcidev, 0);
+       devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
        if (!devpriv->io_addr)
                return -ENOMEM;
 
index 112fdc3e9c69dddcf64c322194b3d4a3d275b6bf..5aa8be1e7b9217cb6027d3652e134a3f17f1b300 100644 (file)
@@ -1619,9 +1619,8 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        struct rtdPrivate *devpriv;
        struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       resource_size_t pci_base;
        int ret;
-       resource_size_t physLas1;       /* data area */
-       resource_size_t physLcfg;       /* PLX9080 */
 #ifdef USE_DMA
        int index;
 #endif
@@ -1655,20 +1654,15 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
                return ret;
        }
-
-       /*
-        * Initialize base addresses
-        */
-       /* Get the physical address from PCI config */
-       dev->iobase = pci_resource_start(pcidev, LAS0_PCIINDEX);
-       physLas1 = pci_resource_start(pcidev, LAS1_PCIINDEX);
-       physLcfg = pci_resource_start(pcidev, LCFG_PCIINDEX);
-       /* Now have the kernel map this into memory */
-       /* ASSUME page aligned */
-       devpriv->las0 = ioremap_nocache(dev->iobase, LAS0_PCISIZE);
-       devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
-       devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
-
+       dev->iobase = 1;        /* the "detach" needs this */
+
+       /* Initialize the base addresses */
+       pci_base = pci_resource_start(pcidev, LAS0_PCIINDEX);
+       devpriv->las0 = ioremap_nocache(pci_base, LAS0_PCISIZE);
+       pci_base = pci_resource_start(pcidev, LAS1_PCIINDEX);
+       devpriv->las1 = ioremap_nocache(pci_base, LAS1_PCISIZE);
+       pci_base = pci_resource_start(pcidev, LCFG_PCIINDEX);
+       devpriv->lcfg = ioremap_nocache(pci_base, LCFG_PCISIZE);
        if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
                return -ENOMEM;
 
index 848c7ec06976dfdebb68fdea580e6fc1333ede33..11ee83681da7744fc7efdf2cd62063ed0c514311 100644 (file)
@@ -102,6 +102,7 @@ sampling rate. If you sample two channels you get 4kHz and so on.
 #define BULK_TIMEOUT 1000
 
 /* constants for "firmware" upload and download */
+#define FIRMWARE "usbdux_firmware.bin"
 #define USBDUXSUB_FIRMWARE 0xA0
 #define VENDOR_DIR_IN  0xC0
 #define VENDOR_DIR_OUT 0x40
@@ -2791,7 +2792,7 @@ static int usbdux_usb_probe(struct usb_interface *uinterf,
 
        ret = request_firmware_nowait(THIS_MODULE,
                                      FW_ACTION_HOTPLUG,
-                                     "usbdux_firmware.bin",
+                                     FIRMWARE,
                                      &udev->dev,
                                      GFP_KERNEL,
                                      usbduxsub + index,
@@ -2850,3 +2851,4 @@ module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE);
index d9911588c10a9f2ecad8cd528a795270071e54f1..8eb41257c6ceca4dd9be11e997f95853dafdcdf2 100644 (file)
@@ -57,6 +57,7 @@
 /*
  * constants for "firmware" upload and download
  */
+#define FIRMWARE               "usbduxfast_firmware.bin"
 #define USBDUXFASTSUB_FIRMWARE 0xA0
 #define VENDOR_DIR_IN          0xC0
 #define VENDOR_DIR_OUT         0x40
@@ -1706,7 +1707,7 @@ static int usbduxfast_usb_probe(struct usb_interface *uinterf,
 
        ret = request_firmware_nowait(THIS_MODULE,
                                      FW_ACTION_HOTPLUG,
-                                     "usbduxfast_firmware.bin",
+                                     FIRMWARE,
                                      &udev->dev,
                                      GFP_KERNEL,
                                      usbduxfastsub + index,
@@ -1774,3 +1775,4 @@ module_comedi_usb_driver(usbduxfast_driver, usbduxfast_usb_driver);
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("USB-DUXfast, BerndPorr@f2s.com");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE);
index 543e604791e2719c16378a05ef8ad31a9ce7208b..f54ab8c2fcfd3604935fac8dd76f18b0f19bd034 100644 (file)
@@ -63,6 +63,7 @@ Status: testing
 #define BULK_TIMEOUT 1000
 
 /* constants for "firmware" upload and download */
+#define FIRMWARE "usbduxsigma_firmware.bin"
 #define USBDUXSUB_FIRMWARE 0xA0
 #define VENDOR_DIR_IN  0xC0
 #define VENDOR_DIR_OUT 0x40
@@ -2780,7 +2781,7 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf,
 
        ret = request_firmware_nowait(THIS_MODULE,
                                      FW_ACTION_HOTPLUG,
-                                     "usbduxsigma_firmware.bin",
+                                     FIRMWARE,
                                      &udev->dev,
                                      GFP_KERNEL,
                                      usbduxsub + index,
@@ -2845,3 +2846,4 @@ module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver);
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE);
index cee8d48d2af91337006f8b852deddf8614d1adaa..ad2a1096e920c4008a7314f10691aadf4fddfcd9 100644 (file)
@@ -1,6 +1,6 @@
 config CSR_WIFI
        tristate "CSR wireless driver"
-       depends on MMC && CFG80211_WEXT
+       depends on MMC && CFG80211_WEXT && INET
        select WIRELESS_EXT
        select WEXT_PRIV
        help
index 22c3923d55eb34fc31c1313a570498d31dcb95a1..095837285f4fb25732b8986f3d6d25458a9a11a2 100644 (file)
@@ -754,7 +754,7 @@ static ssize_t ad7192_set(struct device *dev,
                else
                        st->mode &= ~AD7192_MODE_ACX;
 
-               ad7192_write_reg(st, AD7192_REG_GPOCON, 3, st->mode);
+               ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode);
                break;
        default:
                ret = -EINVAL;
@@ -798,6 +798,11 @@ static const struct attribute_group ad7195_attribute_group = {
        .attrs = ad7195_attributes,
 };
 
+static unsigned int ad7192_get_temp_scale(bool unipolar)
+{
+       return unipolar ? 2815 * 2 : 2815;
+}
+
 static int ad7192_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val,
@@ -824,19 +829,6 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
                *val = (smpl >> chan->scan_type.shift) &
                        ((1 << (chan->scan_type.realbits)) - 1);
 
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       if (!unipolar)
-                               *val -= (1 << (chan->scan_type.realbits - 1));
-                       break;
-               case IIO_TEMP:
-                       *val -= 0x800000;
-                       *val /= 2815; /* temp Kelvin */
-                       *val -= 273; /* temp Celsius */
-                       break;
-               default:
-                       return -EINVAL;
-               }
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
@@ -848,11 +840,21 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
                        mutex_unlock(&indio_dev->mlock);
                        return IIO_VAL_INT_PLUS_NANO;
                case IIO_TEMP:
-                       *val =  1000;
-                       return IIO_VAL_INT;
+                       *val = 0;
+                       *val2 = 1000000000 / ad7192_get_temp_scale(unipolar);
+                       return IIO_VAL_INT_PLUS_NANO;
                default:
                        return -EINVAL;
                }
+       case IIO_CHAN_INFO_OFFSET:
+               if (!unipolar)
+                       *val = -(1 << (chan->scan_type.realbits - 1));
+               else
+                       *val = 0;
+               /* Kelvin to Celsius */
+               if (chan->type == IIO_TEMP)
+                       *val -= 273 * ad7192_get_temp_scale(unipolar);
+               return IIO_VAL_INT;
        }
 
        return -EINVAL;
@@ -890,7 +892,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
                                }
                                ret = 0;
                        }
-
+               break;
        default:
                ret = -EINVAL;
        }
@@ -942,20 +944,22 @@ static const struct iio_info ad7195_info = {
          .channel = _chan,                                             \
          .channel2 = _chan2,                                           \
          .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |                 \
-         IIO_CHAN_INFO_SCALE_SHARED_BIT,                               \
+         IIO_CHAN_INFO_SCALE_SHARED_BIT |                              \
+         IIO_CHAN_INFO_OFFSET_SHARED_BIT,                              \
          .address = _address,                                          \
          .scan_index = _si,                                            \
-         .scan_type =  IIO_ST('s', 24, 32, 0)}
+         .scan_type =  IIO_ST('u', 24, 32, 0)}
 
 #define AD7192_CHAN(_chan, _address, _si)                              \
        { .type = IIO_VOLTAGE,                                          \
          .indexed = 1,                                                 \
          .channel = _chan,                                             \
          .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |                 \
-         IIO_CHAN_INFO_SCALE_SHARED_BIT,                               \
+         IIO_CHAN_INFO_SCALE_SHARED_BIT |                              \
+         IIO_CHAN_INFO_OFFSET_SHARED_BIT,                              \
          .address = _address,                                          \
          .scan_index = _si,                                            \
-         .scan_type =  IIO_ST('s', 24, 32, 0)}
+         .scan_type =  IIO_ST('u', 24, 32, 0)}
 
 #define AD7192_CHAN_TEMP(_chan, _address, _si)                         \
        { .type = IIO_TEMP,                                             \
@@ -965,7 +969,7 @@ static const struct iio_info ad7195_info = {
          IIO_CHAN_INFO_SCALE_SEPARATE_BIT,                             \
          .address = _address,                                          \
          .scan_index = _si,                                            \
-         .scan_type =  IIO_ST('s', 24, 32, 0)}
+         .scan_type =  IIO_ST('u', 24, 32, 0)}
 
 static struct iio_chan_spec ad7192_channels[] = {
        AD7192_CHAN_DIFF(1, 2, NULL, AD7192_CH_AIN1P_AIN2M, 0),
index fd1d855ff57a1c5e2b3786afbc67f5303767a76e..506016f01593c6bdd7a68279f19fa1363b2d21f8 100644 (file)
@@ -76,7 +76,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
        struct iio_dev *indio_dev = pf->indio_dev;
        struct ad7298_state *st = iio_priv(indio_dev);
        struct iio_buffer *ring = indio_dev->buffer;
-       s64 time_ns;
+       s64 time_ns = 0;
        __u16 buf[16];
        int b_sent, i;
 
index 1ece2ac8de56965ea0af82c378244da50bdfdece..19ee49c95de49725e4dfdb62c0e4805a9215cce4 100644 (file)
@@ -131,9 +131,10 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
                        .indexed = 1,
                        .channel = 0,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_type = {
-                               .sign = 's',
+                               .sign = 'u',
                                .realbits = 24,
                                .storagebits = 32,
                                .shift = 8,
@@ -146,9 +147,10 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
                        .indexed = 1,
                        .channel = 0,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_type = {
-                               .sign = 's',
+                               .sign = 'u',
                                .realbits = 20,
                                .storagebits = 32,
                                .shift = 12,
index 76fdd7145fc5d855544c977560dfc3803baa7b95..112e2b7b5bc4a5b1c459081ec23f624b3eed5f9f 100644 (file)
@@ -563,8 +563,9 @@ static ssize_t ad7793_show_scale_available(struct device *dev,
        return len;
 }
 
-static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, in-in_scale_available,
-                            S_IRUGO, ad7793_show_scale_available, NULL, 0);
+static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available,
+               in_voltage-voltage_scale_available, S_IRUGO,
+               ad7793_show_scale_available, NULL, 0);
 
 static struct attribute *ad7793_attributes[] = {
        &iio_dev_attr_sampling_frequency.dev_attr.attr,
@@ -604,9 +605,6 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
                *val = (smpl >> chan->scan_type.shift) &
                        ((1 << (chan->scan_type.realbits)) - 1);
 
-               if (!unipolar)
-                       *val -= (1 << (chan->scan_type.realbits - 1));
-
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
@@ -620,25 +618,38 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
                                return IIO_VAL_INT_PLUS_NANO;
                        } else {
                                /* 1170mV / 2^23 * 6 */
-                               scale_uv = (1170ULL * 100000000ULL * 6ULL)
-                                       >> (chan->scan_type.realbits -
-                                           (unipolar ? 0 : 1));
+                               scale_uv = (1170ULL * 100000000ULL * 6ULL);
                        }
                        break;
                case IIO_TEMP:
-                       /* Always uses unity gain and internal ref */
-                       scale_uv = (2500ULL * 100000000ULL)
-                               >> (chan->scan_type.realbits -
-                               (unipolar ? 0 : 1));
+                               /* 1170mV / 0.81 mV/C / 2^23 */
+                               scale_uv = 1444444444444ULL;
                        break;
                default:
                        return -EINVAL;
                }
 
-               *val2 = do_div(scale_uv, 100000000) * 10;
-               *val =  scale_uv;
-
+               scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1));
+               *val = 0;
+               *val2 = scale_uv;
                return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_OFFSET:
+               if (!unipolar)
+                       *val = -(1 << (chan->scan_type.realbits - 1));
+               else
+                       *val = 0;
+
+               /* Kelvin to Celsius */
+               if (chan->type == IIO_TEMP) {
+                       unsigned long long offset;
+                       unsigned int shift;
+
+                       shift = chan->scan_type.realbits - (unipolar ? 0 : 1);
+                       offset = 273ULL << shift;
+                       do_div(offset, 1444);
+                       *val -= offset;
+               }
+               return IIO_VAL_INT;
        }
        return -EINVAL;
 }
@@ -676,7 +687,7 @@ static int ad7793_write_raw(struct iio_dev *indio_dev,
                                }
                                ret = 0;
                        }
-
+               break;
        default:
                ret = -EINVAL;
        }
@@ -720,9 +731,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 0,
                        .address = AD7793_CH_AIN1P_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 0,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[1] = {
                        .type = IIO_VOLTAGE,
@@ -732,9 +744,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 1,
                        .address = AD7793_CH_AIN2P_AIN2M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 1,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[2] = {
                        .type = IIO_VOLTAGE,
@@ -744,9 +757,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN3P_AIN3M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 2,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[3] = {
                        .type = IIO_VOLTAGE,
@@ -757,9 +771,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN1M_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 3,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[4] = {
                        .type = IIO_TEMP,
@@ -769,7 +784,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
                        IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
                        .scan_index = 4,
-                       .scan_type = IIO_ST('s', 24, 32, 0),
+                       .scan_type = IIO_ST('u', 24, 32, 0),
                },
                .channel[5] = {
                        .type = IIO_VOLTAGE,
@@ -778,9 +793,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel = 4,
                        .address = AD7793_CH_AVDD_MONITOR,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 5,
-                       .scan_type = IIO_ST('s', 24, 32, 0),
+                       .scan_type = IIO_ST('u', 24, 32, 0),
                },
                .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6),
        },
@@ -793,9 +809,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 0,
                        .address = AD7793_CH_AIN1P_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 0,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[1] = {
                        .type = IIO_VOLTAGE,
@@ -805,9 +822,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 1,
                        .address = AD7793_CH_AIN2P_AIN2M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 1,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[2] = {
                        .type = IIO_VOLTAGE,
@@ -817,9 +835,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN3P_AIN3M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 2,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[3] = {
                        .type = IIO_VOLTAGE,
@@ -830,9 +849,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN1M_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 3,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[4] = {
                        .type = IIO_TEMP,
@@ -842,7 +862,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
                        IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
                        .scan_index = 4,
-                       .scan_type = IIO_ST('s', 16, 32, 0),
+                       .scan_type = IIO_ST('u', 16, 32, 0),
                },
                .channel[5] = {
                        .type = IIO_VOLTAGE,
@@ -851,9 +871,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel = 4,
                        .address = AD7793_CH_AVDD_MONITOR,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 5,
-                       .scan_type = IIO_ST('s', 16, 32, 0),
+                       .scan_type = IIO_ST('u', 16, 32, 0),
                },
                .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6),
        },
@@ -901,7 +922,7 @@ static int __devinit ad7793_probe(struct spi_device *spi)
        else if (voltage_uv)
                st->int_vref_mv = voltage_uv / 1000;
        else
-               st->int_vref_mv = 2500; /* Build-in ref */
+               st->int_vref_mv = 1170; /* Build-in ref */
 
        spi_set_drvdata(spi, indio_dev);
        st->spi = spi;
index 4833034027351cdadafbe2ee3ee954c8d7e6b914..55a0b82c6391b7eb92c67c98d3f9474b7e6b225e 100644 (file)
@@ -320,7 +320,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
 
        us->subclass = idesc->bInterfaceSubClass;
        us->protocol = idesc->bInterfaceProtocol;
-       us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
+       us->fflags = id->driver_info;
        us->Power_IsResum = false;
 
        if (us->fflags & US_FL_IGNORE_DEVICE)
index 70f23026932965fd997528ef48ad62d626f4c9a6..95beb76497d66b816c8e5d5da33f6ae5fc5f41b1 100644 (file)
@@ -157,8 +157,7 @@ static void usbip_dump_usb_device(struct usb_device *udev)
        dev_dbg(dev, "have_langid %d, string_langid %d\n",
                udev->have_langid, udev->string_langid);
 
-       dev_dbg(dev, "maxchild %d, children %p\n",
-               udev->maxchild, udev->children);
+       dev_dbg(dev, "maxchild %d\n", udev->maxchild);
 }
 
 static void usbip_dump_request_type(__u8 rt)
index b06fd5b723fa5cb693fd860c43e9232395c57bad..d536756549e684479ac067e5b2caea8832245e9e 100644 (file)
@@ -189,7 +189,7 @@ DEVICE_PARAM(b80211hEnable, "802.11h mode");
 // Static vars definitions
 //
 
-static struct usb_device_id vt6656_table[] __devinitdata = {
+static struct usb_device_id vt6656_table[] = {
        {USB_DEVICE(VNT_USB_VENDOR_ID, VNT_USB_PRODUCT_ID)},
        {}
 };
index ef360547ececf262841ad46068028fb7fd40f4d2..0ca857ac473e91e3171c0963f85a4be214b64947 100644 (file)
@@ -25,7 +25,7 @@ MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION("0.1");
 
-static const struct usb_device_id wb35_table[] __devinitconst = {
+static const struct usb_device_id wb35_table[] = {
        { USB_DEVICE(0x0416, 0x0035) },
        { USB_DEVICE(0x18E8, 0x6201) },
        { USB_DEVICE(0x18E8, 0x6206) },
index 6e32ff6f2fa0ce4ead43073d87bedc77d3ffee2c..5552fa7426bc9b317da906dec2e395bbf854ae78 100644 (file)
@@ -673,8 +673,15 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
        struct scsi_device *sd = pdv->pdv_sd;
        int result;
        struct pscsi_plugin_task *pt = cmd->priv;
-       unsigned char *cdb = &pt->pscsi_cdb[0];
+       unsigned char *cdb;
+       /*
+        * Special case for REPORT_LUNs handling where pscsi_plugin_task has
+        * not been allocated because TCM is handling the emulation directly.
+        */
+       if (!pt)
+               return 0;
 
+       cdb = &pt->pscsi_cdb[0];
        result = pt->pscsi_result;
        /*
         * Hack to make sure that Write-Protect modepage is set if R/O mode is
index 0eaae23d12b576547fa51f25ed8f05579f6ec646..4de3186dc44e99672d3666a24ec145e058183691 100644 (file)
@@ -1165,8 +1165,6 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
                        " 0x%02x\n", cmd->se_tfo->get_fabric_name(),
                                cmd->data_length, size, cmd->t_task_cdb[0]);
 
-               cmd->cmd_spdtl = size;
-
                if (cmd->data_direction == DMA_TO_DEVICE) {
                        pr_err("Rejecting underflow/overflow"
                                        " WRITE data\n");
@@ -2294,9 +2292,9 @@ transport_generic_get_mem(struct se_cmd *cmd)
        return 0;
 
 out:
-       while (i >= 0) {
-               __free_page(sg_page(&cmd->t_data_sg[i]));
+       while (i > 0) {
                i--;
+               __free_page(sg_page(&cmd->t_data_sg[i]));
        }
        kfree(cmd->t_data_sg);
        cmd->t_data_sg = NULL;
@@ -2323,9 +2321,12 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
                if (ret < 0)
                        goto out_fail;
        }
-
-       /* Workaround for handling zero-length control CDBs */
-       if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->data_length) {
+       /*
+        * If this command doesn't have any payload and we don't have to call
+        * into the fabric for data transfers, go ahead and complete it right
+        * away.
+        */
+       if (!cmd->data_length) {
                spin_lock_irq(&cmd->t_state_lock);
                cmd->t_state = TRANSPORT_COMPLETE;
                cmd->transport_state |= CMD_T_ACTIVE;
index c5eb3c33c3dbed83db4b647c07619e44f320659f..eea69358ced3a5c8eec138eb403b2347905c801e 100644 (file)
@@ -131,6 +131,7 @@ extern struct list_head ft_lport_list;
 extern struct mutex ft_lport_lock;
 extern struct fc4_prov ft_prov;
 extern struct target_fabric_configfs *ft_configfs;
+extern unsigned int ft_debug_logging;
 
 /*
  * Fabric methods.
index b9cb5006177e22166732032468bf8d0a733299f8..823e6922249d07e3122973ebdb370cd4994704a0 100644 (file)
@@ -48,7 +48,7 @@
 /*
  * Dump cmd state for debugging.
  */
-void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
+static void _ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
 {
        struct fc_exch *ep;
        struct fc_seq *sp;
@@ -80,6 +80,12 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
        }
 }
 
+void ft_dump_cmd(struct ft_cmd *cmd, const char *caller)
+{
+       if (unlikely(ft_debug_logging))
+               _ft_dump_cmd(cmd, caller);
+}
+
 static void ft_free_cmd(struct ft_cmd *cmd)
 {
        struct fc_frame *fp;
index 87901fa74dd7e1acb136cbdf0607aa4b8eeeb652..3c9e5b57caabea23567192e2d2f85843ca6bc70f 100644 (file)
@@ -456,7 +456,9 @@ static void ft_prlo(struct fc_rport_priv *rdata)
        struct ft_tport *tport;
 
        mutex_lock(&ft_lport_lock);
-       tport = rcu_dereference(rdata->local_port->prov[FC_TYPE_FCP]);
+       tport = rcu_dereference_protected(rdata->local_port->prov[FC_TYPE_FCP],
+                                         lockdep_is_held(&ft_lport_lock));
+
        if (!tport) {
                mutex_unlock(&ft_lport_lock);
                return;
index 070b442c1f81abb08ffee6cd69e3ffe0ab87b209..4720b4ba096a5d7b2efc6cca8aca82dd75c127e2 100644 (file)
@@ -160,10 +160,12 @@ config SERIAL_KS8695_CONSOLE
 
 config SERIAL_CLPS711X
        tristate "CLPS711X serial port support"
-       depends on ARM && ARCH_CLPS711X
+       depends on ARCH_CLPS711X
        select SERIAL_CORE
+       default y
        help
-         ::: To be written :::
+         This enables the driver for the on-chip UARTs of the Cirrus
+         Logic EP711x/EP721x/EP731x processors.
 
 config SERIAL_CLPS711X_CONSOLE
        bool "Support for console on CLPS711X serial port"
@@ -173,9 +175,7 @@ config SERIAL_CLPS711X_CONSOLE
          Even if you say Y here, the currently visible virtual console
          (/dev/tty0) will still be used as the system console by default, but
          you can alter that using a kernel command line option such as
-         "console=ttyCL1". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
+         "console=ttyCL1".
 
 config SERIAL_SAMSUNG
        tristate "Samsung SoC serial support"
index 144cd3987d4cb5c6c108d0488a41a0e1ba8eca73..3ad079ffd049cbce0441d730e28f27bbfe4aeb4b 100644 (file)
@@ -1331,7 +1331,7 @@ static const struct spi_device_id ifx_id_table[] = {
 MODULE_DEVICE_TABLE(spi, ifx_id_table);
 
 /* spi operations */
-static const struct spi_driver ifx_spi_driver = {
+static struct spi_driver ifx_spi_driver = {
        .driver = {
                .name = DRVNAME,
                .pm = &ifx_spi_pm,
index 2e341b81ff891b632e5cbee6d2337aba0f10cfe8..3a667eed63d6086c017c8abcc83a597850ec4966 100644 (file)
@@ -73,6 +73,7 @@
 #define AUART_CTRL0_CLKGATE                    (1 << 30)
 
 #define AUART_CTRL2_CTSEN                      (1 << 15)
+#define AUART_CTRL2_RTSEN                      (1 << 14)
 #define AUART_CTRL2_RTS                                (1 << 11)
 #define AUART_CTRL2_RXE                                (1 << 9)
 #define AUART_CTRL2_TXE                                (1 << 8)
@@ -259,9 +260,12 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
 
        u32 ctrl = readl(u->membase + AUART_CTRL2);
 
-       ctrl &= ~AUART_CTRL2_RTS;
-       if (mctrl & TIOCM_RTS)
-               ctrl |= AUART_CTRL2_RTS;
+       ctrl &= ~AUART_CTRL2_RTSEN;
+       if (mctrl & TIOCM_RTS) {
+               if (u->state->port.flags & ASYNC_CTS_FLOW)
+                       ctrl |= AUART_CTRL2_RTSEN;
+       }
+
        s->ctrl = mctrl;
        writel(ctrl, u->membase + AUART_CTRL2);
 }
@@ -359,9 +363,9 @@ static void mxs_auart_settermios(struct uart_port *u,
 
        /* figure out the hardware flow control settings */
        if (cflag & CRTSCTS)
-               ctrl2 |= AUART_CTRL2_CTSEN;
+               ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN;
        else
-               ctrl2 &= ~AUART_CTRL2_CTSEN;
+               ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
 
        /* set baud rate */
        baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
index 654755a990dfc30cac559567e260b17978bbc54b..333c8d012b0e32c9e40881fd1defff6cc52b8b10 100644 (file)
@@ -1348,10 +1348,16 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
 static int pmz_poll_get_char(struct uart_port *port)
 {
        struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+       int tries = 2;
 
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
-               udelay(5);
-       return read_zsdata(uap);
+       while (tries) {
+               if ((read_zsreg(uap, R0) & Rx_CH_AV) != 0)
+                       return read_zsdata(uap);
+               if (tries--)
+                       udelay(5);
+       }
+
+       return NO_POLL_CHAR;
 }
 
 static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
index a7773a3e02b11cedabb884a74b11ef366a4e342e..2564b546ba8ac2b7cd4436e76aecc44e72e6d502 100644 (file)
@@ -13,7 +13,7 @@ config USB_ARCH_HAS_OHCI
        default y if PXA3xx
        default y if ARCH_EP93XX
        default y if ARCH_AT91
-       default y if ARCH_PNX4008 && I2C
+       default y if ARCH_PNX4008
        default y if MFD_TC6393XB
        default y if ARCH_W90X900
        default y if ARCH_DAVINCI_DA8XX
@@ -48,6 +48,7 @@ config USB_ARCH_HAS_EHCI
        default y if SPARC_LEON
        default y if ARCH_MMP
        default y if MACH_LOONGSON1
+       default y if PLAT_ORION
        default PCI
 
 # some non-PCI HCDs implement xHCI
index d7e422dc0ef7d567ea391c13b901d0b222a8e2fc..e1f8b2c973fe1e7df698e918328fd5bc421906e6 100644 (file)
@@ -307,6 +307,34 @@ enum {
 #define FW_GET_BYTE(p) (*((__u8 *) (p)))
 
 #define FW_DIR "ueagle-atm/"
+#define EAGLE_FIRMWARE FW_DIR "eagle.fw"
+#define ADI930_FIRMWARE FW_DIR "adi930.fw"
+#define EAGLE_I_FIRMWARE FW_DIR "eagleI.fw"
+#define EAGLE_II_FIRMWARE FW_DIR "eagleII.fw"
+#define EAGLE_III_FIRMWARE FW_DIR "eagleIII.fw"
+#define EAGLE_IV_FIRMWARE FW_DIR "eagleIV.fw"
+
+#define DSP4I_FIRMWARE FW_DIR "DSP4i.bin"
+#define DSP4P_FIRMWARE FW_DIR "DSP4p.bin"
+#define DSP9I_FIRMWARE FW_DIR "DSP9i.bin"
+#define DSP9P_FIRMWARE FW_DIR "DSP9p.bin"
+#define DSPEI_FIRMWARE FW_DIR "DSPei.bin"
+#define DSPEP_FIRMWARE FW_DIR "DSPep.bin"
+#define FPGA930_FIRMWARE FW_DIR "930-fpga.bin"
+
+#define CMV4P_FIRMWARE FW_DIR "CMV4p.bin"
+#define CMV4PV2_FIRMWARE FW_DIR "CMV4p.bin.v2"
+#define CMV4I_FIRMWARE FW_DIR "CMV4i.bin"
+#define CMV4IV2_FIRMWARE FW_DIR "CMV4i.bin.v2"
+#define CMV9P_FIRMWARE FW_DIR "CMV9p.bin"
+#define CMV9PV2_FIRMWARE FW_DIR "CMV9p.bin.v2"
+#define CMV9I_FIRMWARE FW_DIR "CMV9i.bin"
+#define CMV9IV2_FIRMWARE FW_DIR "CMV9i.bin.v2"
+#define CMVEP_FIRMWARE FW_DIR "CMVep.bin"
+#define CMVEPV2_FIRMWARE FW_DIR "CMVep.bin.v2"
+#define CMVEI_FIRMWARE FW_DIR "CMVei.bin"
+#define CMVEIV2_FIRMWARE FW_DIR "CMVei.bin.v2"
+
 #define UEA_FW_NAME_MAX 30
 #define NB_MODEM 4
 
@@ -694,26 +722,26 @@ err:
 static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
 {
        int ret;
-       char *fw_name = FW_DIR "eagle.fw";
+       char *fw_name = EAGLE_FIRMWARE;
 
        uea_enters(usb);
        uea_info(usb, "pre-firmware device, uploading firmware\n");
 
        switch (ver) {
        case ADI930:
-               fw_name = FW_DIR "adi930.fw";
+               fw_name = ADI930_FIRMWARE;
                break;
        case EAGLE_I:
-               fw_name = FW_DIR "eagleI.fw";
+               fw_name = EAGLE_I_FIRMWARE;
                break;
        case EAGLE_II:
-               fw_name = FW_DIR "eagleII.fw";
+               fw_name = EAGLE_II_FIRMWARE;
                break;
        case EAGLE_III:
-               fw_name = FW_DIR "eagleIII.fw";
+               fw_name = EAGLE_III_FIRMWARE;
                break;
        case EAGLE_IV:
-               fw_name = FW_DIR "eagleIV.fw";
+               fw_name = EAGLE_IV_FIRMWARE;
                break;
        }
 
@@ -869,19 +897,19 @@ static int request_dsp(struct uea_softc *sc)
 
        if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
                if (IS_ISDN(sc))
-                       dsp_name = FW_DIR "DSP4i.bin";
+                       dsp_name = DSP4I_FIRMWARE;
                else
-                       dsp_name = FW_DIR "DSP4p.bin";
+                       dsp_name = DSP4P_FIRMWARE;
        } else if (UEA_CHIP_VERSION(sc) == ADI930) {
                if (IS_ISDN(sc))
-                       dsp_name = FW_DIR "DSP9i.bin";
+                       dsp_name = DSP9I_FIRMWARE;
                else
-                       dsp_name = FW_DIR "DSP9p.bin";
+                       dsp_name = DSP9P_FIRMWARE;
        } else {
                if (IS_ISDN(sc))
-                       dsp_name = FW_DIR "DSPei.bin";
+                       dsp_name = DSPEI_FIRMWARE;
                else
-                       dsp_name = FW_DIR "DSPep.bin";
+                       dsp_name = DSPEP_FIRMWARE;
        }
 
        ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev);
@@ -1925,7 +1953,7 @@ static int load_XILINX_firmware(struct uea_softc *sc)
        int ret, size, u, ln;
        const u8 *pfw;
        u8 value;
-       char *fw_name = FW_DIR "930-fpga.bin";
+       char *fw_name = FPGA930_FIRMWARE;
 
        uea_enters(INS_TO_USBDEV(sc));
 
@@ -2753,3 +2781,28 @@ module_usb_driver(uea_driver);
 MODULE_AUTHOR("Damien Bergamini/Matthieu Castet/Stanislaw W. Gruszka");
 MODULE_DESCRIPTION("ADI 930/Eagle USB ADSL Modem driver");
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_FIRMWARE(EAGLE_FIRMWARE);
+MODULE_FIRMWARE(ADI930_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_I_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_II_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_III_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_IV_FIRMWARE);
+MODULE_FIRMWARE(DSP4I_FIRMWARE);
+MODULE_FIRMWARE(DSP4P_FIRMWARE);
+MODULE_FIRMWARE(DSP9I_FIRMWARE);
+MODULE_FIRMWARE(DSP9P_FIRMWARE);
+MODULE_FIRMWARE(DSPEI_FIRMWARE);
+MODULE_FIRMWARE(DSPEP_FIRMWARE);
+MODULE_FIRMWARE(FPGA930_FIRMWARE);
+MODULE_FIRMWARE(CMV4P_FIRMWARE);
+MODULE_FIRMWARE(CMV4PV2_FIRMWARE);
+MODULE_FIRMWARE(CMV4I_FIRMWARE);
+MODULE_FIRMWARE(CMV4IV2_FIRMWARE);
+MODULE_FIRMWARE(CMV9P_FIRMWARE);
+MODULE_FIRMWARE(CMV9PV2_FIRMWARE);
+MODULE_FIRMWARE(CMV9I_FIRMWARE);
+MODULE_FIRMWARE(CMV9IV2_FIRMWARE);
+MODULE_FIRMWARE(CMVEP_FIRMWARE);
+MODULE_FIRMWARE(CMVEPV2_FIRMWARE);
+MODULE_FIRMWARE(CMVEI_FIRMWARE);
+MODULE_FIRMWARE(CMVEIV2_FIRMWARE);
index 8337fb5d988de6cc68c7e06aa44341d09cd67c62..1ea932a13685f32acddfd8231affb29add64d220 100644 (file)
@@ -1,9 +1,9 @@
 config USB_CHIPIDEA
        tristate "ChipIdea Highspeed Dual Role Controller"
-       depends on USB
+       depends on USB || USB_GADGET
        help
-          Say Y here if your system has a dual role high speed USB
-          controller based on ChipIdea silicon IP. Currently, only the
+         Say Y here if your system has a dual role high speed USB
+         controller based on ChipIdea silicon IP. Currently, only the
          peripheral mode is supported.
 
          When compiled dynamically, the module will be called ci-hdrc.ko.
@@ -12,14 +12,14 @@ if USB_CHIPIDEA
 
 config USB_CHIPIDEA_UDC
        bool "ChipIdea device controller"
-       depends on USB_GADGET
-       select USB_GADGET_DUALSPEED
+       depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA
        help
          Say Y here to enable device controller functionality of the
          ChipIdea driver.
 
 config USB_CHIPIDEA_HOST
        bool "ChipIdea host controller"
+       depends on USB=y || USB=USB_CHIPIDEA
        select USB_EHCI_ROOT_HUB_TT
        help
          Say Y here to enable host controller functionality of the
index 56d6bf66848894b76564ba452e00d6cf37f13416..344a51d3c291074374473c17ed78d4b9d004b61d 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/serial.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/serial.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
@@ -1104,7 +1103,8 @@ skip_normal_probe:
        }
 
 
-       if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
+       if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 ||
+           control_interface->cur_altsetting->desc.bNumEndpoints == 0)
                return -EINVAL;
 
        epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
index f4bdd0ce8d56cdfcf3dda323d6ee2c33ec86b445..7199adccf44488dc487641de2a085361bdaa0041 100644 (file)
@@ -702,6 +702,8 @@ int usb_get_configuration(struct usb_device *dev)
                if (result < 0) {
                        dev_err(ddev, "unable to read config index %d "
                            "descriptor/%s: %d\n", cfgno, "start", result);
+                       if (result != -EPIPE)
+                               goto err;
                        dev_err(ddev, "chopping to %d config(s)\n", cfgno);
                        dev->descriptor.bNumConfigurations = cfgno;
                        break;
index d9569658476274f34d8a51726da828d87bf44831..f4ead1296820c8e789903f428a5b1d1a28bbcc6d 100644 (file)
@@ -496,6 +496,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
        char *pages_start, *data_end, *speed;
        unsigned int length;
        ssize_t total_written = 0;
+       struct usb_device *childdev = NULL;
 
        /* don't bother with anything else if we're not writing any data */
        if (*nbytes <= 0)
@@ -589,14 +590,12 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
        free_pages((unsigned long)pages_start, 1);
 
        /* Now look at all of this device's children. */
-       for (chix = 0; chix < usbdev->maxchild; chix++) {
-               struct usb_device *childdev = usbdev->children[chix];
-
+       usb_hub_for_each_child(usbdev, chix, childdev) {
                if (childdev) {
                        usb_lock_device(childdev);
                        ret = usb_device_dump(buffer, nbytes, skip_bytes,
                                              file_offset, childdev, bus,
-                                             level + 1, chix, ++cnt);
+                                             level + 1, chix - 1, ++cnt);
                        usb_unlock_device(childdev);
                        if (ret == -EFAULT)
                                return total_written;
index ebb8a9de8b5fe448c98e0c25ec394e68c784d5b5..e0356cb859b5910eaaf5aa6e0b324808c56f4c0a 100644 (file)
@@ -1928,6 +1928,38 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
        return 0;
 }
 
+static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
+{
+       struct usbdevfs_disconnect_claim dc;
+       struct usb_interface *intf;
+
+       if (copy_from_user(&dc, arg, sizeof(dc)))
+               return -EFAULT;
+
+       intf = usb_ifnum_to_if(ps->dev, dc.interface);
+       if (!intf)
+               return -EINVAL;
+
+       if (intf->dev.driver) {
+               struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+
+               if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
+                               strncmp(dc.driver, intf->dev.driver->name,
+                                       sizeof(dc.driver)) != 0)
+                       return -EBUSY;
+
+               if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
+                               strncmp(dc.driver, intf->dev.driver->name,
+                                       sizeof(dc.driver)) == 0)
+                       return -EBUSY;
+
+               dev_dbg(&intf->dev, "disconnect by usbfs\n");
+               usb_driver_release_interface(driver, intf);
+       }
+
+       return claimintf(ps, dc.interface);
+}
+
 /*
  * NOTE:  All requests here that have interface numbers as parameters
  * are assuming that somehow the configuration has been prevented from
@@ -2101,6 +2133,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
        case USBDEVFS_GET_CAPABILITIES:
                ret = proc_get_capabilities(ps, p);
                break;
+       case USBDEVFS_DISCONNECT_CLAIM:
+               ret = proc_disconnect_claim(ps, p);
+               break;
        }
        usb_unlock_device(dev);
        if (ret >= 0)
index db7fe50c23d4df96a90faddf880507ccfdd55d26..68cc6532e7492ee4293708ab8db9cd6e257e5e51 100644 (file)
@@ -24,10 +24,6 @@ struct ep_device {
 #define to_ep_device(_dev) \
        container_of(_dev, struct ep_device, dev)
 
-struct device_type usb_ep_device_type = {
-       .name =         "usb_endpoint",
-};
-
 struct ep_attribute {
        struct attribute attr;
        ssize_t (*show)(struct usb_device *,
@@ -172,6 +168,11 @@ static void ep_device_release(struct device *dev)
        kfree(ep_dev);
 }
 
+struct device_type usb_ep_device_type = {
+       .name =         "usb_endpoint",
+       .release = ep_device_release,
+};
+
 int usb_create_ep_devs(struct device *parent,
                        struct usb_host_endpoint *endpoint,
                        struct usb_device *udev)
@@ -190,7 +191,6 @@ int usb_create_ep_devs(struct device *parent,
        ep_dev->dev.groups = ep_dev_groups;
        ep_dev->dev.type = &usb_ep_device_type;
        ep_dev->dev.parent = parent;
-       ep_dev->dev.release = ep_device_release;
        dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
 
        retval = device_register(&ep_dev->dev);
index bc84106ac057d7affb0e4d7c5c6ce22dcc2b7943..35b52f6e1c5e03cc9b580986f126f395082c2873 100644 (file)
@@ -22,6 +22,7 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/bcd.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -123,9 +124,8 @@ static inline int is_root_hub(struct usb_device *udev)
  */
 
 /*-------------------------------------------------------------------------*/
-
-#define KERNEL_REL     ((LINUX_VERSION_CODE >> 16) & 0x0ff)
-#define KERNEL_VER     ((LINUX_VERSION_CODE >> 8) & 0x0ff)
+#define KERNEL_REL     bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
+#define KERNEL_VER     bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
 
 /* usb 3.0 root hub device descriptor */
 static const u8 usb3_rh_dev_descriptor[18] = {
@@ -2153,15 +2153,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
        struct usb_hcd          *hcd = __hcd;
-       unsigned long           flags;
        irqreturn_t             rc;
 
-       /* IRQF_DISABLED doesn't work correctly with shared IRQs
-        * when the first handler doesn't use it.  So let's just
-        * assume it's never used.
-        */
-       local_irq_save(flags);
-
        if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
                rc = IRQ_NONE;
        else if (hcd->driver->irq(hcd) == IRQ_NONE)
@@ -2169,7 +2162,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
        else
                rc = IRQ_HANDLED;
 
-       local_irq_restore(flags);
        return rc;
 }
 EXPORT_SYMBOL_GPL(usb_hcd_irq);
@@ -2357,14 +2349,6 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
        int retval;
 
        if (hcd->driver->irq) {
-
-               /* IRQF_DISABLED doesn't work as advertised when used together
-                * with IRQF_SHARED. As usb_hcd_irq() will always disable
-                * interrupts we can remove it here.
-                */
-               if (irqflags & IRQF_SHARED)
-                       irqflags &= ~IRQF_DISABLED;
-
                snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
                                hcd->driver->description, hcd->self.busnum);
                retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
index 128a804c42f406b6c6b1f32f57110ff6b0810b41..aa45e43e0ca9bc97e403dfced247b739ea396c41 100644 (file)
 #endif
 #endif
 
+enum port_power_policy {
+       USB_PORT_POWER_ON = 0,
+       USB_PORT_POWER_OFF,
+};
+
+struct usb_port {
+       struct usb_device *child;
+       struct device dev;
+       struct dev_state *port_owner;
+       enum usb_port_connect_type connect_type;
+       enum port_power_policy port_power_policy;
+};
+
 struct usb_hub {
        struct device           *intfdev;       /* the "interface" device */
        struct usb_device       *hdev;
@@ -83,9 +96,13 @@ struct usb_hub {
        u8                      indicator[USB_MAXCHILDREN];
        struct delayed_work     leds;
        struct delayed_work     init_work;
-       struct dev_state        **port_owners;
+       struct usb_port         **ports;
 };
 
+static const char on_string[] = "on";
+static const char off_string[] = "off";
+static const struct attribute_group *port_dev_group[];
+
 static inline int hub_is_superspeed(struct usb_device *hdev)
 {
        return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
@@ -156,6 +173,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
 #define HUB_DEBOUNCE_STEP        25
 #define HUB_DEBOUNCE_STABLE     100
 
+#define to_usb_port(_dev) \
+       container_of(_dev, struct usb_port, dev)
 
 static int usb_reset_and_verify_device(struct usb_device *udev);
 
@@ -174,7 +193,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)
 /* Note that hdev or one of its children must be locked! */
 static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
 {
-       if (!hdev || !hdev->actconfig)
+       if (!hdev || !hdev->actconfig || !hdev->maxchild)
                return NULL;
        return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
@@ -836,7 +855,12 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
                dev_dbg(hub->intfdev, "trying to enable port power on "
                                "non-switchable hub\n");
        for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
-               set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
+               if (hub->ports[port1 - 1]->port_power_policy
+                               == USB_PORT_POWER_ON)
+                       set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
+               else
+                       clear_port_feature(hub->hdev, port1,
+                                       USB_PORT_FEAT_POWER);
 
        /* Wait at least 100 msec for power to become stable */
        delay = max(pgood_delay, (unsigned) 100);
@@ -869,8 +893,8 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
        struct usb_device *hdev = hub->hdev;
        int ret = 0;
 
-       if (hdev->children[port1-1] && set_state)
-               usb_set_device_state(hdev->children[port1-1],
+       if (hub->ports[port1 - 1]->child && set_state)
+               usb_set_device_state(hub->ports[port1 - 1]->child,
                                USB_STATE_NOTATTACHED);
        if (!hub->error && !hub_is_superspeed(hub->hdev))
                ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
@@ -1026,7 +1050,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
         * which ports need attention.
         */
        for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-               struct usb_device *udev = hdev->children[port1-1];
+               struct usb_device *udev = hub->ports[port1 - 1]->child;
                u16 portstatus, portchange;
 
                portstatus = portchange = 0;
@@ -1191,8 +1215,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
        if (type != HUB_SUSPEND) {
                /* Disconnect all the children */
                for (i = 0; i < hdev->maxchild; ++i) {
-                       if (hdev->children[i])
-                               usb_disconnect(&hdev->children[i]);
+                       if (hub->ports[i]->child)
+                               usb_disconnect(&hub->ports[i]->child);
                }
        }
 
@@ -1222,6 +1246,53 @@ static int hub_post_reset(struct usb_interface *intf)
        return 0;
 }
 
+static void usb_port_device_release(struct device *dev)
+{
+       struct usb_port *port_dev = to_usb_port(dev);
+
+       kfree(port_dev);
+}
+
+static void usb_hub_remove_port_device(struct usb_hub *hub,
+                                      int port1)
+{
+       device_unregister(&hub->ports[port1 - 1]->dev);
+}
+
+struct device_type usb_port_device_type = {
+       .name =         "usb_port",
+       .release =      usb_port_device_release,
+};
+
+static int usb_hub_create_port_device(struct usb_hub *hub,
+                                     int port1)
+{
+       struct usb_port *port_dev = NULL;
+       int retval;
+
+       port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
+       if (!port_dev) {
+               retval = -ENOMEM;
+               goto exit;
+       }
+
+       hub->ports[port1 - 1] = port_dev;
+       port_dev->dev.parent = hub->intfdev;
+       port_dev->dev.groups = port_dev_group;
+       port_dev->dev.type = &usb_port_device_type;
+       dev_set_name(&port_dev->dev, "port%d", port1);
+
+       retval = device_register(&port_dev->dev);
+       if (retval)
+               goto error_register;
+       return 0;
+
+error_register:
+       put_device(&port_dev->dev);
+exit:
+       return retval;
+}
+
 static int hub_configure(struct usb_hub *hub,
        struct usb_endpoint_descriptor *endpoint)
 {
@@ -1231,7 +1302,7 @@ static int hub_configure(struct usb_hub *hub,
        u16 hubstatus, hubchange;
        u16 wHubCharacteristics;
        unsigned int pipe;
-       int maxp, ret;
+       int maxp, ret, i;
        char *message = "out of memory";
 
        hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
@@ -1271,11 +1342,9 @@ static int hub_configure(struct usb_hub *hub,
        dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
                (hdev->maxchild == 1) ? "" : "s");
 
-       hdev->children = kzalloc(hdev->maxchild *
-                               sizeof(struct usb_device *), GFP_KERNEL);
-       hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *),
-                               GFP_KERNEL);
-       if (!hdev->children || !hub->port_owners) {
+       hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *),
+                            GFP_KERNEL);
+       if (!hub->ports) {
                ret = -ENOMEM;
                goto fail;
        }
@@ -1484,6 +1553,11 @@ static int hub_configure(struct usb_hub *hub,
        if (hub->has_indicators && blinkenlights)
                hub->indicator [0] = INDICATOR_CYCLE;
 
+       for (i = 0; i < hdev->maxchild; i++)
+               if (usb_hub_create_port_device(hub, i + 1) < 0)
+                       dev_err(hub->intfdev,
+                               "couldn't create port%d device.\n", i + 1);
+
        hub_activate(hub, HUB_INIT);
        return 0;
 
@@ -1508,6 +1582,10 @@ static void hub_disconnect(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata(intf);
        struct usb_device *hdev = interface_to_usbdev(intf);
+       int i;
+
+       for (i = 0; i < hdev->maxchild; i++)
+               usb_hub_remove_port_device(hub, i + 1);
 
        /* Take the hub off the event list and don't let it be added again */
        spin_lock_irq(&hub_event_lock);
@@ -1529,8 +1607,7 @@ static void hub_disconnect(struct usb_interface *intf)
                highspeed_hubs--;
 
        usb_free_urb(hub->urb);
-       kfree(hdev->children);
-       kfree(hub->port_owners);
+       kfree(hub->ports);
        kfree(hub->descriptor);
        kfree(hub->status);
        kfree(hub->buffer);
@@ -1617,6 +1694,7 @@ static int
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
        struct usb_device *hdev = interface_to_usbdev (intf);
+       struct usb_hub *hub = hdev_to_hub(hdev);
 
        /* assert ifno == 0 (part of hub spec) */
        switch (code) {
@@ -1630,11 +1708,11 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
                else {
                        info->nports = hdev->maxchild;
                        for (i = 0; i < info->nports; i++) {
-                               if (hdev->children[i] == NULL)
+                               if (hub->ports[i]->child == NULL)
                                        info->port[i] = 0;
                                else
                                        info->port[i] =
-                                               hdev->children[i]->devnum;
+                                               hub->ports[i]->child->devnum;
                        }
                }
                spin_unlock_irq(&device_state_lock);
@@ -1662,7 +1740,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,
        /* This assumes that devices not managed by the hub driver
         * will always have maxchild equal to 0.
         */
-       *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
+       *ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1]->port_owner);
        return 0;
 }
 
@@ -1699,16 +1777,14 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
 
 void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
 {
+       struct usb_hub *hub = hdev_to_hub(hdev);
        int n;
-       struct dev_state **powner;
 
-       n = find_port_owner(hdev, 1, &powner);
-       if (n == 0) {
-               for (; n < hdev->maxchild; (++n, ++powner)) {
-                       if (*powner == owner)
-                               *powner = NULL;
-               }
+       for (n = 0; n < hdev->maxchild; n++) {
+               if (hub->ports[n]->port_owner == owner)
+                       hub->ports[n]->port_owner = NULL;
        }
+
 }
 
 /* The caller must hold udev's lock */
@@ -1719,17 +1795,17 @@ bool usb_device_is_owned(struct usb_device *udev)
        if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
                return false;
        hub = hdev_to_hub(udev->parent);
-       return !!hub->port_owners[udev->portnum - 1];
+       return !!hub->ports[udev->portnum - 1]->port_owner;
 }
 
-
 static void recursively_mark_NOTATTACHED(struct usb_device *udev)
 {
+       struct usb_hub *hub = hdev_to_hub(udev);
        int i;
 
        for (i = 0; i < udev->maxchild; ++i) {
-               if (udev->children[i])
-                       recursively_mark_NOTATTACHED(udev->children[i]);
+               if (hub->ports[i]->child)
+                       recursively_mark_NOTATTACHED(hub->ports[i]->child);
        }
        if (udev->state == USB_STATE_SUSPENDED)
                udev->active_duration -= jiffies;
@@ -1893,6 +1969,7 @@ static void hub_free_dev(struct usb_device *udev)
 void usb_disconnect(struct usb_device **pdev)
 {
        struct usb_device       *udev = *pdev;
+       struct usb_hub          *hub = hdev_to_hub(udev);
        int                     i;
 
        /* mark the device as inactive, so any further urb submissions for
@@ -1907,8 +1984,8 @@ void usb_disconnect(struct usb_device **pdev)
 
        /* Free up all the children before we remove this device */
        for (i = 0; i < udev->maxchild; i++) {
-               if (udev->children[i])
-                       usb_disconnect(&udev->children[i]);
+               if (hub->ports[i]->child)
+                       usb_disconnect(&hub->ports[i]->child);
        }
 
        /* deallocate hcd/hardware state ... nuking all pending urbs and
@@ -2113,7 +2190,8 @@ static void set_usb_port_removable(struct usb_device *udev)
                return;
 
        if (hub_is_superspeed(hdev)) {
-               if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
+               if (le16_to_cpu(hub->descriptor->u.ss.DeviceRemovable)
+                               & (1 << port))
                        removable = false;
        } else {
                if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
@@ -2566,6 +2644,25 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
        return ret;
 }
 
+static int usb_get_hub_port_power_state(struct usb_device *hdev, int port1)
+{
+       struct usb_hub *hub = hdev_to_hub(hdev);
+       struct usb_port_status data;
+       u16 portstatus;
+       int ret;
+
+       ret = get_port_status(hub->hdev, port1, &data);
+       if (ret < 4) {
+               dev_err(hub->intfdev,
+                       "%s failed (err = %d)\n", __func__, ret);
+               if (ret >= 0)
+                       ret = -EIO;
+               return ret;
+       } else
+               portstatus = le16_to_cpu(data.wPortStatus);
+       return port_is_power_on(hub, portstatus);
+}
+
 #ifdef CONFIG_PM
 
 /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
@@ -3072,7 +3169,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
        for (port1 = 1; port1 <= hdev->maxchild; port1++) {
                struct usb_device       *udev;
 
-               udev = hdev->children [port1-1];
+               udev = hub->ports[port1 - 1]->child;
                if (udev && udev->can_submit) {
                        dev_warn(&intf->dev, "port %d nyet suspended\n", port1);
                        if (PMSG_IS_AUTO(msg))
@@ -3999,7 +4096,7 @@ hub_power_remaining (struct usb_hub *hub)
 
        remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
        for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-               struct usb_device       *udev = hdev->children[port1 - 1];
+               struct usb_device       *udev = hub->ports[port1 - 1]->child;
                int                     delta;
 
                if (!udev)
@@ -4063,7 +4160,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 #endif
 
        /* Try to resuscitate an existing device */
-       udev = hdev->children[port1-1];
+       udev = hub->ports[port1 - 1]->child;
        if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
                        udev->state != USB_STATE_NOTATTACHED) {
                usb_lock_device(udev);
@@ -4092,7 +4189,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 
        /* Disconnect any existing devices under this port */
        if (udev)
-               usb_disconnect(&hdev->children[port1-1]);
+               usb_disconnect(&hub->ports[port1 - 1]->child);
        clear_bit(port1, hub->change_bits);
 
        /* We can forget about a "removed" device when there's a physical
@@ -4228,7 +4325,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                if (hdev->state == USB_STATE_NOTATTACHED)
                        status = -ENOTCONN;
                else
-                       hdev->children[port1-1] = udev;
+                       hub->ports[port1 - 1]->child = udev;
                spin_unlock_irq(&device_state_lock);
 
                /* Run it through the hoops (find a driver, etc) */
@@ -4236,7 +4333,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                        status = usb_new_device(udev);
                        if (status) {
                                spin_lock_irq(&device_state_lock);
-                               hdev->children[port1-1] = NULL;
+                               hub->ports[port1 - 1]->child = NULL;
                                spin_unlock_irq(&device_state_lock);
                        }
                }
@@ -4282,7 +4379,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
        int ret;
 
        hdev = hub->hdev;
-       udev = hdev->children[port-1];
+       udev = hub->ports[port - 1]->child;
        if (!hub_is_superspeed(hdev)) {
                if (!(portchange & USB_PORT_STAT_C_SUSPEND))
                        return 0;
@@ -4436,7 +4533,7 @@ static void hub_events(void)
                                 */
                                if (!(portstatus & USB_PORT_STAT_ENABLE)
                                    && !connect_change
-                                   && hdev->children[i-1]) {
+                                   && hub->ports[i - 1]->child) {
                                        dev_err (hub_dev,
                                            "port %i "
                                            "disabled by hub (EMI?), "
@@ -4572,6 +4669,102 @@ static int hub_thread(void *__unused)
        return 0;
 }
 
+static ssize_t show_port_power_state(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_device *udev = to_usb_device(dev->parent->parent);
+       struct usb_interface *intf = to_usb_interface(dev->parent);
+       int port1, power_state;
+       const char *result;
+
+       sscanf(dev_name(dev), "port%d", &port1);
+       usb_autopm_get_interface(intf);
+       power_state = usb_get_hub_port_power_state(udev, port1);
+       usb_autopm_put_interface(intf);
+       if (power_state == 1)
+               result = on_string;
+       else if (!power_state)
+               result = off_string;
+       else
+               result = "error";
+       return sprintf(buf, "%s\n", result);
+}
+static DEVICE_ATTR(state, S_IRUGO, show_port_power_state, NULL);
+
+static ssize_t show_port_power_control(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_port *hub_port = to_usb_port(dev);
+       const char *result;
+
+       switch (hub_port->port_power_policy) {
+       case USB_PORT_POWER_ON:
+               result = on_string;
+               break;
+       case USB_PORT_POWER_OFF:
+               result = off_string;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return sprintf(buf, "%s\n", result);
+}
+
+static ssize_t store_port_power_control(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct usb_device *hdev = to_usb_device(dev->parent->parent);
+       struct usb_interface *intf = to_usb_interface(dev->parent);
+       struct usb_port *hub_port = to_usb_port(dev);
+       int port1, ret, len = count;
+       char *cp;
+
+       sscanf(dev_name(dev), "port%d", &port1);
+       cp = memchr(buf, '\n', count);
+       if (cp)
+               len = cp - buf;
+       if (len == sizeof(on_string) - 1
+                       && strncmp(buf, on_string, len) == 0) {
+               hub_port->port_power_policy = USB_PORT_POWER_ON;
+               usb_autopm_get_interface(intf);
+               ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+               usb_autopm_put_interface(intf);
+               if (ret < 0)
+                       return -EIO;
+       } else if (len == sizeof(off_string) - 1
+                       && strncmp(buf, off_string, len) == 0) {
+               struct usb_hub *hub = hdev_to_hub(hdev);
+
+               hub_port->port_power_policy = USB_PORT_POWER_OFF;
+               usb_autopm_get_interface(intf);
+               hub_port_logical_disconnect(hub, port1);
+               ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
+               usb_autopm_put_interface(intf);
+               if (ret < 0)
+                       return -EIO;
+       } else
+               return -EINVAL;
+
+       return count;
+}
+static DEVICE_ATTR(control, S_IWUSR | S_IRUGO, show_port_power_control,
+               store_port_power_control);
+
+static struct attribute *port_dev_attrs[] = {
+       &dev_attr_control.attr,
+       &dev_attr_state.attr,
+       NULL,
+};
+
+static struct attribute_group port_dev_attr_grp = {
+       .attrs = port_dev_attrs,
+};
+
+static const struct attribute_group *port_dev_group[] = {
+       &port_dev_attr_grp,
+       NULL,
+};
+
 static const struct usb_device_id hub_id_table[] = {
     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
       .bDeviceClass = USB_CLASS_HUB},
@@ -4993,3 +5186,75 @@ void usb_queue_reset_device(struct usb_interface *iface)
        schedule_work(&iface->reset_ws);
 }
 EXPORT_SYMBOL_GPL(usb_queue_reset_device);
+
+/**
+ * usb_hub_find_child - Get the pointer of child device
+ * attached to the port which is specified by @port1.
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num to indicate which port the child device
+ *     is attached to.
+ *
+ * USB drivers call this function to get hub's child device
+ * pointer.
+ *
+ * Return NULL if input param is invalid and
+ * child's usb_device pointer if non-NULL.
+ */
+struct usb_device *usb_hub_find_child(struct usb_device *hdev,
+               int port1)
+{
+       struct usb_hub *hub = hdev_to_hub(hdev);
+
+       if (port1 < 1 || port1 > hdev->maxchild)
+               return NULL;
+       return hub->ports[port1 - 1]->child;
+}
+EXPORT_SYMBOL_GPL(usb_hub_find_child);
+
+/**
+ * usb_set_hub_port_connect_type - set hub port connect type.
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ * @type: connect type of the port
+ */
+void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
+       enum usb_port_connect_type type)
+{
+       struct usb_hub *hub = hdev_to_hub(hdev);
+
+       hub->ports[port1 - 1]->connect_type = type;
+}
+
+/**
+ * usb_get_hub_port_connect_type - Get the port's connect type
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ *
+ * Return connect type of the port and if input params are
+ * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN.
+ */
+enum usb_port_connect_type
+usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
+{
+       struct usb_hub *hub = hdev_to_hub(hdev);
+
+       return hub->ports[port1 - 1]->connect_type;
+}
+
+#ifdef CONFIG_ACPI
+/**
+ * usb_get_hub_port_acpi_handle - Get the usb port's acpi handle
+ * @hdev: USB device belonging to the usb hub
+ * @port1: port num of the port
+ *
+ * Return port's acpi handle if successful, NULL if params are
+ * invaild.
+ */
+acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
+       int port1)
+{
+       struct usb_hub *hub = hdev_to_hub(hdev);
+
+       return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
+}
+#endif
index f15501f4c585694c0c513eac78f692558ae8720f..2dbb5154f356b01baf3a8f9da9f1aa855e2ad11f 100644 (file)
@@ -205,7 +205,7 @@ void usb_detect_quirks(struct usb_device *udev)
         * for all devices.  It will affect things like hub resets
         * and EMF-related port disables.
         */
-       if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
+       if (!(udev->quirks & USB_QUIRK_RESET))
                udev->persist_enabled = 1;
 #endif /* CONFIG_PM */
 }
index 682e8256b95da719d3e5d2aeea019cc59c25520f..818e4a024d0d8d259c1fffa8f93c60806f8a64c1 100644 (file)
@@ -196,7 +196,7 @@ show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *
        struct usb_device *udev;
 
        udev = to_usb_device(dev);
-       return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS));
+       return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
 }
 
 static ssize_t
@@ -204,15 +204,15 @@ set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
        struct usb_device       *udev = to_usb_device(dev);
-       int                     config;
+       int                     val;
 
-       if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
+       if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
                return -EINVAL;
        usb_lock_device(udev);
-       if (config)
-               udev->quirks |= USB_QUIRK_RESET_MORPHS;
+       if (val)
+               udev->quirks |= USB_QUIRK_RESET;
        else
-               udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
+               udev->quirks &= ~USB_QUIRK_RESET;
        usb_unlock_device(udev);
        return count;
 }
index 8947b203d5a4dd1cbe2dcc190a9d3b19363bf75b..0ef7d42d8abe85e77f7fdac7778b7e1220e41c49 100644 (file)
 
 #include "usb.h"
 
-static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
+/**
+ * usb_acpi_power_manageable - check whether usb port has
+ * acpi power resource.
+ * @hdev: USB device belonging to the usb hub
+ * @index: port index based zero
+ *
+ * Return true if the port has acpi power resource and false if no.
+ */
+bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
+{
+       acpi_handle port_handle;
+       int port1 = index + 1;
+
+       port_handle = usb_get_hub_port_acpi_handle(hdev,
+               port1);
+       if (port_handle)
+               return acpi_bus_power_manageable(port_handle);
+       else
+               return false;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
+
+/**
+ * usb_acpi_set_power_state - control usb port's power via acpi power
+ * resource
+ * @hdev: USB device belonging to the usb hub
+ * @index: port index based zero
+ * @enable: power state expected to be set
+ *
+ * Notice to use usb_acpi_power_manageable() to check whether the usb port
+ * has acpi power resource before invoking this function.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
+{
+       acpi_handle port_handle;
+       unsigned char state;
+       int port1 = index + 1;
+       int error = -EINVAL;
+
+       port_handle = (acpi_handle)usb_get_hub_port_acpi_handle(hdev,
+               port1);
+       if (!port_handle)
+               return error;
+
+       if (enable)
+               state = ACPI_STATE_D0;
+       else
+               state = ACPI_STATE_D3_COLD;
+
+       error = acpi_bus_set_power(port_handle, state);
+       if (!error)
+               dev_dbg(&hdev->dev, "The power of hub port %d was set to %d\n",
+                       port1, enable);
+       else
+               dev_dbg(&hdev->dev, "The power of hub port failed to be set\n");
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_set_power_state);
+
+static int usb_acpi_check_port_connect_type(struct usb_device *hdev,
+       acpi_handle handle, int port1)
 {
        acpi_status status;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *upc;
+       struct acpi_pld pld;
        int ret = 0;
 
-       status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
-
+       /*
+        * Accoding to ACPI Spec 9.13. PLD indicates whether usb port is
+        * user visible and _UPC indicates whether it is connectable. If
+        * the port was visible and connectable, it could be freely connected
+        * and disconnected with USB devices. If no visible and connectable,
+        * a usb device is directly hard-wired to the port. If no visible and
+        * no connectable, the port would be not used.
+        */
+       status = acpi_get_physical_device_location(handle, &pld);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
+       status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
        upc = buffer.pointer;
-
        if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
                || upc->package.count != 4) {
                ret = -EINVAL;
@@ -40,69 +111,107 @@ static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
        }
 
        if (upc->package.elements[0].integer.value)
-               udev->removable = USB_DEVICE_REMOVABLE;
-       else
-               udev->removable = USB_DEVICE_FIXED;
+               if (pld.user_visible)
+                       usb_set_hub_port_connect_type(hdev, port1,
+                               USB_PORT_CONNECT_TYPE_HOT_PLUG);
+               else
+                       usb_set_hub_port_connect_type(hdev, port1,
+                               USB_PORT_CONNECT_TYPE_HARD_WIRED);
+       else if (!pld.user_visible)
+               usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED);
 
 out:
        kfree(upc);
        return ret;
 }
 
-static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle)
-{
-       acpi_status status;
-       struct acpi_pld pld;
-
-       status = acpi_get_physical_device_location(handle, &pld);
-
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       if (pld.user_visible)
-               udev->removable = USB_DEVICE_REMOVABLE;
-       else
-               udev->removable = USB_DEVICE_FIXED;
-
-       return 0;
-}
-
 static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
 {
        struct usb_device *udev;
-       struct device *parent;
        acpi_handle *parent_handle;
-
-       if (!is_usb_device(dev))
-               return -ENODEV;
-
-       udev = to_usb_device(dev);
-       parent = dev->parent;
-       parent_handle = DEVICE_ACPI_HANDLE(parent);
-
-       if (!parent_handle)
-               return -ENODEV;
-
-       *handle = acpi_get_child(parent_handle, udev->portnum);
-
-       if (!*handle)
-               return -ENODEV;
+       int port_num;
 
        /*
-        * PLD will tell us whether a port is removable to the user or
-        * not. If we don't get an answer from PLD (it's not present
-        * or it's malformed) then try to infer it from UPC. If a
-        * device isn't connectable then it's probably not removable.
+        * In the ACPI DSDT table, only usb root hub and usb ports are
+        * acpi device nodes. The hierarchy like following.
+        * Device (EHC1)
+        *      Device (HUBN)
+        *              Device (PR01)
+        *                      Device (PR11)
+        *                      Device (PR12)
+        *                      Device (PR13)
+        *                      ...
+        * So all binding process is divided into two parts. binding
+        * root hub and usb ports.
         */
-       if (usb_acpi_check_pld(udev, *handle) != 0)
-               usb_acpi_check_upc(udev, *handle);
+       if (is_usb_device(dev)) {
+               udev = to_usb_device(dev);
+               if (udev->parent) {
+                       enum usb_port_connect_type type;
+
+                       /*
+                        * According usb port's connect type to set usb device's
+                        * removability.
+                        */
+                       type = usb_get_hub_port_connect_type(udev->parent,
+                               udev->portnum);
+                       switch (type) {
+                       case USB_PORT_CONNECT_TYPE_HOT_PLUG:
+                               udev->removable = USB_DEVICE_REMOVABLE;
+                               break;
+                       case USB_PORT_CONNECT_TYPE_HARD_WIRED:
+                               udev->removable = USB_DEVICE_FIXED;
+                               break;
+                       default:
+                               udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN;
+                               break;
+                       }
+
+                       return -ENODEV;
+               }
+
+               /* root hub's parent is the usb hcd. */
+               parent_handle = DEVICE_ACPI_HANDLE(dev->parent);
+               *handle = acpi_get_child(parent_handle, udev->portnum);
+               if (!*handle)
+                       return -ENODEV;
+               return 0;
+       } else if (is_usb_port(dev)) {
+               sscanf(dev_name(dev), "port%d", &port_num);
+               /* Get the struct usb_device point of port's hub */
+               udev = to_usb_device(dev->parent->parent);
+
+               /*
+                * The root hub ports' parent is the root hub. The non-root-hub
+                * ports' parent is the parent hub port which the hub is
+                * connected to.
+                */
+               if (!udev->parent) {
+                       *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
+                               port_num);
+                       if (!*handle)
+                               return -ENODEV;
+               } else {
+                       parent_handle =
+                               usb_get_hub_port_acpi_handle(udev->parent,
+                               udev->portnum);
+                       if (!parent_handle)
+                               return -ENODEV;
+
+                       *handle = acpi_get_child(parent_handle, port_num);
+                       if (!*handle)
+                               return -ENODEV;
+               }
+               usb_acpi_check_port_connect_type(udev, *handle, port_num);
+       } else
+               return -ENODEV;
 
        return 0;
 }
 
 static struct acpi_bus_type usb_acpi_bus = {
        .bus = &usb_bus_type,
-       .find_bridge = NULL,
+       .find_bridge = usb_acpi_find_device,
        .find_device = usb_acpi_find_device,
 };
 
index acb103c5c391190e83ee66e3d837f80ad14f72e8..1c528c1bf0bed767f2a502546e91bbfcc7fff706 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/pm.h>
+#include <linux/acpi.h>
 
 struct dev_state;
 
@@ -115,6 +116,7 @@ extern struct bus_type usb_bus_type;
 extern struct device_type usb_device_type;
 extern struct device_type usb_if_device_type;
 extern struct device_type usb_ep_device_type;
+extern struct device_type usb_port_device_type;
 extern struct usb_device_driver usb_generic_driver;
 
 static inline int is_usb_device(const struct device *dev)
@@ -132,6 +134,11 @@ static inline int is_usb_endpoint(const struct device *dev)
        return dev->type == &usb_ep_device_type;
 }
 
+static inline int is_usb_port(const struct device *dev)
+{
+       return dev->type == &usb_port_device_type;
+}
+
 /* Do the same for device drivers and interface drivers. */
 
 static inline int is_usb_device_driver(struct device_driver *drv)
@@ -162,10 +169,16 @@ extern void usb_notify_add_device(struct usb_device *udev);
 extern void usb_notify_remove_device(struct usb_device *udev);
 extern void usb_notify_add_bus(struct usb_bus *ubus);
 extern void usb_notify_remove_bus(struct usb_bus *ubus);
+extern enum usb_port_connect_type
+       usb_get_hub_port_connect_type(struct usb_device *hdev, int port1);
+extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
+       enum usb_port_connect_type type);
 
 #ifdef CONFIG_ACPI
 extern int usb_acpi_register(void);
 extern void usb_acpi_unregister(void);
+extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
+       int port1);
 #else
 static inline int usb_acpi_register(void) { return 0; };
 static inline void usb_acpi_unregister(void) { };
index d13c60f421399abb8eab352dd582020a9f614bdd..f6a6e070c2ac0219390d9a17706ed22e1333c739 100644 (file)
@@ -2,8 +2,6 @@ config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
        depends on (USB && USB_GADGET)
        select USB_OTG_UTILS
-       select USB_GADGET_DUALSPEED
-       select USB_GADGET_SUPERSPEED
        select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
        help
          Say Y or M here if your system has a Dual Role SuperSpeed
index 08a5738a6e1bb96f0e0f78888be3e5f639a41071..bed2c1615463782065f2539d6c9c0cf0fa38e3a8 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
 
+#include <linux/usb/otg.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
@@ -137,6 +138,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
        reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
+       usb_phy_init(dwc->usb2_phy);
+       usb_phy_init(dwc->usb3_phy);
        mdelay(100);
 
        /* Clear USB3 PHY reset */
@@ -466,6 +469,18 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+       if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
+               dev_err(dev, "no usb2 phy configured\n");
+               return -EPROBE_DEFER;
+       }
+
+       dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+       if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
+               dev_err(dev, "no usb3 phy configured\n");
+               return -EPROBE_DEFER;
+       }
+
        spin_lock_init(&dwc->lock);
        platform_set_drvdata(pdev, dwc);
 
index c611d80233682047a1ea9009606a741810353617..243affc9343120339bf6b5c0e27e104f228e2dcd 100644 (file)
@@ -623,6 +623,8 @@ struct dwc3_scratchpad_array {
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
  * @mode: mode of operation
+ * @usb2_phy: pointer to USB2 PHY
+ * @usb3_phy: pointer to USB3 PHY
  * @is_selfpowered: true when we are selfpowered
  * @three_stage_setup: set if we perform a three phase setup
  * @ep0_bounced: true when we used bounce buffer
@@ -666,6 +668,9 @@ struct dwc3 {
        struct usb_gadget       gadget;
        struct usb_gadget_driver *gadget_driver;
 
+       struct usb_phy          *usb2_phy;
+       struct usb_phy          *usb3_phy;
+
        void __iomem            *regs;
        size_t                  regs_size;
 
index b8f00389fa34c2acb169afde75d142d84dab9ea2..ca6597853f90339358bf670e37e1cad2f65cf4cc 100644 (file)
 #include <linux/platform_data/dwc3-exynos.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include "core.h"
 
 struct dwc3_exynos {
        struct platform_device  *dwc3;
+       struct platform_device  *usb2_phy;
+       struct platform_device  *usb3_phy;
        struct device           *dev;
 
        struct clk              *clk;
 };
 
+static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
+{
+       struct nop_usb_xceiv_platform_data pdata;
+       struct platform_device  *pdev;
+       int                     ret;
+
+       memset(&pdata, 0x00, sizeof(pdata));
+
+       pdev = platform_device_alloc("nop_usb_xceiv", 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       exynos->usb2_phy = pdev;
+       pdata.type = USB_PHY_TYPE_USB2;
+
+       ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
+       if (ret)
+               goto err1;
+
+       pdev = platform_device_alloc("nop_usb_xceiv", 1);
+       if (!pdev) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       exynos->usb3_phy = pdev;
+       pdata.type = USB_PHY_TYPE_USB3;
+
+       ret = platform_device_add_data(exynos->usb3_phy, &pdata, sizeof(pdata));
+       if (ret)
+               goto err2;
+
+       ret = platform_device_add(exynos->usb2_phy);
+       if (ret)
+               goto err2;
+
+       ret = platform_device_add(exynos->usb3_phy);
+       if (ret)
+               goto err3;
+
+       return 0;
+
+err3:
+       platform_device_del(exynos->usb2_phy);
+
+err2:
+       platform_device_put(exynos->usb3_phy);
+
+err1:
+       platform_device_put(exynos->usb2_phy);
+
+       return ret;
+}
+
 static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
 {
        struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
@@ -51,6 +109,12 @@ static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
        if (devid < 0)
                goto err1;
 
+       ret = dwc3_exynos_register_phys(exynos);
+       if (ret) {
+               dev_err(&pdev->dev, "couldn't register PHYs\n");
+               goto err1;
+       }
+
        dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
                dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
@@ -120,6 +184,8 @@ static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
        struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
 
        platform_device_unregister(exynos->dwc3);
+       platform_device_unregister(exynos->usb2_phy);
+       platform_device_unregister(exynos->usb3_phy);
 
        dwc3_put_device_id(exynos->dwc3->id);
 
index 479dc047da3a76ac567143046a27c0b816264e92..ee57a10d90d044373455dd6a66ac4118fd3cab5a 100644 (file)
@@ -48,6 +48,9 @@
 #include <linux/io.h>
 #include <linux/of.h>
 
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
+
 #include "core.h"
 
 /*
@@ -131,6 +134,8 @@ struct dwc3_omap {
        spinlock_t              lock;
 
        struct platform_device  *dwc3;
+       struct platform_device  *usb2_phy;
+       struct platform_device  *usb3_phy;
        struct device           *dev;
 
        int                     irq;
@@ -152,6 +157,59 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
        writel(value, base + offset);
 }
 
+static int __devinit dwc3_omap_register_phys(struct dwc3_omap *omap)
+{
+       struct nop_usb_xceiv_platform_data pdata;
+       struct platform_device  *pdev;
+       int                     ret;
+
+       memset(&pdata, 0x00, sizeof(pdata));
+
+       pdev = platform_device_alloc("nop_usb_xceiv", 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       omap->usb2_phy = pdev;
+       pdata.type = USB_PHY_TYPE_USB2;
+
+       ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
+       if (ret)
+               goto err1;
+
+       pdev = platform_device_alloc("nop_usb_xceiv", 1);
+       if (!pdev) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       omap->usb3_phy = pdev;
+       pdata.type = USB_PHY_TYPE_USB3;
+
+       ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
+       if (ret)
+               goto err2;
+
+       ret = platform_device_add(omap->usb2_phy);
+       if (ret)
+               goto err2;
+
+       ret = platform_device_add(omap->usb3_phy);
+       if (ret)
+               goto err3;
+
+       return 0;
+
+err3:
+       platform_device_del(omap->usb2_phy);
+
+err2:
+       platform_device_put(omap->usb3_phy);
+
+err1:
+       platform_device_put(omap->usb2_phy);
+
+       return ret;
+}
 
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 {
@@ -251,6 +309,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       ret = dwc3_omap_register_phys(omap);
+       if (ret) {
+               dev_err(dev, "couldn't register PHYs\n");
+               return ret;
+       }
+
        devid = dwc3_get_device_id();
        if (devid < 0)
                return -ENODEV;
@@ -371,6 +435,8 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
        struct dwc3_omap        *omap = platform_get_drvdata(pdev);
 
        platform_device_unregister(omap->dwc3);
+       platform_device_unregister(omap->usb2_phy);
+       platform_device_unregister(omap->usb3_phy);
 
        dwc3_put_device_id(omap->dwc3->id);
 
index a9ca9adba391aeb1ee1b5c32c9f2cbf0359a5547..94f550e37f986950f35c28e1e53d8773b4156031 100644 (file)
@@ -42,6 +42,9 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 
+#include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
+
 #include "core.h"
 
 /* FIXME define these in <linux/pci_ids.h> */
 struct dwc3_pci {
        struct device           *dev;
        struct platform_device  *dwc3;
+       struct platform_device  *usb2_phy;
+       struct platform_device  *usb3_phy;
 };
 
+static int __devinit dwc3_pci_register_phys(struct dwc3_pci *glue)
+{
+       struct nop_usb_xceiv_platform_data pdata;
+       struct platform_device  *pdev;
+       int                     ret;
+
+       memset(&pdata, 0x00, sizeof(pdata));
+
+       pdev = platform_device_alloc("nop_usb_xceiv", 0);
+       if (!pdev)
+               return -ENOMEM;
+
+       glue->usb2_phy = pdev;
+       pdata.type = USB_PHY_TYPE_USB2;
+
+       ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
+       if (ret)
+               goto err1;
+
+       pdev = platform_device_alloc("nop_usb_xceiv", 1);
+       if (!pdev) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       glue->usb3_phy = pdev;
+       pdata.type = USB_PHY_TYPE_USB3;
+
+       ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
+       if (ret)
+               goto err2;
+
+       ret = platform_device_add(glue->usb2_phy);
+       if (ret)
+               goto err2;
+
+       ret = platform_device_add(glue->usb3_phy);
+       if (ret)
+               goto err3;
+
+       return 0;
+
+err3:
+       platform_device_del(glue->usb2_phy);
+
+err2:
+       platform_device_put(glue->usb3_phy);
+
+err1:
+       platform_device_put(glue->usb2_phy);
+
+       return ret;
+}
+
 static int __devinit dwc3_pci_probe(struct pci_dev *pci,
                const struct pci_device_id *id)
 {
@@ -80,6 +139,12 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
        pci_set_power_state(pci, PCI_D0);
        pci_set_master(pci);
 
+       ret = dwc3_pci_register_phys(glue);
+       if (ret) {
+               dev_err(dev, "couldn't register PHYs\n");
+               return ret;
+       }
+
        devid = dwc3_get_device_id();
        if (devid < 0) {
                ret = -ENOMEM;
@@ -144,6 +209,8 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
 {
        struct dwc3_pci *glue = pci_get_drvdata(pci);
 
+       platform_device_unregister(glue->usb2_phy);
+       platform_device_unregister(glue->usb3_phy);
        dwc3_put_device_id(glue->dwc3->id);
        platform_device_unregister(glue->dwc3);
        pci_set_drvdata(pci, NULL);
index ee0ebacf8227df070dc4a40daf8cd873007ca296..89dcf155d57e9e75fec8919e120fe6fcaa4b0136 100644 (file)
@@ -450,7 +450,7 @@ static int dbgp_ehci_startup(void)
        writel(FLAG_CF, &ehci_regs->configured_flag);
 
        /* Wait until the controller is no longer halted */
-       loop = 10;
+       loop = 1000;
        do {
                status = readl(&ehci_regs->status);
                if (!(status & STS_HALT))
index 51ab5fd5d468ee7aa60de898a9bd921ebaf4bbca..a53be32c22cfd1ed54b0edb0a338f50fdefa183f 100644 (file)
@@ -154,16 +154,25 @@ config USB_LPC32XX
 
 config USB_ATMEL_USBA
        tristate "Atmel USBA"
-       select USB_GADGET_DUALSPEED
        depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
        help
          USBA is the integrated high-speed USB Device controller on
          the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
 
+config USB_BCM63XX_UDC
+       tristate "Broadcom BCM63xx Peripheral Controller"
+       depends on BCM63XX
+       help
+          Many Broadcom BCM63xx chipsets (such as the BCM6328) have a
+          high speed USB Device Port with support for four fixed endpoints
+          (plus endpoint zero).
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "bcm63xx_udc".
+
 config USB_FSL_USB2
        tristate "Freescale Highspeed USB DR Peripheral Controller"
        depends on FSL_SOC || ARCH_MXC
-       select USB_GADGET_DUALSPEED
        select USB_FSL_MPH_DR_OF if OF
        help
           Some of Freescale PowerPC and i.MX processors have a High Speed
@@ -179,7 +188,6 @@ config USB_FSL_USB2
 config USB_FUSB300
        tristate "Faraday FUSB300 USB Peripheral Controller"
        depends on !PHYS_ADDR_T_64BIT
-       select USB_GADGET_DUALSPEED
        help
           Faraday usb device controller FUSB300 driver
 
@@ -227,7 +235,6 @@ config USB_PXA25X_SMALL
 
 config USB_R8A66597
        tristate "Renesas R8A66597 USB Peripheral Controller"
-       select USB_GADGET_DUALSPEED
        help
           R8A66597 is a discrete USB host and peripheral controller chip that
           supports both full and high speed USB 2.0 data transfers.
@@ -240,7 +247,6 @@ config USB_R8A66597
 config USB_RENESAS_USBHS_UDC
        tristate 'Renesas USBHS controller'
        depends on USB_RENESAS_USBHS
-       select USB_GADGET_DUALSPEED
        help
           Renesas USBHS is a discrete USB host and peripheral controller chip
           that supports both full and high speed USB 2.0 data transfers.
@@ -268,7 +274,6 @@ config USB_PXA27X
 config USB_S3C_HSOTG
        tristate "S3C HS/OtG USB Device controller"
        depends on S3C_DEV_USB_HSOTG
-       select USB_GADGET_DUALSPEED
        help
          The Samsung S3C64XX USB2.0 high-speed gadget controller
          integrated into the S3C64XX series SoC.
@@ -305,7 +310,6 @@ config USB_S3C2410_DEBUG
 config USB_S3C_HSUDC
        tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
        depends on ARCH_S3C24XX
-       select USB_GADGET_DUALSPEED
        help
          Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
          integrated with dual speed USB 2.0 device controller. It has
@@ -315,7 +319,6 @@ config USB_S3C_HSUDC
 
 config USB_MV_UDC
        tristate "Marvell USB2.0 Device Controller"
-       select USB_GADGET_DUALSPEED
        help
          Marvell Socs (including PXA and MMP series) include a high speed
          USB2.0 OTG controller, which can be configured as high speed or
@@ -338,14 +341,12 @@ config USB_MV_U3D
 config USB_GADGET_MUSB_HDRC
        tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
        depends on USB_MUSB_HDRC
-       select USB_GADGET_DUALSPEED
        help
          This OTG-capable silicon IP is used in dual designs including
          the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 
 config USB_M66592
        tristate "Renesas M66592 USB Peripheral Controller"
-       select USB_GADGET_DUALSPEED
        help
           M66592 is a discrete USB peripheral controller chip that
           supports both full and high speed USB 2.0 data transfers.
@@ -362,7 +363,6 @@ config USB_M66592
 config USB_AMD5536UDC
        tristate "AMD5536 UDC"
        depends on PCI
-       select USB_GADGET_DUALSPEED
        help
           The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
           It is a USB Highspeed DMA capable USB device controller. Beside ep0
@@ -389,7 +389,6 @@ config USB_FSL_QE
 
 config USB_NET2272
        tristate "PLX NET2272"
-       select USB_GADGET_DUALSPEED
        help
          PLX NET2272 is a USB peripheral controller which supports
          both full and high speed USB 2.0 data transfers.
@@ -413,7 +412,6 @@ config USB_NET2272_DMA
 config USB_NET2280
        tristate "NetChip 228x"
        depends on PCI
-       select USB_GADGET_DUALSPEED
        help
           NetChip 2280 / 2282 is a PCI based USB peripheral controller which
           supports both full and high speed USB 2.0 data transfers.
@@ -443,7 +441,6 @@ config USB_GOKU
 config USB_EG20T
        tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
        depends on PCI
-       select USB_GADGET_DUALSPEED
        help
          This is a USB device driver for EG20T PCH.
          EG20T PCH is the platform controller hub that is used in Intel's
@@ -470,8 +467,6 @@ config USB_EG20T
 config USB_DUMMY_HCD
        tristate "Dummy HCD (DEVELOPMENT)"
        depends on USB=y || (USB=m && USB_GADGET=m)
-       select USB_GADGET_DUALSPEED
-       select USB_GADGET_SUPERSPEED
        help
          This host controller driver emulates USB, looping all data transfer
          requests back to a USB "gadget driver" in the same host.  The host
@@ -496,18 +491,15 @@ config USB_DUMMY_HCD
 
 endmenu
 
-# Selected by UDC drivers that support high-speed operation.
-config USB_GADGET_DUALSPEED
-       bool
-
-# Selected by UDC drivers that support super-speed opperation
-config USB_GADGET_SUPERSPEED
-       bool
-       depends on USB_GADGET_DUALSPEED
-
 #
 # USB Gadget Drivers
 #
+
+# composite based drivers
+config USB_LIBCOMPOSITE
+       tristate
+       depends on USB_GADGET
+
 choice
        tristate "USB Gadget Drivers"
        default USB_ETH
@@ -531,6 +523,7 @@ choice
 
 config USB_ZERO
        tristate "Gadget Zero (DEVELOPMENT)"
+       select USB_LIBCOMPOSITE
        help
          Gadget Zero is a two-configuration device.  It either sinks and
          sources bulk data; or it loops back a configurable number of
@@ -566,6 +559,7 @@ config USB_ZERO_HNPTEST
 config USB_AUDIO
        tristate "Audio Gadget (EXPERIMENTAL)"
        depends on SND
+       select USB_LIBCOMPOSITE
        select SND_PCM
        help
          This Gadget Audio driver is compatible with USB Audio Class
@@ -594,6 +588,7 @@ config GADGET_UAC1
 config USB_ETH
        tristate "Ethernet Gadget (with CDC Ethernet support)"
        depends on NET
+       select USB_LIBCOMPOSITE
        select CRC32
        help
          This driver implements Ethernet style communication, in one of
@@ -629,6 +624,7 @@ config USB_ETH
 config USB_ETH_RNDIS
        bool "RNDIS support"
        depends on USB_ETH
+       select USB_LIBCOMPOSITE
        default y
        help
           Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
@@ -647,6 +643,7 @@ config USB_ETH_RNDIS
 config USB_ETH_EEM
        bool "Ethernet Emulation Model (EEM) support"
        depends on USB_ETH
+       select USB_LIBCOMPOSITE
        default n
        help
          CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
@@ -663,6 +660,7 @@ config USB_ETH_EEM
 config USB_G_NCM
        tristate "Network Control Model (NCM) support"
        depends on NET
+       select USB_LIBCOMPOSITE
        select CRC32
        help
          This driver implements USB CDC NCM subclass standard. NCM is
@@ -692,6 +690,7 @@ config USB_GADGETFS
 config USB_FUNCTIONFS
        tristate "Function Filesystem (EXPERIMENTAL)"
        depends on EXPERIMENTAL
+       select USB_LIBCOMPOSITE
        select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
        help
          The Function Filesystem (FunctionFS) lets one create USB
@@ -755,6 +754,7 @@ config USB_FILE_STORAGE_TEST
 config USB_MASS_STORAGE
        tristate "Mass Storage Gadget"
        depends on BLOCK
+       select USB_LIBCOMPOSITE
        help
          The Mass Storage Gadget acts as a USB Mass Storage disk drive.
          As its storage repository it can use a regular file or a block
@@ -770,6 +770,7 @@ config USB_MASS_STORAGE
 config USB_GADGET_TARGET
        tristate "USB Gadget Target Fabric Module"
        depends on TARGET_CORE
+       select USB_LIBCOMPOSITE
        help
          This fabric is an USB gadget. Two USB protocols are supported that is
          BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
@@ -779,6 +780,7 @@ config USB_GADGET_TARGET
 
 config USB_G_SERIAL
        tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
+       select USB_LIBCOMPOSITE
        help
          The Serial Gadget talks to the Linux-USB generic serial driver.
          This driver supports a CDC-ACM module option, which can be used
@@ -799,6 +801,7 @@ config USB_G_SERIAL
 config USB_MIDI_GADGET
        tristate "MIDI Gadget (EXPERIMENTAL)"
        depends on SND && EXPERIMENTAL
+       select USB_LIBCOMPOSITE
        select SND_RAWMIDI
        help
          The MIDI Gadget acts as a USB Audio device, with one MIDI
@@ -812,6 +815,7 @@ config USB_MIDI_GADGET
 
 config USB_G_PRINTER
        tristate "Printer Gadget"
+       select USB_LIBCOMPOSITE
        help
          The Printer Gadget channels data between the USB host and a
          userspace program driving the print engine. The user space
@@ -828,6 +832,7 @@ config USB_G_PRINTER
 config USB_CDC_COMPOSITE
        tristate "CDC Composite Device (Ethernet and ACM)"
        depends on NET
+       select USB_LIBCOMPOSITE
        help
          This driver provides two functions in one configuration:
          a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
@@ -842,6 +847,7 @@ config USB_CDC_COMPOSITE
 config USB_G_NOKIA
        tristate "Nokia composite gadget"
        depends on PHONET
+       select USB_LIBCOMPOSITE
        help
          The Nokia composite gadget provides support for acm, obex
          and phonet in only one composite gadget driver.
@@ -852,6 +858,7 @@ config USB_G_NOKIA
 config USB_G_ACM_MS
        tristate "CDC Composite Device (ACM and mass storage)"
        depends on BLOCK
+       select USB_LIBCOMPOSITE
        help
          This driver provides two functions in one configuration:
          a mass storage, and a CDC ACM (serial port) link.
@@ -863,6 +870,7 @@ config USB_G_MULTI
        tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
        depends on BLOCK && NET
        select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
+       select USB_LIBCOMPOSITE
        help
          The Multifunction Composite Gadget provides Ethernet (RNDIS
          and/or CDC Ethernet), mass storage and ACM serial link
@@ -903,6 +911,7 @@ config USB_G_MULTI_CDC
 
 config USB_G_HID
        tristate "HID Gadget"
+       select USB_LIBCOMPOSITE
        help
          The HID gadget driver provides generic emulation of USB
          Human Interface Devices (HID).
@@ -913,8 +922,10 @@ config USB_G_HID
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_hid".
 
+# Standalone / single function gadgets
 config USB_G_DBGP
        tristate "EHCI Debug Device Gadget"
+       select USB_LIBCOMPOSITE
        help
          This gadget emulates an EHCI Debug device. This is useful when you want
          to interact with an EHCI Debug Port.
index 3fd8cd09d2c18e9f04797fad829e4984d27e2ced..307be5fa824cf98e3d71001863a74a5fd03139f8 100644 (file)
@@ -4,6 +4,9 @@
 ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_USB_GADGET)       += udc-core.o
+obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
+libcomposite-y                 := usbstring.o config.o epautoconf.o
+libcomposite-y                 += composite.o
 obj-$(CONFIG_USB_DUMMY_HCD)    += dummy_hcd.o
 obj-$(CONFIG_USB_NET2272)      += net2272.o
 obj-$(CONFIG_USB_NET2280)      += net2280.o
@@ -16,6 +19,7 @@ obj-$(CONFIG_USB_OMAP)                += omap_udc.o
 obj-$(CONFIG_USB_S3C2410)      += s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)         += at91_udc.o
 obj-$(CONFIG_USB_ATMEL_USBA)   += atmel_usba_udc.o
+obj-$(CONFIG_USB_BCM63XX_UDC)  += bcm63xx_udc.o
 obj-$(CONFIG_USB_FSL_USB2)     += fsl_usb2_udc.o
 fsl_usb2_udc-y                 := fsl_udc_core.o
 fsl_usb2_udc-$(CONFIG_ARCH_MXC)        += fsl_mxc_udc.o
index 75b8a691fd0036154897ab530074027099b17bc8..5a7f289805ff2f8956cd7a4d1fa99753d1e5a238 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
+#include <linux/module.h>
 
 #include "u_serial.h"
 
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
 
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "u_serial.c"
 #include "f_acm.c"
 #include "f_mass_storage.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor device_desc = {
        .bLength =              sizeof device_desc,
@@ -89,17 +86,11 @@ static const struct usb_descriptor_header *otg_desc[] = {
        NULL,
 };
 
-
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        {  } /* end of list */
 };
 
@@ -157,7 +148,6 @@ static struct usb_configuration acm_ms_config_driver = {
 
 static int __init acm_ms_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
        void                    *retp;
@@ -174,44 +164,22 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
                goto fail0;
        }
 
-       /* set bcdDevice */
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0) {
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       } else {
-               WARNING(cdev, "controller '%s' not recognized; trying %s\n",
-                               gadget->name,
-                               acm_ms_config_driver.label);
-               device_desc.bcdDevice =
-                       cpu_to_le16(0x0300 | 0x0099);
-       }
-
        /*
         * Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
-
-       /* device descriptor strings: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail1;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto fail1;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        /* register our configuration */
        status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
        if (status < 0)
                goto fail1;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
                        DRIVER_DESC);
        fsg_common_put(&fsg_common);
@@ -232,11 +200,12 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver acm_ms_driver = {
+static __refdata struct usb_composite_driver acm_ms_driver = {
        .name           = "g_acm_ms",
        .dev            = &device_desc,
        .max_speed      = USB_SPEED_SUPER,
        .strings        = dev_strings,
+       .bind           = acm_ms_bind,
        .unbind         = __exit_p(acm_ms_unbind),
 };
 
@@ -246,7 +215,7 @@ MODULE_LICENSE("GPL v2");
 
 static int __init init(void)
 {
-       return usb_composite_probe(&acm_ms_driver, acm_ms_bind);
+       return usb_composite_probe(&acm_ms_driver);
 }
 module_init(init);
 
index 187d21181cd5f85d6b23627bfbabb56af0301c2b..fc0ec5e0d58ef43a11f525148dca69d1cb442188 100644 (file)
@@ -1401,7 +1401,7 @@ static int udc_wakeup(struct usb_gadget *gadget)
 }
 
 static int amd5536_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int amd5536_stop(struct usb_gadget_driver *driver);
 /* gadget operations */
 static const struct usb_gadget_ops udc_ops = {
@@ -1914,7 +1914,7 @@ static int setup_ep0(struct udc *dev)
 
 /* Called by gadget driver to register itself */
 static int amd5536_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct udc              *dev = udc;
        int                     retval;
@@ -1932,7 +1932,7 @@ static int amd5536_start(struct usb_gadget_driver *driver,
        dev->driver = driver;
        dev->gadget.dev.driver = &driver->driver;
 
-       retval = bind(&dev->gadget);
+       retval = bind(&dev->gadget, driver);
 
        /* Some gadget drivers use both ep0 directions.
         * NOTE: to gadget driver, ep0 is just one endpoint...
index c9e66dfb02e6642c1e88149884857948b44869e8..af931282843d3e206695d51827f469ac81e31794 100644 (file)
@@ -469,7 +469,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
                                const struct usb_endpoint_descriptor *desc)
 {
        struct at91_ep  *ep = container_of(_ep, struct at91_ep, ep);
-       struct at91_udc *udc = ep->udc;
+       struct at91_udc *udc;
        u16             maxpacket;
        u32             tmp;
        unsigned long   flags;
@@ -484,6 +484,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
                return -EINVAL;
        }
 
+       udc = ep->udc;
        if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
                DBG("bogus device state\n");
                return -ESHUTDOWN;
@@ -1703,7 +1704,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
        int             retval;
        struct resource *res;
 
-       if (!dev->platform_data) {
+       if (!dev->platform_data && !pdev->dev.of_node) {
                /* small (so we copy it) but critical! */
                DBG("missing platform_data\n");
                return -ENODEV;
index 98899244860ecce46d86bd7592b779e9534afe94..231b0efe8fdc12704f596e84c7fbab8f86e9aee7 100644 (file)
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
 
+#include "gadget_chips.h"
 #define DRIVER_DESC            "Linux USB Audio Gadget"
 #define DRIVER_VERSION         "Feb 2, 2012"
 
-/*-------------------------------------------------------------------------*/
-
-/*
- * 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 "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        {  } /* end of list */
 };
 
@@ -149,39 +135,18 @@ static struct usb_configuration audio_config_driver = {
 
 static int __init audio_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
        int                     status;
 
-       gcnum = usb_gadget_controller_number(cdev->gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       else {
-               ERROR(cdev, "controller '%s' not recognized; trying %s\n",
-                       cdev->gadget->name,
-                       audio_config_driver.label);
-               device_desc.bcdDevice =
-                       __constant_cpu_to_le16(0x0300 | 0x0099);
-       }
-
-       /* device descriptor strings: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               cdev->gadget->name);
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto fail;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
        if (status < 0)
                goto fail;
+       usb_composite_overwrite_options(cdev, &coverwrite);
 
        INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
        return 0;
@@ -198,17 +163,18 @@ static int __exit audio_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver audio_driver = {
+static __refdata struct usb_composite_driver audio_driver = {
        .name           = "g_audio",
        .dev            = &device_desc,
        .strings        = audio_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = audio_bind,
        .unbind         = __exit_p(audio_unbind),
 };
 
 static int __init init(void)
 {
-       return usb_composite_probe(&audio_driver, audio_bind);
+       return usb_composite_probe(&audio_driver);
 }
 module_init(init);
 
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
new file mode 100644 (file)
index 0000000..9ca7922
--- /dev/null
@@ -0,0 +1,2464 @@
+/*
+ * bcm63xx_udc.c -- BCM63xx UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
+ * Copyright (C) 2012 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/workqueue.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_iudma.h>
+#include <bcm63xx_dev_usb_usbd.h>
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+#define DRV_MODULE_NAME                "bcm63xx_udc"
+
+static const char bcm63xx_ep0name[] = "ep0";
+static const char *const bcm63xx_ep_name[] = {
+       bcm63xx_ep0name,
+       "ep1in-bulk", "ep2out-bulk", "ep3in-int", "ep4out-int",
+};
+
+static bool use_fullspeed;
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*
+ * RX IRQ coalescing options:
+ *
+ * false (default) - one IRQ per DATAx packet.  Slow but reliable.  The
+ * driver is able to pass the "testusb" suite and recover from conditions like:
+ *
+ *   1) Device queues up a 2048-byte RX IUDMA transaction on an OUT bulk ep
+ *   2) Host sends 512 bytes of data
+ *   3) Host decides to reconfigure the device and sends SET_INTERFACE
+ *   4) Device shuts down the endpoint and cancels the RX transaction
+ *
+ * true - one IRQ per transfer, for transfers <= 2048B.  Generates
+ * considerably fewer IRQs, but error recovery is less robust.  Does not
+ * reliably pass "testusb".
+ *
+ * TX always uses coalescing, because we can cancel partially complete TX
+ * transfers by repeatedly flushing the FIFO.  The hardware doesn't allow
+ * this on RX.
+ */
+static bool irq_coalesce;
+module_param(irq_coalesce, bool, S_IRUGO);
+MODULE_PARM_DESC(irq_coalesce, "take one IRQ per RX transfer");
+
+#define BCM63XX_NUM_EP                 5
+#define BCM63XX_NUM_IUDMA              6
+#define BCM63XX_NUM_FIFO_PAIRS         3
+
+#define IUDMA_RESET_TIMEOUT_US         10000
+
+#define IUDMA_EP0_RXCHAN               0
+#define IUDMA_EP0_TXCHAN               1
+
+#define IUDMA_MAX_FRAGMENT             2048
+#define BCM63XX_MAX_CTRL_PKT           64
+
+#define BCMEP_CTRL                     0x00
+#define BCMEP_ISOC                     0x01
+#define BCMEP_BULK                     0x02
+#define BCMEP_INTR                     0x03
+
+#define BCMEP_OUT                      0x00
+#define BCMEP_IN                       0x01
+
+#define BCM63XX_SPD_FULL               1
+#define BCM63XX_SPD_HIGH               0
+
+#define IUDMA_DMAC_OFFSET              0x200
+#define IUDMA_DMAS_OFFSET              0x400
+
+enum bcm63xx_ep0_state {
+       EP0_REQUEUE,
+       EP0_IDLE,
+       EP0_IN_DATA_PHASE_SETUP,
+       EP0_IN_DATA_PHASE_COMPLETE,
+       EP0_OUT_DATA_PHASE_SETUP,
+       EP0_OUT_DATA_PHASE_COMPLETE,
+       EP0_OUT_STATUS_PHASE,
+       EP0_IN_FAKE_STATUS_PHASE,
+       EP0_SHUTDOWN,
+};
+
+static const char __maybe_unused bcm63xx_ep0_state_names[][32] = {
+       "REQUEUE",
+       "IDLE",
+       "IN_DATA_PHASE_SETUP",
+       "IN_DATA_PHASE_COMPLETE",
+       "OUT_DATA_PHASE_SETUP",
+       "OUT_DATA_PHASE_COMPLETE",
+       "OUT_STATUS_PHASE",
+       "IN_FAKE_STATUS_PHASE",
+       "SHUTDOWN",
+};
+
+/**
+ * struct iudma_ch_cfg - Static configuration for an IUDMA channel.
+ * @ep_num: USB endpoint number.
+ * @n_bds: Number of buffer descriptors in the ring.
+ * @ep_type: Endpoint type (control, bulk, interrupt).
+ * @dir: Direction (in, out).
+ * @n_fifo_slots: Number of FIFO entries to allocate for this channel.
+ * @max_pkt_hs: Maximum packet size in high speed mode.
+ * @max_pkt_fs: Maximum packet size in full speed mode.
+ */
+struct iudma_ch_cfg {
+       int                             ep_num;
+       int                             n_bds;
+       int                             ep_type;
+       int                             dir;
+       int                             n_fifo_slots;
+       int                             max_pkt_hs;
+       int                             max_pkt_fs;
+};
+
+static const struct iudma_ch_cfg iudma_defaults[] = {
+
+       /* This controller was designed to support a CDC/RNDIS application.
+          It may be possible to reconfigure some of the endpoints, but
+          the hardware limitations (FIFO sizing and number of DMA channels)
+          may significantly impact flexibility and/or stability.  Change
+          these values at your own risk.
+
+             ep_num       ep_type           n_fifo_slots    max_pkt_fs
+       idx      |  n_bds     |         dir       |  max_pkt_hs  |
+        |       |    |       |          |        |      |       |       */
+       [0] = { -1,   4, BCMEP_CTRL, BCMEP_OUT,  32,    64,     64 },
+       [1] = {  0,   4, BCMEP_CTRL, BCMEP_OUT,  32,    64,     64 },
+       [2] = {  2,  16, BCMEP_BULK, BCMEP_OUT, 128,   512,     64 },
+       [3] = {  1,  16, BCMEP_BULK, BCMEP_IN,  128,   512,     64 },
+       [4] = {  4,   4, BCMEP_INTR, BCMEP_OUT,  32,    64,     64 },
+       [5] = {  3,   4, BCMEP_INTR, BCMEP_IN,   32,    64,     64 },
+};
+
+struct bcm63xx_udc;
+
+/**
+ * struct iudma_ch - Represents the current state of a single IUDMA channel.
+ * @ch_idx: IUDMA channel index (0 to BCM63XX_NUM_IUDMA-1).
+ * @ep_num: USB endpoint number.  -1 for ep0 RX.
+ * @enabled: Whether bcm63xx_ep_enable() has been called.
+ * @max_pkt: "Chunk size" on the USB interface.  Based on interface speed.
+ * @is_tx: true for TX, false for RX.
+ * @bep: Pointer to the associated endpoint.  NULL for ep0 RX.
+ * @udc: Reference to the device controller.
+ * @read_bd: Next buffer descriptor to reap from the hardware.
+ * @write_bd: Next BD available for a new packet.
+ * @end_bd: Points to the final BD in the ring.
+ * @n_bds_used: Number of BD entries currently occupied.
+ * @bd_ring: Base pointer to the BD ring.
+ * @bd_ring_dma: Physical (DMA) address of bd_ring.
+ * @n_bds: Total number of BDs in the ring.
+ *
+ * ep0 has two IUDMA channels (IUDMA_EP0_RXCHAN and IUDMA_EP0_TXCHAN), as it is
+ * bidirectional.  The "struct usb_ep" associated with ep0 is for TX (IN)
+ * only.
+ *
+ * Each bulk/intr endpoint has a single IUDMA channel and a single
+ * struct usb_ep.
+ */
+struct iudma_ch {
+       unsigned int                    ch_idx;
+       int                             ep_num;
+       bool                            enabled;
+       int                             max_pkt;
+       bool                            is_tx;
+       struct bcm63xx_ep               *bep;
+       struct bcm63xx_udc              *udc;
+
+       struct bcm_enet_desc            *read_bd;
+       struct bcm_enet_desc            *write_bd;
+       struct bcm_enet_desc            *end_bd;
+       int                             n_bds_used;
+
+       struct bcm_enet_desc            *bd_ring;
+       dma_addr_t                      bd_ring_dma;
+       unsigned int                    n_bds;
+};
+
+/**
+ * struct bcm63xx_ep - Internal (driver) state of a single endpoint.
+ * @ep_num: USB endpoint number.
+ * @iudma: Pointer to IUDMA channel state.
+ * @ep: USB gadget layer representation of the EP.
+ * @udc: Reference to the device controller.
+ * @queue: Linked list of outstanding requests for this EP.
+ * @halted: 1 if the EP is stalled; 0 otherwise.
+ */
+struct bcm63xx_ep {
+       unsigned int                    ep_num;
+       struct iudma_ch                 *iudma;
+       struct usb_ep                   ep;
+       struct bcm63xx_udc              *udc;
+       struct list_head                queue;
+       unsigned                        halted:1;
+};
+
+/**
+ * struct bcm63xx_req - Internal (driver) state of a single request.
+ * @queue: Links back to the EP's request list.
+ * @req: USB gadget layer representation of the request.
+ * @offset: Current byte offset into the data buffer (next byte to queue).
+ * @bd_bytes: Number of data bytes in outstanding BD entries.
+ * @iudma: IUDMA channel used for the request.
+ */
+struct bcm63xx_req {
+       struct list_head                queue;          /* ep's requests */
+       struct usb_request              req;
+       unsigned int                    offset;
+       unsigned int                    bd_bytes;
+       struct iudma_ch                 *iudma;
+};
+
+/**
+ * struct bcm63xx_udc - Driver/hardware private context.
+ * @lock: Spinlock to mediate access to this struct, and (most) HW regs.
+ * @dev: Generic Linux device structure.
+ * @pd: Platform data (board/port info).
+ * @usbd_clk: Clock descriptor for the USB device block.
+ * @usbh_clk: Clock descriptor for the USB host block.
+ * @gadget: USB slave device.
+ * @driver: Driver for USB slave devices.
+ * @usbd_regs: Base address of the USBD/USB20D block.
+ * @iudma_regs: Base address of the USBD's associated IUDMA block.
+ * @bep: Array of endpoints, including ep0.
+ * @iudma: Array of all IUDMA channels used by this controller.
+ * @cfg: USB configuration number, from SET_CONFIGURATION wValue.
+ * @iface: USB interface number, from SET_INTERFACE wIndex.
+ * @alt_iface: USB alt interface number, from SET_INTERFACE wValue.
+ * @ep0_ctrl_req: Request object for bcm63xx_udc-initiated ep0 transactions.
+ * @ep0_ctrl_buf: Data buffer for ep0_ctrl_req.
+ * @ep0state: Current state of the ep0 state machine.
+ * @ep0_wq: Workqueue struct used to wake up the ep0 state machine.
+ * @wedgemap: Bitmap of wedged endpoints.
+ * @ep0_req_reset: USB reset is pending.
+ * @ep0_req_set_cfg: Need to spoof a SET_CONFIGURATION packet.
+ * @ep0_req_set_iface: Need to spoof a SET_INTERFACE packet.
+ * @ep0_req_shutdown: Driver is shutting down; requesting ep0 to halt activity.
+ * @ep0_req_completed: ep0 request has completed; worker has not seen it yet.
+ * @ep0_reply: Pending reply from gadget driver.
+ * @ep0_request: Outstanding ep0 request.
+ * @debugfs_root: debugfs directory: /sys/kernel/debug/<DRV_MODULE_NAME>.
+ * @debugfs_usbd: debugfs file "usbd" for controller state.
+ * @debugfs_iudma: debugfs file "usbd" for IUDMA state.
+ */
+struct bcm63xx_udc {
+       spinlock_t                      lock;
+
+       struct device                   *dev;
+       struct bcm63xx_usbd_platform_data *pd;
+       struct clk                      *usbd_clk;
+       struct clk                      *usbh_clk;
+
+       struct usb_gadget               gadget;
+       struct usb_gadget_driver        *driver;
+
+       void __iomem                    *usbd_regs;
+       void __iomem                    *iudma_regs;
+
+       struct bcm63xx_ep               bep[BCM63XX_NUM_EP];
+       struct iudma_ch                 iudma[BCM63XX_NUM_IUDMA];
+
+       int                             cfg;
+       int                             iface;
+       int                             alt_iface;
+
+       struct bcm63xx_req              ep0_ctrl_req;
+       u8                              *ep0_ctrl_buf;
+
+       int                             ep0state;
+       struct work_struct              ep0_wq;
+
+       unsigned long                   wedgemap;
+
+       unsigned                        ep0_req_reset:1;
+       unsigned                        ep0_req_set_cfg:1;
+       unsigned                        ep0_req_set_iface:1;
+       unsigned                        ep0_req_shutdown:1;
+
+       unsigned                        ep0_req_completed:1;
+       struct usb_request              *ep0_reply;
+       struct usb_request              *ep0_request;
+
+       struct dentry                   *debugfs_root;
+       struct dentry                   *debugfs_usbd;
+       struct dentry                   *debugfs_iudma;
+};
+
+static const struct usb_ep_ops bcm63xx_udc_ep_ops;
+
+/***********************************************************************
+ * Convenience functions
+ ***********************************************************************/
+
+static inline struct bcm63xx_udc *gadget_to_udc(struct usb_gadget *g)
+{
+       return container_of(g, struct bcm63xx_udc, gadget);
+}
+
+static inline struct bcm63xx_ep *our_ep(struct usb_ep *ep)
+{
+       return container_of(ep, struct bcm63xx_ep, ep);
+}
+
+static inline struct bcm63xx_req *our_req(struct usb_request *req)
+{
+       return container_of(req, struct bcm63xx_req, req);
+}
+
+static inline u32 usbd_readl(struct bcm63xx_udc *udc, u32 off)
+{
+       return bcm_readl(udc->usbd_regs + off);
+}
+
+static inline void usbd_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+       bcm_writel(val, udc->usbd_regs + off);
+}
+
+static inline u32 usb_dma_readl(struct bcm63xx_udc *udc, u32 off)
+{
+       return bcm_readl(udc->iudma_regs + off);
+}
+
+static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+       bcm_writel(val, udc->iudma_regs + off);
+}
+
+static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off)
+{
+       return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+}
+
+static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+       bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+}
+
+static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off)
+{
+       return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+}
+
+static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+{
+       bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+}
+
+static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled)
+{
+       if (is_enabled) {
+               clk_enable(udc->usbh_clk);
+               clk_enable(udc->usbd_clk);
+               udelay(10);
+       } else {
+               clk_disable(udc->usbd_clk);
+               clk_disable(udc->usbh_clk);
+       }
+}
+
+/***********************************************************************
+ * Low-level IUDMA / FIFO operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_ep_dma_select - Helper function to set up the init_sel signal.
+ * @udc: Reference to the device controller.
+ * @idx: Desired init_sel value.
+ *
+ * The "init_sel" signal is used as a selection index for both endpoints
+ * and IUDMA channels.  Since these do not map 1:1, the use of this signal
+ * depends on the context.
+ */
+static void bcm63xx_ep_dma_select(struct bcm63xx_udc *udc, int idx)
+{
+       u32 val = usbd_readl(udc, USBD_CONTROL_REG);
+
+       val &= ~USBD_CONTROL_INIT_SEL_MASK;
+       val |= idx << USBD_CONTROL_INIT_SEL_SHIFT;
+       usbd_writel(udc, val, USBD_CONTROL_REG);
+}
+
+/**
+ * bcm63xx_set_stall - Enable/disable stall on one endpoint.
+ * @udc: Reference to the device controller.
+ * @bep: Endpoint on which to operate.
+ * @is_stalled: true to enable stall, false to disable.
+ *
+ * See notes in bcm63xx_update_wedge() regarding automatic clearing of
+ * halt/stall conditions.
+ */
+static void bcm63xx_set_stall(struct bcm63xx_udc *udc, struct bcm63xx_ep *bep,
+       bool is_stalled)
+{
+       u32 val;
+
+       val = USBD_STALL_UPDATE_MASK |
+               (is_stalled ? USBD_STALL_ENABLE_MASK : 0) |
+               (bep->ep_num << USBD_STALL_EPNUM_SHIFT);
+       usbd_writel(udc, val, USBD_STALL_REG);
+}
+
+/**
+ * bcm63xx_fifo_setup - (Re)initialize FIFO boundaries and settings.
+ * @udc: Reference to the device controller.
+ *
+ * These parameters depend on the USB link speed.  Settings are
+ * per-IUDMA-channel-pair.
+ */
+static void bcm63xx_fifo_setup(struct bcm63xx_udc *udc)
+{
+       int is_hs = udc->gadget.speed == USB_SPEED_HIGH;
+       u32 i, val, rx_fifo_slot, tx_fifo_slot;
+
+       /* set up FIFO boundaries and packet sizes; this is done in pairs */
+       rx_fifo_slot = tx_fifo_slot = 0;
+       for (i = 0; i < BCM63XX_NUM_IUDMA; i += 2) {
+               const struct iudma_ch_cfg *rx_cfg = &iudma_defaults[i];
+               const struct iudma_ch_cfg *tx_cfg = &iudma_defaults[i + 1];
+
+               bcm63xx_ep_dma_select(udc, i >> 1);
+
+               val = (rx_fifo_slot << USBD_RXFIFO_CONFIG_START_SHIFT) |
+                       ((rx_fifo_slot + rx_cfg->n_fifo_slots - 1) <<
+                        USBD_RXFIFO_CONFIG_END_SHIFT);
+               rx_fifo_slot += rx_cfg->n_fifo_slots;
+               usbd_writel(udc, val, USBD_RXFIFO_CONFIG_REG);
+               usbd_writel(udc,
+                           is_hs ? rx_cfg->max_pkt_hs : rx_cfg->max_pkt_fs,
+                           USBD_RXFIFO_EPSIZE_REG);
+
+               val = (tx_fifo_slot << USBD_TXFIFO_CONFIG_START_SHIFT) |
+                       ((tx_fifo_slot + tx_cfg->n_fifo_slots - 1) <<
+                        USBD_TXFIFO_CONFIG_END_SHIFT);
+               tx_fifo_slot += tx_cfg->n_fifo_slots;
+               usbd_writel(udc, val, USBD_TXFIFO_CONFIG_REG);
+               usbd_writel(udc,
+                           is_hs ? tx_cfg->max_pkt_hs : tx_cfg->max_pkt_fs,
+                           USBD_TXFIFO_EPSIZE_REG);
+
+               usbd_readl(udc, USBD_TXFIFO_EPSIZE_REG);
+       }
+}
+
+/**
+ * bcm63xx_fifo_reset_ep - Flush a single endpoint's FIFO.
+ * @udc: Reference to the device controller.
+ * @ep_num: Endpoint number.
+ */
+static void bcm63xx_fifo_reset_ep(struct bcm63xx_udc *udc, int ep_num)
+{
+       u32 val;
+
+       bcm63xx_ep_dma_select(udc, ep_num);
+
+       val = usbd_readl(udc, USBD_CONTROL_REG);
+       val |= USBD_CONTROL_FIFO_RESET_MASK;
+       usbd_writel(udc, val, USBD_CONTROL_REG);
+       usbd_readl(udc, USBD_CONTROL_REG);
+}
+
+/**
+ * bcm63xx_fifo_reset - Flush all hardware FIFOs.
+ * @udc: Reference to the device controller.
+ */
+static void bcm63xx_fifo_reset(struct bcm63xx_udc *udc)
+{
+       int i;
+
+       for (i = 0; i < BCM63XX_NUM_FIFO_PAIRS; i++)
+               bcm63xx_fifo_reset_ep(udc, i);
+}
+
+/**
+ * bcm63xx_ep_init - Initial (one-time) endpoint initialization.
+ * @udc: Reference to the device controller.
+ */
+static void bcm63xx_ep_init(struct bcm63xx_udc *udc)
+{
+       u32 i, val;
+
+       for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+               const struct iudma_ch_cfg *cfg = &iudma_defaults[i];
+
+               if (cfg->ep_num < 0)
+                       continue;
+
+               bcm63xx_ep_dma_select(udc, cfg->ep_num);
+               val = (cfg->ep_type << USBD_EPNUM_TYPEMAP_TYPE_SHIFT) |
+                       ((i >> 1) << USBD_EPNUM_TYPEMAP_DMA_CH_SHIFT);
+               usbd_writel(udc, val, USBD_EPNUM_TYPEMAP_REG);
+       }
+}
+
+/**
+ * bcm63xx_ep_setup - Configure per-endpoint settings.
+ * @udc: Reference to the device controller.
+ *
+ * This needs to be rerun if the speed/cfg/intf/altintf changes.
+ */
+static void bcm63xx_ep_setup(struct bcm63xx_udc *udc)
+{
+       u32 val, i;
+
+       usbd_writel(udc, USBD_CSR_SETUPADDR_DEF, USBD_CSR_SETUPADDR_REG);
+
+       for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+               const struct iudma_ch_cfg *cfg = &iudma_defaults[i];
+               int max_pkt = udc->gadget.speed == USB_SPEED_HIGH ?
+                             cfg->max_pkt_hs : cfg->max_pkt_fs;
+               int idx = cfg->ep_num;
+
+               udc->iudma[i].max_pkt = max_pkt;
+
+               if (idx < 0)
+                       continue;
+               udc->bep[idx].ep.maxpacket = max_pkt;
+
+               val = (idx << USBD_CSR_EP_LOG_SHIFT) |
+                     (cfg->dir << USBD_CSR_EP_DIR_SHIFT) |
+                     (cfg->ep_type << USBD_CSR_EP_TYPE_SHIFT) |
+                     (udc->cfg << USBD_CSR_EP_CFG_SHIFT) |
+                     (udc->iface << USBD_CSR_EP_IFACE_SHIFT) |
+                     (udc->alt_iface << USBD_CSR_EP_ALTIFACE_SHIFT) |
+                     (max_pkt << USBD_CSR_EP_MAXPKT_SHIFT);
+               usbd_writel(udc, val, USBD_CSR_EP_REG(idx));
+       }
+}
+
+/**
+ * iudma_write - Queue a single IUDMA transaction.
+ * @udc: Reference to the device controller.
+ * @iudma: IUDMA channel to use.
+ * @breq: Request containing the transaction data.
+ *
+ * For RX IUDMA, this will queue a single buffer descriptor, as RX IUDMA
+ * does not honor SOP/EOP so the handling of multiple buffers is ambiguous.
+ * So iudma_write() may be called several times to fulfill a single
+ * usb_request.
+ *
+ * For TX IUDMA, this can queue multiple buffer descriptors if needed.
+ */
+static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,
+       struct bcm63xx_req *breq)
+{
+       int first_bd = 1, last_bd = 0, extra_zero_pkt = 0;
+       unsigned int bytes_left = breq->req.length - breq->offset;
+       const int max_bd_bytes = !irq_coalesce && !iudma->is_tx ?
+               iudma->max_pkt : IUDMA_MAX_FRAGMENT;
+
+       iudma->n_bds_used = 0;
+       breq->bd_bytes = 0;
+       breq->iudma = iudma;
+
+       if ((bytes_left % iudma->max_pkt == 0) && bytes_left && breq->req.zero)
+               extra_zero_pkt = 1;
+
+       do {
+               struct bcm_enet_desc *d = iudma->write_bd;
+               u32 dmaflags = 0;
+               unsigned int n_bytes;
+
+               if (d == iudma->end_bd) {
+                       dmaflags |= DMADESC_WRAP_MASK;
+                       iudma->write_bd = iudma->bd_ring;
+               } else {
+                       iudma->write_bd++;
+               }
+               iudma->n_bds_used++;
+
+               n_bytes = min_t(int, bytes_left, max_bd_bytes);
+               if (n_bytes)
+                       dmaflags |= n_bytes << DMADESC_LENGTH_SHIFT;
+               else
+                       dmaflags |= (1 << DMADESC_LENGTH_SHIFT) |
+                                   DMADESC_USB_ZERO_MASK;
+
+               dmaflags |= DMADESC_OWNER_MASK;
+               if (first_bd) {
+                       dmaflags |= DMADESC_SOP_MASK;
+                       first_bd = 0;
+               }
+
+               /*
+                * extra_zero_pkt forces one more iteration through the loop
+                * after all data is queued up, to send the zero packet
+                */
+               if (extra_zero_pkt && !bytes_left)
+                       extra_zero_pkt = 0;
+
+               if (!iudma->is_tx || iudma->n_bds_used == iudma->n_bds ||
+                   (n_bytes == bytes_left && !extra_zero_pkt)) {
+                       last_bd = 1;
+                       dmaflags |= DMADESC_EOP_MASK;
+               }
+
+               d->address = breq->req.dma + breq->offset;
+               mb();
+               d->len_stat = dmaflags;
+
+               breq->offset += n_bytes;
+               breq->bd_bytes += n_bytes;
+               bytes_left -= n_bytes;
+       } while (!last_bd);
+
+       usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK,
+                       ENETDMAC_CHANCFG_REG(iudma->ch_idx));
+}
+
+/**
+ * iudma_read - Check for IUDMA buffer completion.
+ * @udc: Reference to the device controller.
+ * @iudma: IUDMA channel to use.
+ *
+ * This checks to see if ALL of the outstanding BDs on the DMA channel
+ * have been filled.  If so, it returns the actual transfer length;
+ * otherwise it returns -EBUSY.
+ */
+static int iudma_read(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
+{
+       int i, actual_len = 0;
+       struct bcm_enet_desc *d = iudma->read_bd;
+
+       if (!iudma->n_bds_used)
+               return -EINVAL;
+
+       for (i = 0; i < iudma->n_bds_used; i++) {
+               u32 dmaflags;
+
+               dmaflags = d->len_stat;
+
+               if (dmaflags & DMADESC_OWNER_MASK)
+                       return -EBUSY;
+
+               actual_len += (dmaflags & DMADESC_LENGTH_MASK) >>
+                             DMADESC_LENGTH_SHIFT;
+               if (d == iudma->end_bd)
+                       d = iudma->bd_ring;
+               else
+                       d++;
+       }
+
+       iudma->read_bd = d;
+       iudma->n_bds_used = 0;
+       return actual_len;
+}
+
+/**
+ * iudma_reset_channel - Stop DMA on a single channel.
+ * @udc: Reference to the device controller.
+ * @iudma: IUDMA channel to reset.
+ */
+static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
+{
+       int timeout = IUDMA_RESET_TIMEOUT_US;
+       struct bcm_enet_desc *d;
+       int ch_idx = iudma->ch_idx;
+
+       if (!iudma->is_tx)
+               bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));
+
+       /* stop DMA, then wait for the hardware to wrap up */
+       usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx));
+
+       while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) &
+                                  ENETDMAC_CHANCFG_EN_MASK) {
+               udelay(1);
+
+               /* repeatedly flush the FIFO data until the BD completes */
+               if (iudma->is_tx && iudma->ep_num >= 0)
+                       bcm63xx_fifo_reset_ep(udc, iudma->ep_num);
+
+               if (!timeout--) {
+                       dev_err(udc->dev, "can't reset IUDMA channel %d\n",
+                               ch_idx);
+                       break;
+               }
+               if (timeout == IUDMA_RESET_TIMEOUT_US / 2) {
+                       dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",
+                                ch_idx);
+                       usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK,
+                                       ENETDMAC_CHANCFG_REG(ch_idx));
+               }
+       }
+       usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx));
+
+       /* don't leave "live" HW-owned entries for the next guy to step on */
+       for (d = iudma->bd_ring; d <= iudma->end_bd; d++)
+               d->len_stat = 0;
+       mb();
+
+       iudma->read_bd = iudma->write_bd = iudma->bd_ring;
+       iudma->n_bds_used = 0;
+
+       /* set up IRQs, UBUS burst size, and BD base for this channel */
+       usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
+                       ENETDMAC_IRMASK_REG(ch_idx));
+       usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx));
+
+       usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx));
+       usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx));
+}
+
+/**
+ * iudma_init_channel - One-time IUDMA channel initialization.
+ * @udc: Reference to the device controller.
+ * @ch_idx: Channel to initialize.
+ */
+static int iudma_init_channel(struct bcm63xx_udc *udc, unsigned int ch_idx)
+{
+       struct iudma_ch *iudma = &udc->iudma[ch_idx];
+       const struct iudma_ch_cfg *cfg = &iudma_defaults[ch_idx];
+       unsigned int n_bds = cfg->n_bds;
+       struct bcm63xx_ep *bep = NULL;
+
+       iudma->ep_num = cfg->ep_num;
+       iudma->ch_idx = ch_idx;
+       iudma->is_tx = !!(ch_idx & 0x01);
+       if (iudma->ep_num >= 0) {
+               bep = &udc->bep[iudma->ep_num];
+               bep->iudma = iudma;
+               INIT_LIST_HEAD(&bep->queue);
+       }
+
+       iudma->bep = bep;
+       iudma->udc = udc;
+
+       /* ep0 is always active; others are controlled by the gadget driver */
+       if (iudma->ep_num <= 0)
+               iudma->enabled = true;
+
+       iudma->n_bds = n_bds;
+       iudma->bd_ring = dmam_alloc_coherent(udc->dev,
+               n_bds * sizeof(struct bcm_enet_desc),
+               &iudma->bd_ring_dma, GFP_KERNEL);
+       if (!iudma->bd_ring)
+               return -ENOMEM;
+       iudma->end_bd = &iudma->bd_ring[n_bds - 1];
+
+       return 0;
+}
+
+/**
+ * iudma_init - One-time initialization of all IUDMA channels.
+ * @udc: Reference to the device controller.
+ *
+ * Enable DMA, flush channels, and enable global IUDMA IRQs.
+ */
+static int iudma_init(struct bcm63xx_udc *udc)
+{
+       int i, rc;
+
+       usb_dma_writel(udc, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
+
+       for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+               rc = iudma_init_channel(udc, i);
+               if (rc)
+                       return rc;
+               iudma_reset_channel(udc, &udc->iudma[i]);
+       }
+
+       usb_dma_writel(udc, BIT(BCM63XX_NUM_IUDMA)-1, ENETDMA_GLB_IRQMASK_REG);
+       return 0;
+}
+
+/**
+ * iudma_uninit - Uninitialize IUDMA channels.
+ * @udc: Reference to the device controller.
+ *
+ * Kill global IUDMA IRQs, flush channels, and kill DMA.
+ */
+static void iudma_uninit(struct bcm63xx_udc *udc)
+{
+       int i;
+
+       usb_dma_writel(udc, 0, ENETDMA_GLB_IRQMASK_REG);
+
+       for (i = 0; i < BCM63XX_NUM_IUDMA; i++)
+               iudma_reset_channel(udc, &udc->iudma[i]);
+
+       usb_dma_writel(udc, 0, ENETDMA_CFG_REG);
+}
+
+/***********************************************************************
+ * Other low-level USBD operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_set_ctrl_irqs - Mask/unmask control path interrupts.
+ * @udc: Reference to the device controller.
+ * @enable_irqs: true to enable, false to disable.
+ */
+static void bcm63xx_set_ctrl_irqs(struct bcm63xx_udc *udc, bool enable_irqs)
+{
+       u32 val;
+
+       usbd_writel(udc, 0, USBD_STATUS_REG);
+
+       val = BIT(USBD_EVENT_IRQ_USB_RESET) |
+             BIT(USBD_EVENT_IRQ_SETUP) |
+             BIT(USBD_EVENT_IRQ_SETCFG) |
+             BIT(USBD_EVENT_IRQ_SETINTF) |
+             BIT(USBD_EVENT_IRQ_USB_LINK);
+       usbd_writel(udc, enable_irqs ? val : 0, USBD_EVENT_IRQ_MASK_REG);
+       usbd_writel(udc, val, USBD_EVENT_IRQ_STATUS_REG);
+}
+
+/**
+ * bcm63xx_select_phy_mode - Select between USB device and host mode.
+ * @udc: Reference to the device controller.
+ * @is_device: true for device, false for host.
+ *
+ * This should probably be reworked to use the drivers/usb/otg
+ * infrastructure.
+ *
+ * By default, the AFE/pullups are disabled in device mode, until
+ * bcm63xx_select_pullup() is called.
+ */
+static void bcm63xx_select_phy_mode(struct bcm63xx_udc *udc, bool is_device)
+{
+       u32 val, portmask = BIT(udc->pd->port_no);
+
+       if (BCMCPU_IS_6328()) {
+               /* configure pinmux to sense VBUS signal */
+               val = bcm_gpio_readl(GPIO_PINMUX_OTHR_REG);
+               val &= ~GPIO_PINMUX_OTHR_6328_USB_MASK;
+               val |= is_device ? GPIO_PINMUX_OTHR_6328_USB_DEV :
+                              GPIO_PINMUX_OTHR_6328_USB_HOST;
+               bcm_gpio_writel(val, GPIO_PINMUX_OTHR_REG);
+       }
+
+       val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+       if (is_device) {
+               val |= (portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
+               val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+       } else {
+               val &= ~(portmask << USBH_PRIV_UTMI_CTL_HOSTB_SHIFT);
+               val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+       }
+       bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
+
+       val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_SWAP_6368_REG);
+       if (is_device)
+               val |= USBH_PRIV_SWAP_USBD_MASK;
+       else
+               val &= ~USBH_PRIV_SWAP_USBD_MASK;
+       bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_SWAP_6368_REG);
+}
+
+/**
+ * bcm63xx_select_pullup - Enable/disable the pullup on D+
+ * @udc: Reference to the device controller.
+ * @is_on: true to enable the pullup, false to disable.
+ *
+ * If the pullup is active, the host will sense a FS/HS device connected to
+ * the port.  If the pullup is inactive, the host will think the USB
+ * device has been disconnected.
+ */
+static void bcm63xx_select_pullup(struct bcm63xx_udc *udc, bool is_on)
+{
+       u32 val, portmask = BIT(udc->pd->port_no);
+
+       val = bcm_rset_readl(RSET_USBH_PRIV, USBH_PRIV_UTMI_CTL_6368_REG);
+       if (is_on)
+               val &= ~(portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+       else
+               val |= (portmask << USBH_PRIV_UTMI_CTL_NODRIV_SHIFT);
+       bcm_rset_writel(RSET_USBH_PRIV, val, USBH_PRIV_UTMI_CTL_6368_REG);
+}
+
+/**
+ * bcm63xx_uninit_udc_hw - Shut down the hardware prior to driver removal.
+ * @udc: Reference to the device controller.
+ *
+ * This just masks the IUDMA IRQs and releases the clocks.  It is assumed
+ * that bcm63xx_udc_stop() has already run, and the clocks are stopped.
+ */
+static void bcm63xx_uninit_udc_hw(struct bcm63xx_udc *udc)
+{
+       set_clocks(udc, true);
+       iudma_uninit(udc);
+       set_clocks(udc, false);
+
+       clk_put(udc->usbd_clk);
+       clk_put(udc->usbh_clk);
+}
+
+/**
+ * bcm63xx_init_udc_hw - Initialize the controller hardware and data structures.
+ * @udc: Reference to the device controller.
+ */
+static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc)
+{
+       int i, rc = 0;
+       u32 val;
+
+       udc->ep0_ctrl_buf = devm_kzalloc(udc->dev, BCM63XX_MAX_CTRL_PKT,
+                                        GFP_KERNEL);
+       if (!udc->ep0_ctrl_buf)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&udc->gadget.ep_list);
+       for (i = 0; i < BCM63XX_NUM_EP; i++) {
+               struct bcm63xx_ep *bep = &udc->bep[i];
+
+               bep->ep.name = bcm63xx_ep_name[i];
+               bep->ep_num = i;
+               bep->ep.ops = &bcm63xx_udc_ep_ops;
+               list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list);
+               bep->halted = 0;
+               bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT;
+               bep->udc = udc;
+               bep->ep.desc = NULL;
+               INIT_LIST_HEAD(&bep->queue);
+       }
+
+       udc->gadget.ep0 = &udc->bep[0].ep;
+       list_del(&udc->bep[0].ep.ep_list);
+
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       udc->ep0state = EP0_SHUTDOWN;
+
+       udc->usbh_clk = clk_get(udc->dev, "usbh");
+       if (IS_ERR(udc->usbh_clk))
+               return -EIO;
+
+       udc->usbd_clk = clk_get(udc->dev, "usbd");
+       if (IS_ERR(udc->usbd_clk)) {
+               clk_put(udc->usbh_clk);
+               return -EIO;
+       }
+
+       set_clocks(udc, true);
+
+       val = USBD_CONTROL_AUTO_CSRS_MASK |
+             USBD_CONTROL_DONE_CSRS_MASK |
+             (irq_coalesce ? USBD_CONTROL_RXZSCFG_MASK : 0);
+       usbd_writel(udc, val, USBD_CONTROL_REG);
+
+       val = USBD_STRAPS_APP_SELF_PWR_MASK |
+             USBD_STRAPS_APP_RAM_IF_MASK |
+             USBD_STRAPS_APP_CSRPRGSUP_MASK |
+             USBD_STRAPS_APP_8BITPHY_MASK |
+             USBD_STRAPS_APP_RMTWKUP_MASK;
+
+       if (udc->gadget.max_speed == USB_SPEED_HIGH)
+               val |= (BCM63XX_SPD_HIGH << USBD_STRAPS_SPEED_SHIFT);
+       else
+               val |= (BCM63XX_SPD_FULL << USBD_STRAPS_SPEED_SHIFT);
+       usbd_writel(udc, val, USBD_STRAPS_REG);
+
+       bcm63xx_set_ctrl_irqs(udc, false);
+
+       usbd_writel(udc, 0, USBD_EVENT_IRQ_CFG_LO_REG);
+
+       val = USBD_EVENT_IRQ_CFG_FALLING(USBD_EVENT_IRQ_ENUM_ON) |
+             USBD_EVENT_IRQ_CFG_FALLING(USBD_EVENT_IRQ_SET_CSRS);
+       usbd_writel(udc, val, USBD_EVENT_IRQ_CFG_HI_REG);
+
+       rc = iudma_init(udc);
+       set_clocks(udc, false);
+       if (rc)
+               bcm63xx_uninit_udc_hw(udc);
+
+       return 0;
+}
+
+/***********************************************************************
+ * Standard EP gadget operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_ep_enable - Enable one endpoint.
+ * @ep: Endpoint to enable.
+ * @desc: Contains max packet, direction, etc.
+ *
+ * Most of the endpoint parameters are fixed in this controller, so there
+ * isn't much for this function to do.
+ */
+static int bcm63xx_ep_enable(struct usb_ep *ep,
+       const struct usb_endpoint_descriptor *desc)
+{
+       struct bcm63xx_ep *bep = our_ep(ep);
+       struct bcm63xx_udc *udc = bep->udc;
+       struct iudma_ch *iudma = bep->iudma;
+       unsigned long flags;
+
+       if (!ep || !desc || ep->name == bcm63xx_ep0name)
+               return -EINVAL;
+
+       if (!udc->driver)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (iudma->enabled) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return -EINVAL;
+       }
+
+       iudma->enabled = true;
+       BUG_ON(!list_empty(&bep->queue));
+
+       iudma_reset_channel(udc, iudma);
+
+       bep->halted = 0;
+       bcm63xx_set_stall(udc, bep, false);
+       clear_bit(bep->ep_num, &udc->wedgemap);
+
+       ep->desc = desc;
+       ep->maxpacket = usb_endpoint_maxp(desc);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return 0;
+}
+
+/**
+ * bcm63xx_ep_disable - Disable one endpoint.
+ * @ep: Endpoint to disable.
+ */
+static int bcm63xx_ep_disable(struct usb_ep *ep)
+{
+       struct bcm63xx_ep *bep = our_ep(ep);
+       struct bcm63xx_udc *udc = bep->udc;
+       struct iudma_ch *iudma = bep->iudma;
+       struct list_head *pos, *n;
+       unsigned long flags;
+
+       if (!ep || !ep->desc)
+               return -EINVAL;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (!iudma->enabled) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return -EINVAL;
+       }
+       iudma->enabled = false;
+
+       iudma_reset_channel(udc, iudma);
+
+       if (!list_empty(&bep->queue)) {
+               list_for_each_safe(pos, n, &bep->queue) {
+                       struct bcm63xx_req *breq =
+                               list_entry(pos, struct bcm63xx_req, queue);
+
+                       usb_gadget_unmap_request(&udc->gadget, &breq->req,
+                                                iudma->is_tx);
+                       list_del(&breq->queue);
+                       breq->req.status = -ESHUTDOWN;
+
+                       spin_unlock_irqrestore(&udc->lock, flags);
+                       breq->req.complete(&iudma->bep->ep, &breq->req);
+                       spin_lock_irqsave(&udc->lock, flags);
+               }
+       }
+       ep->desc = NULL;
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return 0;
+}
+
+/**
+ * bcm63xx_udc_alloc_request - Allocate a new request.
+ * @ep: Endpoint associated with the request.
+ * @mem_flags: Flags to pass to kzalloc().
+ */
+static struct usb_request *bcm63xx_udc_alloc_request(struct usb_ep *ep,
+       gfp_t mem_flags)
+{
+       struct bcm63xx_req *breq;
+
+       breq = kzalloc(sizeof(*breq), mem_flags);
+       if (!breq)
+               return NULL;
+       return &breq->req;
+}
+
+/**
+ * bcm63xx_udc_free_request - Free a request.
+ * @ep: Endpoint associated with the request.
+ * @req: Request to free.
+ */
+static void bcm63xx_udc_free_request(struct usb_ep *ep,
+       struct usb_request *req)
+{
+       struct bcm63xx_req *breq = our_req(req);
+       kfree(breq);
+}
+
+/**
+ * bcm63xx_udc_queue - Queue up a new request.
+ * @ep: Endpoint associated with the request.
+ * @req: Request to add.
+ * @mem_flags: Unused.
+ *
+ * If the queue is empty, start this request immediately.  Otherwise, add
+ * it to the list.
+ *
+ * ep0 replies are sent through this function from the gadget driver, but
+ * they are treated differently because they need to be handled by the ep0
+ * state machine.  (Sometimes they are replies to control requests that
+ * were spoofed by this driver, and so they shouldn't be transmitted at all.)
+ */
+static int bcm63xx_udc_queue(struct usb_ep *ep, struct usb_request *req,
+       gfp_t mem_flags)
+{
+       struct bcm63xx_ep *bep = our_ep(ep);
+       struct bcm63xx_udc *udc = bep->udc;
+       struct bcm63xx_req *breq = our_req(req);
+       unsigned long flags;
+       int rc = 0;
+
+       if (unlikely(!req || !req->complete || !req->buf || !ep))
+               return -EINVAL;
+
+       req->actual = 0;
+       req->status = 0;
+       breq->offset = 0;
+
+       if (bep == &udc->bep[0]) {
+               /* only one reply per request, please */
+               if (udc->ep0_reply)
+                       return -EINVAL;
+
+               udc->ep0_reply = req;
+               schedule_work(&udc->ep0_wq);
+               return 0;
+       }
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (!bep->iudma->enabled) {
+               rc = -ESHUTDOWN;
+               goto out;
+       }
+
+       rc = usb_gadget_map_request(&udc->gadget, req, bep->iudma->is_tx);
+       if (rc == 0) {
+               list_add_tail(&breq->queue, &bep->queue);
+               if (list_is_singular(&bep->queue))
+                       iudma_write(udc, bep->iudma, breq);
+       }
+
+out:
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return rc;
+}
+
+/**
+ * bcm63xx_udc_dequeue - Remove a pending request from the queue.
+ * @ep: Endpoint associated with the request.
+ * @req: Request to remove.
+ *
+ * If the request is not at the head of the queue, this is easy - just nuke
+ * it.  If the request is at the head of the queue, we'll need to stop the
+ * DMA transaction and then queue up the successor.
+ */
+static int bcm63xx_udc_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       struct bcm63xx_ep *bep = our_ep(ep);
+       struct bcm63xx_udc *udc = bep->udc;
+       struct bcm63xx_req *breq = our_req(req), *cur;
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (list_empty(&bep->queue)) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       cur = list_first_entry(&bep->queue, struct bcm63xx_req, queue);
+       usb_gadget_unmap_request(&udc->gadget, &breq->req, bep->iudma->is_tx);
+
+       if (breq == cur) {
+               iudma_reset_channel(udc, bep->iudma);
+               list_del(&breq->queue);
+
+               if (!list_empty(&bep->queue)) {
+                       struct bcm63xx_req *next;
+
+                       next = list_first_entry(&bep->queue,
+                               struct bcm63xx_req, queue);
+                       iudma_write(udc, bep->iudma, next);
+               }
+       } else {
+               list_del(&breq->queue);
+       }
+
+out:
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       req->status = -ESHUTDOWN;
+       req->complete(ep, req);
+
+       return rc;
+}
+
+/**
+ * bcm63xx_udc_set_halt - Enable/disable STALL flag in the hardware.
+ * @ep: Endpoint to halt.
+ * @value: Zero to clear halt; nonzero to set halt.
+ *
+ * See comments in bcm63xx_update_wedge().
+ */
+static int bcm63xx_udc_set_halt(struct usb_ep *ep, int value)
+{
+       struct bcm63xx_ep *bep = our_ep(ep);
+       struct bcm63xx_udc *udc = bep->udc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       bcm63xx_set_stall(udc, bep, !!value);
+       bep->halted = value;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+/**
+ * bcm63xx_udc_set_wedge - Stall the endpoint until the next reset.
+ * @ep: Endpoint to wedge.
+ *
+ * See comments in bcm63xx_update_wedge().
+ */
+static int bcm63xx_udc_set_wedge(struct usb_ep *ep)
+{
+       struct bcm63xx_ep *bep = our_ep(ep);
+       struct bcm63xx_udc *udc = bep->udc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       set_bit(bep->ep_num, &udc->wedgemap);
+       bcm63xx_set_stall(udc, bep, true);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static const struct usb_ep_ops bcm63xx_udc_ep_ops = {
+       .enable         = bcm63xx_ep_enable,
+       .disable        = bcm63xx_ep_disable,
+
+       .alloc_request  = bcm63xx_udc_alloc_request,
+       .free_request   = bcm63xx_udc_free_request,
+
+       .queue          = bcm63xx_udc_queue,
+       .dequeue        = bcm63xx_udc_dequeue,
+
+       .set_halt       = bcm63xx_udc_set_halt,
+       .set_wedge      = bcm63xx_udc_set_wedge,
+};
+
+/***********************************************************************
+ * EP0 handling
+ ***********************************************************************/
+
+/**
+ * bcm63xx_ep0_setup_callback - Drop spinlock to invoke ->setup callback.
+ * @udc: Reference to the device controller.
+ * @ctrl: 8-byte SETUP request.
+ */
+static int bcm63xx_ep0_setup_callback(struct bcm63xx_udc *udc,
+       struct usb_ctrlrequest *ctrl)
+{
+       int rc;
+
+       spin_unlock_irq(&udc->lock);
+       rc = udc->driver->setup(&udc->gadget, ctrl);
+       spin_lock_irq(&udc->lock);
+       return rc;
+}
+
+/**
+ * bcm63xx_ep0_spoof_set_cfg - Synthesize a SET_CONFIGURATION request.
+ * @udc: Reference to the device controller.
+ *
+ * Many standard requests are handled automatically in the hardware, but
+ * we still need to pass them to the gadget driver so that it can
+ * reconfigure the interfaces/endpoints if necessary.
+ *
+ * Unfortunately we are not able to send a STALL response if the host
+ * requests an invalid configuration.  If this happens, we'll have to be
+ * content with printing a warning.
+ */
+static int bcm63xx_ep0_spoof_set_cfg(struct bcm63xx_udc *udc)
+{
+       struct usb_ctrlrequest ctrl;
+       int rc;
+
+       ctrl.bRequestType = USB_DIR_OUT | USB_RECIP_DEVICE;
+       ctrl.bRequest = USB_REQ_SET_CONFIGURATION;
+       ctrl.wValue = cpu_to_le16(udc->cfg);
+       ctrl.wIndex = 0;
+       ctrl.wLength = 0;
+
+       rc = bcm63xx_ep0_setup_callback(udc, &ctrl);
+       if (rc < 0) {
+               dev_warn_ratelimited(udc->dev,
+                       "hardware auto-acked bad SET_CONFIGURATION(%d) request\n",
+                       udc->cfg);
+       }
+       return rc;
+}
+
+/**
+ * bcm63xx_ep0_spoof_set_iface - Synthesize a SET_INTERFACE request.
+ * @udc: Reference to the device controller.
+ */
+static int bcm63xx_ep0_spoof_set_iface(struct bcm63xx_udc *udc)
+{
+       struct usb_ctrlrequest ctrl;
+       int rc;
+
+       ctrl.bRequestType = USB_DIR_OUT | USB_RECIP_INTERFACE;
+       ctrl.bRequest = USB_REQ_SET_INTERFACE;
+       ctrl.wValue = cpu_to_le16(udc->alt_iface);
+       ctrl.wIndex = cpu_to_le16(udc->iface);
+       ctrl.wLength = 0;
+
+       rc = bcm63xx_ep0_setup_callback(udc, &ctrl);
+       if (rc < 0) {
+               dev_warn_ratelimited(udc->dev,
+                       "hardware auto-acked bad SET_INTERFACE(%d,%d) request\n",
+                       udc->iface, udc->alt_iface);
+       }
+       return rc;
+}
+
+/**
+ * bcm63xx_ep0_map_write - dma_map and iudma_write a single request.
+ * @udc: Reference to the device controller.
+ * @ch_idx: IUDMA channel number.
+ * @req: USB gadget layer representation of the request.
+ */
+static void bcm63xx_ep0_map_write(struct bcm63xx_udc *udc, int ch_idx,
+       struct usb_request *req)
+{
+       struct bcm63xx_req *breq = our_req(req);
+       struct iudma_ch *iudma = &udc->iudma[ch_idx];
+
+       BUG_ON(udc->ep0_request);
+       udc->ep0_request = req;
+
+       req->actual = 0;
+       breq->offset = 0;
+       usb_gadget_map_request(&udc->gadget, req, iudma->is_tx);
+       iudma_write(udc, iudma, breq);
+}
+
+/**
+ * bcm63xx_ep0_complete - Set completion status and "stage" the callback.
+ * @udc: Reference to the device controller.
+ * @req: USB gadget layer representation of the request.
+ * @status: Status to return to the gadget driver.
+ */
+static void bcm63xx_ep0_complete(struct bcm63xx_udc *udc,
+       struct usb_request *req, int status)
+{
+       req->status = status;
+       if (status)
+               req->actual = 0;
+       if (req->complete) {
+               spin_unlock_irq(&udc->lock);
+               req->complete(&udc->bep[0].ep, req);
+               spin_lock_irq(&udc->lock);
+       }
+}
+
+/**
+ * bcm63xx_ep0_nuke_reply - Abort request from the gadget driver due to
+ *   reset/shutdown.
+ * @udc: Reference to the device controller.
+ * @is_tx: Nonzero for TX (IN), zero for RX (OUT).
+ */
+static void bcm63xx_ep0_nuke_reply(struct bcm63xx_udc *udc, int is_tx)
+{
+       struct usb_request *req = udc->ep0_reply;
+
+       udc->ep0_reply = NULL;
+       usb_gadget_unmap_request(&udc->gadget, req, is_tx);
+       if (udc->ep0_request == req) {
+               udc->ep0_req_completed = 0;
+               udc->ep0_request = NULL;
+       }
+       bcm63xx_ep0_complete(udc, req, -ESHUTDOWN);
+}
+
+/**
+ * bcm63xx_ep0_read_complete - Close out the pending ep0 request; return
+ *   transfer len.
+ * @udc: Reference to the device controller.
+ */
+static int bcm63xx_ep0_read_complete(struct bcm63xx_udc *udc)
+{
+       struct usb_request *req = udc->ep0_request;
+
+       udc->ep0_req_completed = 0;
+       udc->ep0_request = NULL;
+
+       return req->actual;
+}
+
+/**
+ * bcm63xx_ep0_internal_request - Helper function to submit an ep0 request.
+ * @udc: Reference to the device controller.
+ * @ch_idx: IUDMA channel number.
+ * @length: Number of bytes to TX/RX.
+ *
+ * Used for simple transfers performed by the ep0 worker.  This will always
+ * use ep0_ctrl_req / ep0_ctrl_buf.
+ */
+static void bcm63xx_ep0_internal_request(struct bcm63xx_udc *udc, int ch_idx,
+       int length)
+{
+       struct usb_request *req = &udc->ep0_ctrl_req.req;
+
+       req->buf = udc->ep0_ctrl_buf;
+       req->length = length;
+       req->complete = NULL;
+
+       bcm63xx_ep0_map_write(udc, ch_idx, req);
+}
+
+/**
+ * bcm63xx_ep0_do_setup - Parse new SETUP packet and decide how to handle it.
+ * @udc: Reference to the device controller.
+ *
+ * EP0_IDLE probably shouldn't ever happen.  EP0_REQUEUE means we're ready
+ * for the next packet.  Anything else means the transaction requires multiple
+ * stages of handling.
+ */
+static enum bcm63xx_ep0_state bcm63xx_ep0_do_setup(struct bcm63xx_udc *udc)
+{
+       int rc;
+       struct usb_ctrlrequest *ctrl = (void *)udc->ep0_ctrl_buf;
+
+       rc = bcm63xx_ep0_read_complete(udc);
+
+       if (rc < 0) {
+               dev_err(udc->dev, "missing SETUP packet\n");
+               return EP0_IDLE;
+       }
+
+       /*
+        * Handle 0-byte IN STATUS acknowledgement.  The hardware doesn't
+        * ALWAYS deliver these 100% of the time, so if we happen to see one,
+        * just throw it away.
+        */
+       if (rc == 0)
+               return EP0_REQUEUE;
+
+       /* Drop malformed SETUP packets */
+       if (rc != sizeof(*ctrl)) {
+               dev_warn_ratelimited(udc->dev,
+                       "malformed SETUP packet (%d bytes)\n", rc);
+               return EP0_REQUEUE;
+       }
+
+       /* Process new SETUP packet arriving on ep0 */
+       rc = bcm63xx_ep0_setup_callback(udc, ctrl);
+       if (rc < 0) {
+               bcm63xx_set_stall(udc, &udc->bep[0], true);
+               return EP0_REQUEUE;
+       }
+
+       if (!ctrl->wLength)
+               return EP0_REQUEUE;
+       else if (ctrl->bRequestType & USB_DIR_IN)
+               return EP0_IN_DATA_PHASE_SETUP;
+       else
+               return EP0_OUT_DATA_PHASE_SETUP;
+}
+
+/**
+ * bcm63xx_ep0_do_idle - Check for outstanding requests if ep0 is idle.
+ * @udc: Reference to the device controller.
+ *
+ * In state EP0_IDLE, the RX descriptor is either pending, or has been
+ * filled with a SETUP packet from the host.  This function handles new
+ * SETUP packets, control IRQ events (which can generate fake SETUP packets),
+ * and reset/shutdown events.
+ *
+ * Returns 0 if work was done; -EAGAIN if nothing to do.
+ */
+static int bcm63xx_ep0_do_idle(struct bcm63xx_udc *udc)
+{
+       if (udc->ep0_req_reset) {
+               udc->ep0_req_reset = 0;
+       } else if (udc->ep0_req_set_cfg) {
+               udc->ep0_req_set_cfg = 0;
+               if (bcm63xx_ep0_spoof_set_cfg(udc) >= 0)
+                       udc->ep0state = EP0_IN_FAKE_STATUS_PHASE;
+       } else if (udc->ep0_req_set_iface) {
+               udc->ep0_req_set_iface = 0;
+               if (bcm63xx_ep0_spoof_set_iface(udc) >= 0)
+                       udc->ep0state = EP0_IN_FAKE_STATUS_PHASE;
+       } else if (udc->ep0_req_completed) {
+               udc->ep0state = bcm63xx_ep0_do_setup(udc);
+               return udc->ep0state == EP0_IDLE ? -EAGAIN : 0;
+       } else if (udc->ep0_req_shutdown) {
+               udc->ep0_req_shutdown = 0;
+               udc->ep0_req_completed = 0;
+               udc->ep0_request = NULL;
+               iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_RXCHAN]);
+               usb_gadget_unmap_request(&udc->gadget,
+                       &udc->ep0_ctrl_req.req, 0);
+
+               /* bcm63xx_udc_pullup() is waiting for this */
+               mb();
+               udc->ep0state = EP0_SHUTDOWN;
+       } else if (udc->ep0_reply) {
+               /*
+                * This could happen if a USB RESET shows up during an ep0
+                * transaction (especially if a laggy driver like gadgetfs
+                * is in use).
+                */
+               dev_warn(udc->dev, "nuking unexpected reply\n");
+               bcm63xx_ep0_nuke_reply(udc, 0);
+       } else {
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+/**
+ * bcm63xx_ep0_one_round - Handle the current ep0 state.
+ * @udc: Reference to the device controller.
+ *
+ * Returns 0 if work was done; -EAGAIN if nothing to do.
+ */
+static int bcm63xx_ep0_one_round(struct bcm63xx_udc *udc)
+{
+       enum bcm63xx_ep0_state ep0state = udc->ep0state;
+       bool shutdown = udc->ep0_req_reset || udc->ep0_req_shutdown;
+
+       switch (udc->ep0state) {
+       case EP0_REQUEUE:
+               /* set up descriptor to receive SETUP packet */
+               bcm63xx_ep0_internal_request(udc, IUDMA_EP0_RXCHAN,
+                                            BCM63XX_MAX_CTRL_PKT);
+               ep0state = EP0_IDLE;
+               break;
+       case EP0_IDLE:
+               return bcm63xx_ep0_do_idle(udc);
+       case EP0_IN_DATA_PHASE_SETUP:
+               /*
+                * Normal case: TX request is in ep0_reply (queued by the
+                * callback), or will be queued shortly.  When it's here,
+                * send it to the HW and go to EP0_IN_DATA_PHASE_COMPLETE.
+                *
+                * Shutdown case: Stop waiting for the reply.  Just
+                * REQUEUE->IDLE.  The gadget driver is NOT expected to
+                * queue anything else now.
+                */
+               if (udc->ep0_reply) {
+                       bcm63xx_ep0_map_write(udc, IUDMA_EP0_TXCHAN,
+                                             udc->ep0_reply);
+                       ep0state = EP0_IN_DATA_PHASE_COMPLETE;
+               } else if (shutdown) {
+                       ep0state = EP0_REQUEUE;
+               }
+               break;
+       case EP0_IN_DATA_PHASE_COMPLETE: {
+               /*
+                * Normal case: TX packet (ep0_reply) is in flight; wait for
+                * it to finish, then go back to REQUEUE->IDLE.
+                *
+                * Shutdown case: Reset the TX channel, send -ESHUTDOWN
+                * completion to the gadget driver, then REQUEUE->IDLE.
+                */
+               if (udc->ep0_req_completed) {
+                       udc->ep0_reply = NULL;
+                       bcm63xx_ep0_read_complete(udc);
+                       /*
+                        * the "ack" sometimes gets eaten (see
+                        * bcm63xx_ep0_do_idle)
+                        */
+                       ep0state = EP0_REQUEUE;
+               } else if (shutdown) {
+                       iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_TXCHAN]);
+                       bcm63xx_ep0_nuke_reply(udc, 1);
+                       ep0state = EP0_REQUEUE;
+               }
+               break;
+       }
+       case EP0_OUT_DATA_PHASE_SETUP:
+               /* Similar behavior to EP0_IN_DATA_PHASE_SETUP */
+               if (udc->ep0_reply) {
+                       bcm63xx_ep0_map_write(udc, IUDMA_EP0_RXCHAN,
+                                             udc->ep0_reply);
+                       ep0state = EP0_OUT_DATA_PHASE_COMPLETE;
+               } else if (shutdown) {
+                       ep0state = EP0_REQUEUE;
+               }
+               break;
+       case EP0_OUT_DATA_PHASE_COMPLETE: {
+               /* Similar behavior to EP0_IN_DATA_PHASE_COMPLETE */
+               if (udc->ep0_req_completed) {
+                       udc->ep0_reply = NULL;
+                       bcm63xx_ep0_read_complete(udc);
+
+                       /* send 0-byte ack to host */
+                       bcm63xx_ep0_internal_request(udc, IUDMA_EP0_TXCHAN, 0);
+                       ep0state = EP0_OUT_STATUS_PHASE;
+               } else if (shutdown) {
+                       iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_RXCHAN]);
+                       bcm63xx_ep0_nuke_reply(udc, 0);
+                       ep0state = EP0_REQUEUE;
+               }
+               break;
+       }
+       case EP0_OUT_STATUS_PHASE:
+               /*
+                * Normal case: 0-byte OUT ack packet is in flight; wait
+                * for it to finish, then go back to REQUEUE->IDLE.
+                *
+                * Shutdown case: just cancel the transmission.  Don't bother
+                * calling the completion, because it originated from this
+                * function anyway.  Then go back to REQUEUE->IDLE.
+                */
+               if (udc->ep0_req_completed) {
+                       bcm63xx_ep0_read_complete(udc);
+                       ep0state = EP0_REQUEUE;
+               } else if (shutdown) {
+                       iudma_reset_channel(udc, &udc->iudma[IUDMA_EP0_TXCHAN]);
+                       udc->ep0_request = NULL;
+                       ep0state = EP0_REQUEUE;
+               }
+               break;
+       case EP0_IN_FAKE_STATUS_PHASE: {
+               /*
+                * Normal case: we spoofed a SETUP packet and are now
+                * waiting for the gadget driver to send a 0-byte reply.
+                * This doesn't actually get sent to the HW because the
+                * HW has already sent its own reply.  Once we get the
+                * response, return to IDLE.
+                *
+                * Shutdown case: return to IDLE immediately.
+                *
+                * Note that the ep0 RX descriptor has remained queued
+                * (and possibly unfilled) during this entire transaction.
+                * The HW datapath (IUDMA) never even sees SET_CONFIGURATION
+                * or SET_INTERFACE transactions.
+                */
+               struct usb_request *r = udc->ep0_reply;
+
+               if (!r) {
+                       if (shutdown)
+                               ep0state = EP0_IDLE;
+                       break;
+               }
+
+               bcm63xx_ep0_complete(udc, r, 0);
+               udc->ep0_reply = NULL;
+               ep0state = EP0_IDLE;
+               break;
+       }
+       case EP0_SHUTDOWN:
+               break;
+       }
+
+       if (udc->ep0state == ep0state)
+               return -EAGAIN;
+
+       udc->ep0state = ep0state;
+       return 0;
+}
+
+/**
+ * bcm63xx_ep0_process - ep0 worker thread / state machine.
+ * @w: Workqueue struct.
+ *
+ * bcm63xx_ep0_process is triggered any time an event occurs on ep0.  It
+ * is used to synchronize ep0 events and ensure that both HW and SW events
+ * occur in a well-defined order.  When the ep0 IUDMA queues are idle, it may
+ * synthesize SET_CONFIGURATION / SET_INTERFACE requests that were consumed
+ * by the USBD hardware.
+ *
+ * The worker function will continue iterating around the state machine
+ * until there is nothing left to do.  Usually "nothing left to do" means
+ * that we're waiting for a new event from the hardware.
+ */
+static void bcm63xx_ep0_process(struct work_struct *w)
+{
+       struct bcm63xx_udc *udc = container_of(w, struct bcm63xx_udc, ep0_wq);
+       spin_lock_irq(&udc->lock);
+       while (bcm63xx_ep0_one_round(udc) == 0)
+               ;
+       spin_unlock_irq(&udc->lock);
+}
+
+/***********************************************************************
+ * Standard UDC gadget operations
+ ***********************************************************************/
+
+/**
+ * bcm63xx_udc_get_frame - Read current SOF frame number from the HW.
+ * @gadget: USB slave device.
+ */
+static int bcm63xx_udc_get_frame(struct usb_gadget *gadget)
+{
+       struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+
+       return (usbd_readl(udc, USBD_STATUS_REG) &
+               USBD_STATUS_SOF_MASK) >> USBD_STATUS_SOF_SHIFT;
+}
+
+/**
+ * bcm63xx_udc_pullup - Enable/disable pullup on D+ line.
+ * @gadget: USB slave device.
+ * @is_on: 0 to disable pullup, 1 to enable.
+ *
+ * See notes in bcm63xx_select_pullup().
+ */
+static int bcm63xx_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
+       int i, rc = -EINVAL;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (is_on && udc->ep0state == EP0_SHUTDOWN) {
+               udc->gadget.speed = USB_SPEED_UNKNOWN;
+               udc->ep0state = EP0_REQUEUE;
+               bcm63xx_fifo_setup(udc);
+               bcm63xx_fifo_reset(udc);
+               bcm63xx_ep_setup(udc);
+
+               bitmap_zero(&udc->wedgemap, BCM63XX_NUM_EP);
+               for (i = 0; i < BCM63XX_NUM_EP; i++)
+                       bcm63xx_set_stall(udc, &udc->bep[i], false);
+
+               bcm63xx_set_ctrl_irqs(udc, true);
+               bcm63xx_select_pullup(gadget_to_udc(gadget), true);
+               rc = 0;
+       } else if (!is_on && udc->ep0state != EP0_SHUTDOWN) {
+               bcm63xx_select_pullup(gadget_to_udc(gadget), false);
+
+               udc->ep0_req_shutdown = 1;
+               spin_unlock_irqrestore(&udc->lock, flags);
+
+               while (1) {
+                       schedule_work(&udc->ep0_wq);
+                       if (udc->ep0state == EP0_SHUTDOWN)
+                               break;
+                       msleep(50);
+               }
+               bcm63xx_set_ctrl_irqs(udc, false);
+               cancel_work_sync(&udc->ep0_wq);
+               return 0;
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return rc;
+}
+
+/**
+ * bcm63xx_udc_start - Start the controller.
+ * @gadget: USB slave device.
+ * @driver: Driver for USB slave devices.
+ */
+static int bcm63xx_udc_start(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
+
+       if (!driver || driver->max_speed < USB_SPEED_HIGH ||
+           !driver->setup)
+               return -EINVAL;
+       if (!udc)
+               return -ENODEV;
+       if (udc->driver)
+               return -EBUSY;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       set_clocks(udc, true);
+       bcm63xx_fifo_setup(udc);
+       bcm63xx_ep_init(udc);
+       bcm63xx_ep_setup(udc);
+       bcm63xx_fifo_reset(udc);
+       bcm63xx_select_phy_mode(udc, true);
+
+       udc->driver = driver;
+       driver->driver.bus = NULL;
+       udc->gadget.dev.driver = &driver->driver;
+       udc->gadget.dev.of_node = udc->dev->of_node;
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+/**
+ * bcm63xx_udc_stop - Shut down the controller.
+ * @gadget: USB slave device.
+ * @driver: Driver for USB slave devices.
+ */
+static int bcm63xx_udc_stop(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       struct bcm63xx_udc *udc = gadget_to_udc(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       udc->driver = NULL;
+       udc->gadget.dev.driver = NULL;
+
+       /*
+        * If we switch the PHY too abruptly after dropping D+, the host
+        * will often complain:
+        *
+        *     hub 1-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
+        */
+       msleep(100);
+
+       bcm63xx_select_phy_mode(udc, false);
+       set_clocks(udc, false);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static const struct usb_gadget_ops bcm63xx_udc_ops = {
+       .get_frame      = bcm63xx_udc_get_frame,
+       .pullup         = bcm63xx_udc_pullup,
+       .udc_start      = bcm63xx_udc_start,
+       .udc_stop       = bcm63xx_udc_stop,
+};
+
+/***********************************************************************
+ * IRQ handling
+ ***********************************************************************/
+
+/**
+ * bcm63xx_update_cfg_iface - Read current configuration/interface settings.
+ * @udc: Reference to the device controller.
+ *
+ * This controller intercepts SET_CONFIGURATION and SET_INTERFACE messages.
+ * The driver never sees the raw control packets coming in on the ep0
+ * IUDMA channel, but at least we get an interrupt event to tell us that
+ * new values are waiting in the USBD_STATUS register.
+ */
+static void bcm63xx_update_cfg_iface(struct bcm63xx_udc *udc)
+{
+       u32 reg = usbd_readl(udc, USBD_STATUS_REG);
+
+       udc->cfg = (reg & USBD_STATUS_CFG_MASK) >> USBD_STATUS_CFG_SHIFT;
+       udc->iface = (reg & USBD_STATUS_INTF_MASK) >> USBD_STATUS_INTF_SHIFT;
+       udc->alt_iface = (reg & USBD_STATUS_ALTINTF_MASK) >>
+                        USBD_STATUS_ALTINTF_SHIFT;
+       bcm63xx_ep_setup(udc);
+}
+
+/**
+ * bcm63xx_update_link_speed - Check to see if the link speed has changed.
+ * @udc: Reference to the device controller.
+ *
+ * The link speed update coincides with a SETUP IRQ.  Returns 1 if the
+ * speed has changed, so that the caller can update the endpoint settings.
+ */
+static int bcm63xx_update_link_speed(struct bcm63xx_udc *udc)
+{
+       u32 reg = usbd_readl(udc, USBD_STATUS_REG);
+       enum usb_device_speed oldspeed = udc->gadget.speed;
+
+       switch ((reg & USBD_STATUS_SPD_MASK) >> USBD_STATUS_SPD_SHIFT) {
+       case BCM63XX_SPD_HIGH:
+               udc->gadget.speed = USB_SPEED_HIGH;
+               break;
+       case BCM63XX_SPD_FULL:
+               udc->gadget.speed = USB_SPEED_FULL;
+               break;
+       default:
+               /* this should never happen */
+               udc->gadget.speed = USB_SPEED_UNKNOWN;
+               dev_err(udc->dev,
+                       "received SETUP packet with invalid link speed\n");
+               return 0;
+       }
+
+       if (udc->gadget.speed != oldspeed) {
+               dev_info(udc->dev, "link up, %s-speed mode\n",
+                        udc->gadget.speed == USB_SPEED_HIGH ? "high" : "full");
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+/**
+ * bcm63xx_update_wedge - Iterate through wedged endpoints.
+ * @udc: Reference to the device controller.
+ * @new_status: true to "refresh" wedge status; false to clear it.
+ *
+ * On a SETUP interrupt, we need to manually "refresh" the wedge status
+ * because the controller hardware is designed to automatically clear
+ * stalls in response to a CLEAR_FEATURE request from the host.
+ *
+ * On a RESET interrupt, we do want to restore all wedged endpoints.
+ */
+static void bcm63xx_update_wedge(struct bcm63xx_udc *udc, bool new_status)
+{
+       int i;
+
+       for_each_set_bit(i, &udc->wedgemap, BCM63XX_NUM_EP) {
+               bcm63xx_set_stall(udc, &udc->bep[i], new_status);
+               if (!new_status)
+                       clear_bit(i, &udc->wedgemap);
+       }
+}
+
+/**
+ * bcm63xx_udc_ctrl_isr - ISR for control path events (USBD).
+ * @irq: IRQ number (unused).
+ * @dev_id: Reference to the device controller.
+ *
+ * This is where we handle link (VBUS) down, USB reset, speed changes,
+ * SET_CONFIGURATION, and SET_INTERFACE events.
+ */
+static irqreturn_t bcm63xx_udc_ctrl_isr(int irq, void *dev_id)
+{
+       struct bcm63xx_udc *udc = dev_id;
+       u32 stat;
+       bool disconnected = false;
+
+       stat = usbd_readl(udc, USBD_EVENT_IRQ_STATUS_REG) &
+              usbd_readl(udc, USBD_EVENT_IRQ_MASK_REG);
+
+       usbd_writel(udc, stat, USBD_EVENT_IRQ_STATUS_REG);
+
+       spin_lock(&udc->lock);
+       if (stat & BIT(USBD_EVENT_IRQ_USB_LINK)) {
+               /* VBUS toggled */
+
+               if (!(usbd_readl(udc, USBD_EVENTS_REG) &
+                     USBD_EVENTS_USB_LINK_MASK) &&
+                     udc->gadget.speed != USB_SPEED_UNKNOWN)
+                       dev_info(udc->dev, "link down\n");
+
+               udc->gadget.speed = USB_SPEED_UNKNOWN;
+               disconnected = true;
+       }
+       if (stat & BIT(USBD_EVENT_IRQ_USB_RESET)) {
+               bcm63xx_fifo_setup(udc);
+               bcm63xx_fifo_reset(udc);
+               bcm63xx_ep_setup(udc);
+
+               bcm63xx_update_wedge(udc, false);
+
+               udc->ep0_req_reset = 1;
+               schedule_work(&udc->ep0_wq);
+               disconnected = true;
+       }
+       if (stat & BIT(USBD_EVENT_IRQ_SETUP)) {
+               if (bcm63xx_update_link_speed(udc)) {
+                       bcm63xx_fifo_setup(udc);
+                       bcm63xx_ep_setup(udc);
+               }
+               bcm63xx_update_wedge(udc, true);
+       }
+       if (stat & BIT(USBD_EVENT_IRQ_SETCFG)) {
+               bcm63xx_update_cfg_iface(udc);
+               udc->ep0_req_set_cfg = 1;
+               schedule_work(&udc->ep0_wq);
+       }
+       if (stat & BIT(USBD_EVENT_IRQ_SETINTF)) {
+               bcm63xx_update_cfg_iface(udc);
+               udc->ep0_req_set_iface = 1;
+               schedule_work(&udc->ep0_wq);
+       }
+       spin_unlock(&udc->lock);
+
+       if (disconnected && udc->driver)
+               udc->driver->disconnect(&udc->gadget);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * bcm63xx_udc_data_isr - ISR for data path events (IUDMA).
+ * @irq: IRQ number (unused).
+ * @dev_id: Reference to the IUDMA channel that generated the interrupt.
+ *
+ * For the two ep0 channels, we have special handling that triggers the
+ * ep0 worker thread.  For normal bulk/intr channels, either queue up
+ * the next buffer descriptor for the transaction (incomplete transaction),
+ * or invoke the completion callback (complete transactions).
+ */
+static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)
+{
+       struct iudma_ch *iudma = dev_id;
+       struct bcm63xx_udc *udc = iudma->udc;
+       struct bcm63xx_ep *bep;
+       struct usb_request *req = NULL;
+       struct bcm63xx_req *breq = NULL;
+       int rc;
+       bool is_done = false;
+
+       spin_lock(&udc->lock);
+
+       usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
+                       ENETDMAC_IR_REG(iudma->ch_idx));
+       bep = iudma->bep;
+       rc = iudma_read(udc, iudma);
+
+       /* special handling for EP0 RX (0) and TX (1) */
+       if (iudma->ch_idx == IUDMA_EP0_RXCHAN ||
+           iudma->ch_idx == IUDMA_EP0_TXCHAN) {
+               req = udc->ep0_request;
+               breq = our_req(req);
+
+               /* a single request could require multiple submissions */
+               if (rc >= 0) {
+                       req->actual += rc;
+
+                       if (req->actual >= req->length || breq->bd_bytes > rc) {
+                               udc->ep0_req_completed = 1;
+                               is_done = true;
+                               schedule_work(&udc->ep0_wq);
+
+                               /* "actual" on a ZLP is 1 byte */
+                               req->actual = min(req->actual, req->length);
+                       } else {
+                               /* queue up the next BD (same request) */
+                               iudma_write(udc, iudma, breq);
+                       }
+               }
+       } else if (!list_empty(&bep->queue)) {
+               breq = list_first_entry(&bep->queue, struct bcm63xx_req, queue);
+               req = &breq->req;
+
+               if (rc >= 0) {
+                       req->actual += rc;
+
+                       if (req->actual >= req->length || breq->bd_bytes > rc) {
+                               is_done = true;
+                               list_del(&breq->queue);
+
+                               req->actual = min(req->actual, req->length);
+
+                               if (!list_empty(&bep->queue)) {
+                                       struct bcm63xx_req *next;
+
+                                       next = list_first_entry(&bep->queue,
+                                               struct bcm63xx_req, queue);
+                                       iudma_write(udc, iudma, next);
+                               }
+                       } else {
+                               iudma_write(udc, iudma, breq);
+                       }
+               }
+       }
+       spin_unlock(&udc->lock);
+
+       if (is_done) {
+               usb_gadget_unmap_request(&udc->gadget, req, iudma->is_tx);
+               if (req->complete)
+                       req->complete(&bep->ep, req);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/***********************************************************************
+ * Debug filesystem
+ ***********************************************************************/
+
+/*
+ * bcm63xx_usbd_dbg_show - Show USBD controller state.
+ * @s: seq_file to which the information will be written.
+ * @p: Unused.
+ *
+ * This file nominally shows up as /sys/kernel/debug/bcm63xx_udc/usbd
+ */
+static int bcm63xx_usbd_dbg_show(struct seq_file *s, void *p)
+{
+       struct bcm63xx_udc *udc = s->private;
+
+       if (!udc->driver)
+               return -ENODEV;
+
+       seq_printf(s, "ep0 state: %s\n",
+                  bcm63xx_ep0_state_names[udc->ep0state]);
+       seq_printf(s, "  pending requests: %s%s%s%s%s%s%s\n",
+                  udc->ep0_req_reset ? "reset " : "",
+                  udc->ep0_req_set_cfg ? "set_cfg " : "",
+                  udc->ep0_req_set_iface ? "set_iface " : "",
+                  udc->ep0_req_shutdown ? "shutdown " : "",
+                  udc->ep0_request ? "pending " : "",
+                  udc->ep0_req_completed ? "completed " : "",
+                  udc->ep0_reply ? "reply " : "");
+       seq_printf(s, "cfg: %d; iface: %d; alt_iface: %d\n",
+                  udc->cfg, udc->iface, udc->alt_iface);
+       seq_printf(s, "regs:\n");
+       seq_printf(s, "  control: %08x; straps: %08x; status: %08x\n",
+                  usbd_readl(udc, USBD_CONTROL_REG),
+                  usbd_readl(udc, USBD_STRAPS_REG),
+                  usbd_readl(udc, USBD_STATUS_REG));
+       seq_printf(s, "  events:  %08x; stall:  %08x\n",
+                  usbd_readl(udc, USBD_EVENTS_REG),
+                  usbd_readl(udc, USBD_STALL_REG));
+
+       return 0;
+}
+
+/*
+ * bcm63xx_iudma_dbg_show - Show IUDMA status and descriptors.
+ * @s: seq_file to which the information will be written.
+ * @p: Unused.
+ *
+ * This file nominally shows up as /sys/kernel/debug/bcm63xx_udc/iudma
+ */
+static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
+{
+       struct bcm63xx_udc *udc = s->private;
+       int ch_idx, i;
+       u32 sram2, sram3;
+
+       if (!udc->driver)
+               return -ENODEV;
+
+       for (ch_idx = 0; ch_idx < BCM63XX_NUM_IUDMA; ch_idx++) {
+               struct iudma_ch *iudma = &udc->iudma[ch_idx];
+               struct list_head *pos;
+
+               seq_printf(s, "IUDMA channel %d -- ", ch_idx);
+               switch (iudma_defaults[ch_idx].ep_type) {
+               case BCMEP_CTRL:
+                       seq_printf(s, "control");
+                       break;
+               case BCMEP_BULK:
+                       seq_printf(s, "bulk");
+                       break;
+               case BCMEP_INTR:
+                       seq_printf(s, "interrupt");
+                       break;
+               }
+               seq_printf(s, ch_idx & 0x01 ? " tx" : " rx");
+               seq_printf(s, " [ep%d]:\n",
+                          max_t(int, iudma_defaults[ch_idx].ep_num, 0));
+               seq_printf(s, "  cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n",
+                          usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)),
+                          usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)),
+                          usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)),
+                          usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx)));
+
+               sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx));
+               sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx));
+               seq_printf(s, "  base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n",
+                          usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)),
+                          sram2 >> 16, sram2 & 0xffff,
+                          sram3 >> 16, sram3 & 0xffff,
+                          usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx)));
+               seq_printf(s, "  desc: %d/%d used", iudma->n_bds_used,
+                          iudma->n_bds);
+
+               if (iudma->bep) {
+                       i = 0;
+                       list_for_each(pos, &iudma->bep->queue)
+                               i++;
+                       seq_printf(s, "; %d queued\n", i);
+               } else {
+                       seq_printf(s, "\n");
+               }
+
+               for (i = 0; i < iudma->n_bds; i++) {
+                       struct bcm_enet_desc *d = &iudma->bd_ring[i];
+
+                       seq_printf(s, "  %03x (%02x): len_stat: %04x_%04x; pa %08x",
+                                  i * sizeof(*d), i,
+                                  d->len_stat >> 16, d->len_stat & 0xffff,
+                                  d->address);
+                       if (d == iudma->read_bd)
+                               seq_printf(s, "   <<RD");
+                       if (d == iudma->write_bd)
+                               seq_printf(s, "   <<WR");
+                       seq_printf(s, "\n");
+               }
+
+               seq_printf(s, "\n");
+       }
+
+       return 0;
+}
+
+static int bcm63xx_usbd_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bcm63xx_usbd_dbg_show, inode->i_private);
+}
+
+static int bcm63xx_iudma_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bcm63xx_iudma_dbg_show, inode->i_private);
+}
+
+static const struct file_operations usbd_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = bcm63xx_usbd_dbg_open,
+       .llseek         = seq_lseek,
+       .read           = seq_read,
+       .release        = single_release,
+};
+
+static const struct file_operations iudma_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = bcm63xx_iudma_dbg_open,
+       .llseek         = seq_lseek,
+       .read           = seq_read,
+       .release        = single_release,
+};
+
+
+/**
+ * bcm63xx_udc_init_debugfs - Create debugfs entries.
+ * @udc: Reference to the device controller.
+ */
+static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
+{
+       struct dentry *root, *usbd, *iudma;
+
+       if (!IS_ENABLED(CONFIG_USB_GADGET_DEBUG_FS))
+               return;
+
+       root = debugfs_create_dir(udc->gadget.name, NULL);
+       if (IS_ERR(root) || !root)
+               goto err_root;
+
+       usbd = debugfs_create_file("usbd", 0400, root, udc,
+                       &usbd_dbg_fops);
+       if (!usbd)
+               goto err_usbd;
+       iudma = debugfs_create_file("iudma", 0400, root, udc,
+                       &iudma_dbg_fops);
+       if (!iudma)
+               goto err_iudma;
+
+       udc->debugfs_root = root;
+       udc->debugfs_usbd = usbd;
+       udc->debugfs_iudma = iudma;
+       return;
+err_iudma:
+       debugfs_remove(usbd);
+err_usbd:
+       debugfs_remove(root);
+err_root:
+       dev_err(udc->dev, "debugfs is not available\n");
+}
+
+/**
+ * bcm63xx_udc_cleanup_debugfs - Remove debugfs entries.
+ * @udc: Reference to the device controller.
+ *
+ * debugfs_remove() is safe to call with a NULL argument.
+ */
+static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
+{
+       debugfs_remove(udc->debugfs_iudma);
+       debugfs_remove(udc->debugfs_usbd);
+       debugfs_remove(udc->debugfs_root);
+       udc->debugfs_iudma = NULL;
+       udc->debugfs_usbd = NULL;
+       udc->debugfs_root = NULL;
+}
+
+/***********************************************************************
+ * Driver init/exit
+ ***********************************************************************/
+
+/**
+ * bcm63xx_udc_gadget_release - Called from device_release().
+ * @dev: Unused.
+ *
+ * We get a warning if this function doesn't exist, but it's empty because
+ * we don't have to free any of the memory allocated with the devm_* APIs.
+ */
+static void bcm63xx_udc_gadget_release(struct device *dev)
+{
+}
+
+/**
+ * bcm63xx_udc_probe - Initialize a new instance of the UDC.
+ * @pdev: Platform device struct from the bcm63xx BSP code.
+ *
+ * Note that platform data is required, because pd.port_no varies from chip
+ * to chip and is used to switch the correct USB port to device mode.
+ */
+static int __devinit bcm63xx_udc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct bcm63xx_usbd_platform_data *pd = dev->platform_data;
+       struct bcm63xx_udc *udc;
+       struct resource *res;
+       int rc = -ENOMEM, i, irq;
+
+       udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
+       if (!udc) {
+               dev_err(dev, "cannot allocate memory\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, udc);
+       udc->dev = dev;
+       udc->pd = pd;
+
+       if (!pd) {
+               dev_err(dev, "missing platform data\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "error finding USBD resource\n");
+               return -ENXIO;
+       }
+       udc->usbd_regs = devm_request_and_ioremap(dev, res);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(dev, "error finding IUDMA resource\n");
+               return -ENXIO;
+       }
+       udc->iudma_regs = devm_request_and_ioremap(dev, res);
+
+       if (!udc->usbd_regs || !udc->iudma_regs) {
+               dev_err(dev, "error requesting resources\n");
+               return -ENXIO;
+       }
+
+       spin_lock_init(&udc->lock);
+       INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
+       dev_set_name(&udc->gadget.dev, "gadget");
+
+       udc->gadget.ops = &bcm63xx_udc_ops;
+       udc->gadget.name = dev_name(dev);
+       udc->gadget.dev.parent = dev;
+       udc->gadget.dev.release = bcm63xx_udc_gadget_release;
+       udc->gadget.dev.dma_mask = dev->dma_mask;
+
+       if (!pd->use_fullspeed && !use_fullspeed)
+               udc->gadget.max_speed = USB_SPEED_HIGH;
+       else
+               udc->gadget.max_speed = USB_SPEED_FULL;
+
+       /* request clocks, allocate buffers, and clear any pending IRQs */
+       rc = bcm63xx_init_udc_hw(udc);
+       if (rc)
+               return rc;
+
+       rc = -ENXIO;
+
+       /* IRQ resource #0: control interrupt (VBUS, speed, etc.) */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "missing IRQ resource #0\n");
+               goto out_uninit;
+       }
+       if (devm_request_irq(dev, irq, &bcm63xx_udc_ctrl_isr, 0,
+                            dev_name(dev), udc) < 0) {
+               dev_err(dev, "error requesting IRQ #%d\n", irq);
+               goto out_uninit;
+       }
+
+       /* IRQ resources #1-6: data interrupts for IUDMA channels 0-5 */
+       for (i = 0; i < BCM63XX_NUM_IUDMA; i++) {
+               irq = platform_get_irq(pdev, i + 1);
+               if (irq < 0) {
+                       dev_err(dev, "missing IRQ resource #%d\n", i + 1);
+                       goto out_uninit;
+               }
+               if (devm_request_irq(dev, irq, &bcm63xx_udc_data_isr, 0,
+                                    dev_name(dev), &udc->iudma[i]) < 0) {
+                       dev_err(dev, "error requesting IRQ #%d\n", irq);
+                       goto out_uninit;
+               }
+       }
+
+       rc = device_register(&udc->gadget.dev);
+       if (rc)
+               goto out_uninit;
+
+       bcm63xx_udc_init_debugfs(udc);
+       rc = usb_add_gadget_udc(dev, &udc->gadget);
+       if (!rc)
+               return 0;
+
+       bcm63xx_udc_cleanup_debugfs(udc);
+       device_unregister(&udc->gadget.dev);
+out_uninit:
+       bcm63xx_uninit_udc_hw(udc);
+       return rc;
+}
+
+/**
+ * bcm63xx_udc_remove - Remove the device from the system.
+ * @pdev: Platform device struct from the bcm63xx BSP code.
+ */
+static int __devexit bcm63xx_udc_remove(struct platform_device *pdev)
+{
+       struct bcm63xx_udc *udc = platform_get_drvdata(pdev);
+
+       bcm63xx_udc_cleanup_debugfs(udc);
+       usb_del_gadget_udc(&udc->gadget);
+       device_unregister(&udc->gadget.dev);
+       BUG_ON(udc->driver);
+
+       platform_set_drvdata(pdev, NULL);
+       bcm63xx_uninit_udc_hw(udc);
+
+       return 0;
+}
+
+static struct platform_driver bcm63xx_udc_driver = {
+       .probe          = bcm63xx_udc_probe,
+       .remove         = __devexit_p(bcm63xx_udc_remove),
+       .driver         = {
+               .name   = DRV_MODULE_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+module_platform_driver(bcm63xx_udc_driver);
+
+MODULE_DESCRIPTION("BCM63xx USB Peripheral Controller");
+MODULE_AUTHOR("Kevin Cernekee <cernekee@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
index 725550f06fab60c832b51da725ea3feb805b32d7..1e4bb77f00bb76a60de66170f118d3fb5ea8360e 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 
 #include "u_ether.h"
@@ -34,6 +33,7 @@
 #define CDC_PRODUCT_NUM                0xa4aa  /* CDC Composite: ECM + ACM */
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /*
  * Kbuild is not very cooperative with respect to linking separately
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
 
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "u_serial.c"
 #include "f_acm.c"
 #include "f_ecm.c"
@@ -92,15 +88,10 @@ static const struct usb_descriptor_header *otg_desc[] = {
 
 
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        {  } /* end of list */
 };
 
@@ -152,7 +143,6 @@ static struct usb_configuration cdc_config_driver = {
 
 static int __init cdc_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
 
@@ -172,47 +162,22 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                goto fail0;
 
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       else {
-               /* We assume that can_support_ecm() tells the truth;
-                * but if the controller isn't recognized at all then
-                * that assumption is a bit more likely to be wrong.
-                */
-               WARNING(cdev, "controller '%s' not recognized; trying %s\n",
-                               gadget->name,
-                               cdc_config_driver.label);
-               device_desc.bcdDevice =
-                       cpu_to_le16(0x0300 | 0x0099);
-       }
-
-
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
 
-       /* device descriptor strings: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail1;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto fail1;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        /* register our configuration */
        status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config);
        if (status < 0)
                goto fail1;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
                        DRIVER_DESC);
 
@@ -232,11 +197,12 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver cdc_driver = {
+static __refdata struct usb_composite_driver cdc_driver = {
        .name           = "g_cdc",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = cdc_bind,
        .unbind         = __exit_p(cdc_unbind),
 };
 
@@ -246,7 +212,7 @@ MODULE_LICENSE("GPL");
 
 static int __init init(void)
 {
-       return usb_composite_probe(&cdc_driver, cdc_bind);
+       return usb_composite_probe(&cdc_driver);
 }
 module_init(init);
 
index 3f72110da1b0113fd4f1f28243c6315609638010..957f973dd96ad6f069a8eddf084d448c7a34ff0f 100644 (file)
  * with the relevant device-wide data.
  */
 
-/* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ     1024
-
-static struct usb_composite_driver *composite;
-static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);
-
-/* Some systems will need runtime overrides for the  product identifiers
- * published in the device descriptor, either numbers or strings or both.
- * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
- */
-
-static ushort idVendor;
-module_param(idVendor, ushort, 0644);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, 0644);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, 0644);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, 0644);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, 0644);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
-static char *iSerialNumber;
-module_param(iSerialNumber, charp, 0644);
-MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
-
-static char composite_manufacturer[50];
-
-/*-------------------------------------------------------------------------*/
 /**
  * next_ep_desc() - advance to the next EP descriptor
  * @t: currect pointer within descriptor array
@@ -192,6 +154,7 @@ ep_found:
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(config_ep_by_speed);
 
 /**
  * usb_add_function() - add a function to a configuration
@@ -250,6 +213,7 @@ done:
                                function->name, function, value);
        return value;
 }
+EXPORT_SYMBOL_GPL(usb_add_function);
 
 /**
  * usb_function_deactivate - prevent function and gadget enumeration
@@ -286,6 +250,7 @@ int usb_function_deactivate(struct usb_function *function)
        spin_unlock_irqrestore(&cdev->lock, flags);
        return status;
 }
+EXPORT_SYMBOL_GPL(usb_function_deactivate);
 
 /**
  * usb_function_activate - allow function and gadget enumeration
@@ -300,9 +265,10 @@ int usb_function_deactivate(struct usb_function *function)
 int usb_function_activate(struct usb_function *function)
 {
        struct usb_composite_dev        *cdev = function->config->cdev;
+       unsigned long                   flags;
        int                             status = 0;
 
-       spin_lock(&cdev->lock);
+       spin_lock_irqsave(&cdev->lock, flags);
 
        if (WARN_ON(cdev->deactivations == 0))
                status = -EINVAL;
@@ -312,9 +278,10 @@ int usb_function_activate(struct usb_function *function)
                        status = usb_gadget_connect(cdev->gadget);
        }
 
-       spin_unlock(&cdev->lock);
+       spin_unlock_irqrestore(&cdev->lock, flags);
        return status;
 }
+EXPORT_SYMBOL_GPL(usb_function_activate);
 
 /**
  * usb_interface_id() - allocate an unused interface ID
@@ -351,16 +318,18 @@ int usb_interface_id(struct usb_configuration *config,
        }
        return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(usb_interface_id);
 
 static int config_buf(struct usb_configuration *config,
                enum usb_device_speed speed, void *buf, u8 type)
 {
        struct usb_config_descriptor    *c = buf;
        void                            *next = buf + USB_DT_CONFIG_SIZE;
-       int                             len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
+       int                             len;
        struct usb_function             *f;
        int                             status;
 
+       len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;
        /* write the config descriptor */
        c = buf;
        c->bLength = USB_DT_CONFIG_SIZE;
@@ -790,6 +759,7 @@ done:
                                config->bConfigurationValue, status);
        return status;
 }
+EXPORT_SYMBOL_GPL(usb_add_config);
 
 static void remove_config(struct usb_composite_dev *cdev,
                              struct usb_configuration *config)
@@ -889,10 +859,10 @@ static int lookup_string(
 static int get_string(struct usb_composite_dev *cdev,
                void *buf, u16 language, int id)
 {
+       struct usb_composite_driver     *composite = cdev->driver;
        struct usb_configuration        *c;
        struct usb_function             *f;
        int                             len;
-       const char                      *str;
 
        /* Yes, not only is USB's I18N support probably more than most
         * folk will ever care about ... also, it's all supported here.
@@ -932,26 +902,6 @@ static int get_string(struct usb_composite_dev *cdev,
                return s->bLength;
        }
 
-       /* Otherwise, look up and return a specified string.  First
-        * check if the string has not been overridden.
-        */
-       if (cdev->manufacturer_override == id)
-               str = iManufacturer ?: composite->iManufacturer ?:
-                       composite_manufacturer;
-       else if (cdev->product_override == id)
-               str = iProduct ?: composite->iProduct;
-       else if (cdev->serial_override == id)
-               str = iSerialNumber ?: composite->iSerialNumber;
-       else
-               str = NULL;
-       if (str) {
-               struct usb_gadget_strings strings = {
-                       .language = language,
-                       .strings  = &(struct usb_string) { 0xff, str }
-               };
-               return usb_gadget_get_string(&strings, 0xff, buf);
-       }
-
        /* String IDs are device-scoped, so we look up each string
         * table we're told about.  These lookups are infrequent;
         * simpler-is-better here.
@@ -1003,6 +953,7 @@ int usb_string_id(struct usb_composite_dev *cdev)
        }
        return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(usb_string_id);
 
 /**
  * usb_string_ids() - allocate unused string IDs in batch
@@ -1034,6 +985,7 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_string_ids_tab);
 
 /**
  * usb_string_ids_n() - allocate unused string IDs in batch
@@ -1062,7 +1014,7 @@ int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
        c->next_string_id += n;
        return next + 1;
 }
-
+EXPORT_SYMBOL_GPL(usb_string_ids_n);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1359,8 +1311,8 @@ static void composite_disconnect(struct usb_gadget *gadget)
        spin_lock_irqsave(&cdev->lock, flags);
        if (cdev->config)
                reset_config(cdev);
-       if (composite->disconnect)
-               composite->disconnect(cdev);
+       if (cdev->driver->disconnect)
+               cdev->driver->disconnect(cdev);
        spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
@@ -1396,35 +1348,67 @@ composite_unbind(struct usb_gadget *gadget)
                                struct usb_configuration, list);
                remove_config(cdev, c);
        }
-       if (composite->unbind)
-               composite->unbind(cdev);
+       if (cdev->driver->unbind)
+               cdev->driver->unbind(cdev);
 
        if (cdev->req) {
                kfree(cdev->req->buf);
                usb_ep_free_request(gadget->ep0, cdev->req);
        }
        device_remove_file(&gadget->dev, &dev_attr_suspended);
+       kfree(cdev->def_manufacturer);
        kfree(cdev);
        set_gadget_data(gadget, NULL);
-       composite = NULL;
 }
 
-static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
+static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
+               const struct usb_device_descriptor *old)
 {
-       if (!*desc) {
-               int ret = usb_string_id(cdev);
-               if (unlikely(ret < 0))
-                       WARNING(cdev, "failed to override string ID\n");
-               else
-                       *desc = ret;
-       }
+       __le16 idVendor;
+       __le16 idProduct;
+       __le16 bcdDevice;
+       u8 iSerialNumber;
+       u8 iManufacturer;
+       u8 iProduct;
 
-       return *desc;
+       /*
+        * these variables may have been set in
+        * usb_composite_overwrite_options()
+        */
+       idVendor = new->idVendor;
+       idProduct = new->idProduct;
+       bcdDevice = new->bcdDevice;
+       iSerialNumber = new->iSerialNumber;
+       iManufacturer = new->iManufacturer;
+       iProduct = new->iProduct;
+
+       *new = *old;
+       if (idVendor)
+               new->idVendor = idVendor;
+       if (idProduct)
+               new->idProduct = idProduct;
+       if (bcdDevice)
+               new->bcdDevice = bcdDevice;
+       else
+               new->bcdDevice = cpu_to_le16(get_default_bcdDevice());
+       if (iSerialNumber)
+               new->iSerialNumber = iSerialNumber;
+       if (iManufacturer)
+               new->iManufacturer = iManufacturer;
+       if (iProduct)
+               new->iProduct = iProduct;
 }
 
-static int composite_bind(struct usb_gadget *gadget)
+static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv)
+{
+       return container_of(gdrv, struct usb_composite_driver, gadget_driver);
+}
+
+static int composite_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *gdriver)
 {
        struct usb_composite_dev        *cdev;
+       struct usb_composite_driver     *composite = to_cdriver(gdriver);
        int                             status = -ENOMEM;
 
        cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
@@ -1440,13 +1424,12 @@ static int composite_bind(struct usb_gadget *gadget)
        cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
        if (!cdev->req)
                goto fail;
-       cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
+       cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
        if (!cdev->req->buf)
                goto fail;
        cdev->req->complete = composite_setup_complete;
        gadget->ep0->driver_data = cdev;
 
-       cdev->bufsiz = USB_BUFSIZ;
        cdev->driver = composite;
 
        /*
@@ -1467,49 +1450,11 @@ static int composite_bind(struct usb_gadget *gadget)
         * serial number), register function drivers, potentially update
         * power state and consumption, etc
         */
-       status = composite_gadget_bind(cdev);
+       status = composite->bind(cdev);
        if (status < 0)
                goto fail;
 
-       cdev->desc = *composite->dev;
-
-       /* standardized runtime overrides for device ID data */
-       if (idVendor)
-               cdev->desc.idVendor = cpu_to_le16(idVendor);
-       else
-               idVendor = le16_to_cpu(cdev->desc.idVendor);
-       if (idProduct)
-               cdev->desc.idProduct = cpu_to_le16(idProduct);
-       else
-               idProduct = le16_to_cpu(cdev->desc.idProduct);
-       if (bcdDevice)
-               cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-       else
-               bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
-
-       /* string overrides */
-       if (iManufacturer || !cdev->desc.iManufacturer) {
-               if (!iManufacturer && !composite->iManufacturer &&
-                   !*composite_manufacturer)
-                       snprintf(composite_manufacturer,
-                                sizeof composite_manufacturer,
-                                "%s %s with %s",
-                                init_utsname()->sysname,
-                                init_utsname()->release,
-                                gadget->name);
-
-               cdev->manufacturer_override =
-                       override_id(cdev, &cdev->desc.iManufacturer);
-       }
-
-       if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
-               cdev->product_override =
-                       override_id(cdev, &cdev->desc.iProduct);
-
-       if (iSerialNumber ||
-           (!cdev->desc.iSerialNumber && composite->iSerialNumber))
-               cdev->serial_override =
-                       override_id(cdev, &cdev->desc.iSerialNumber);
+       update_unchanged_dev_desc(&cdev->desc, composite->dev);
 
        /* has userspace failed to provide a serial number? */
        if (composite->needs_serial && !cdev->desc.iSerialNumber)
@@ -1546,8 +1491,8 @@ composite_suspend(struct usb_gadget *gadget)
                                f->suspend(f);
                }
        }
-       if (composite->suspend)
-               composite->suspend(cdev);
+       if (cdev->driver->suspend)
+               cdev->driver->suspend(cdev);
 
        cdev->suspended = 1;
 
@@ -1565,8 +1510,8 @@ composite_resume(struct usb_gadget *gadget)
         * suspend/resume callbacks?
         */
        DBG(cdev, "resume\n");
-       if (composite->resume)
-               composite->resume(cdev);
+       if (cdev->driver->resume)
+               cdev->driver->resume(cdev);
        if (cdev->config) {
                list_for_each_entry(f, &cdev->config->functions, list) {
                        if (f->resume)
@@ -1584,13 +1529,8 @@ composite_resume(struct usb_gadget *gadget)
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver composite_driver = {
-#ifdef CONFIG_USB_GADGET_SUPERSPEED
-       .max_speed      = USB_SPEED_SUPER,
-#else
-       .max_speed      = USB_SPEED_HIGH,
-#endif
-
+static const struct usb_gadget_driver composite_driver_template = {
+       .bind           = composite_bind,
        .unbind         = composite_unbind,
 
        .setup          = composite_setup,
@@ -1623,25 +1563,26 @@ static struct usb_gadget_driver composite_driver = {
  * while it was binding.  That would usually be done in order to wait for
  * some userspace participation.
  */
-int usb_composite_probe(struct usb_composite_driver *driver,
-                              int (*bind)(struct usb_composite_dev *cdev))
+int usb_composite_probe(struct usb_composite_driver *driver)
 {
-       if (!driver || !driver->dev || !bind || composite)
+       struct usb_gadget_driver *gadget_driver;
+
+       if (!driver || !driver->dev || !driver->bind)
                return -EINVAL;
 
        if (!driver->name)
                driver->name = "composite";
-       if (!driver->iProduct)
-               driver->iProduct = driver->name;
-       composite_driver.function =  (char *) driver->name;
-       composite_driver.driver.name = driver->name;
-       composite_driver.max_speed =
-               min_t(u8, composite_driver.max_speed, driver->max_speed);
-       composite = driver;
-       composite_gadget_bind = bind;
-
-       return usb_gadget_probe_driver(&composite_driver, composite_bind);
+
+       driver->gadget_driver = composite_driver_template;
+       gadget_driver = &driver->gadget_driver;
+
+       gadget_driver->function =  (char *) driver->name;
+       gadget_driver->driver.name = driver->name;
+       gadget_driver->max_speed = driver->max_speed;
+
+       return usb_gadget_probe_driver(gadget_driver);
 }
+EXPORT_SYMBOL_GPL(usb_composite_probe);
 
 /**
  * usb_composite_unregister() - unregister a composite driver
@@ -1652,10 +1593,9 @@ int usb_composite_probe(struct usb_composite_driver *driver,
  */
 void usb_composite_unregister(struct usb_composite_driver *driver)
 {
-       if (composite != driver)
-               return;
-       usb_gadget_unregister_driver(&composite_driver);
+       usb_gadget_unregister_driver(&driver->gadget_driver);
 }
+EXPORT_SYMBOL_GPL(usb_composite_unregister);
 
 /**
  * usb_composite_setup_continue() - Continue with the control transfer
@@ -1692,4 +1632,60 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev)
 
        spin_unlock_irqrestore(&cdev->lock, flags);
 }
+EXPORT_SYMBOL_GPL(usb_composite_setup_continue);
+
+static char *composite_default_mfr(struct usb_gadget *gadget)
+{
+       char *mfr;
+       int len;
+
+       len = snprintf(NULL, 0, "%s %s with %s", init_utsname()->sysname,
+                       init_utsname()->release, gadget->name);
+       len++;
+       mfr = kmalloc(len, GFP_KERNEL);
+       if (!mfr)
+               return NULL;
+       snprintf(mfr, len, "%s %s with %s", init_utsname()->sysname,
+                       init_utsname()->release, gadget->name);
+       return mfr;
+}
+
+void usb_composite_overwrite_options(struct usb_composite_dev *cdev,
+               struct usb_composite_overwrite *covr)
+{
+       struct usb_device_descriptor    *desc = &cdev->desc;
+       struct usb_gadget_strings       *gstr = cdev->driver->strings[0];
+       struct usb_string               *dev_str = gstr->strings;
+
+       if (covr->idVendor)
+               desc->idVendor = cpu_to_le16(covr->idVendor);
+
+       if (covr->idProduct)
+               desc->idProduct = cpu_to_le16(covr->idProduct);
+
+       if (covr->bcdDevice)
+               desc->bcdDevice = cpu_to_le16(covr->bcdDevice);
+
+       if (covr->serial_number) {
+               desc->iSerialNumber = dev_str[USB_GADGET_SERIAL_IDX].id;
+               dev_str[USB_GADGET_SERIAL_IDX].s = covr->serial_number;
+       }
+       if (covr->manufacturer) {
+               desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id;
+               dev_str[USB_GADGET_MANUFACTURER_IDX].s = covr->manufacturer;
+
+       } else if (!strlen(dev_str[USB_GADGET_MANUFACTURER_IDX].s)) {
+               desc->iManufacturer = dev_str[USB_GADGET_MANUFACTURER_IDX].id;
+               cdev->def_manufacturer = composite_default_mfr(cdev->gadget);
+               dev_str[USB_GADGET_MANUFACTURER_IDX].s = cdev->def_manufacturer;
+       }
+
+       if (covr->product) {
+               desc->iProduct = dev_str[USB_GADGET_PRODUCT_IDX].id;
+               dev_str[USB_GADGET_PRODUCT_IDX].s = covr->product;
+       }
+}
+EXPORT_SYMBOL_GPL(usb_composite_overwrite_options);
 
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Brownell");
index 7542a72ce51ae51a0cbf801650ea22a2f2cdd56b..e3a98929d3463d50ad395be7bf7fe08c92dfc983 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/device.h>
@@ -53,7 +54,7 @@ usb_descriptor_fillbuf(void *buf, unsigned buflen,
        }
        return dest - (u8 *)buf;
 }
-
+EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf);
 
 /**
  * usb_gadget_config_buf - builts a complete configuration descriptor
@@ -106,6 +107,7 @@ int usb_gadget_config_buf(
        cp->bmAttributes |= USB_CONFIG_ATT_ONE;
        return len;
 }
+EXPORT_SYMBOL_GPL(usb_gadget_config_buf);
 
 /**
  * usb_copy_descriptors - copy a vector of USB descriptors
@@ -155,4 +157,4 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
 
        return ret;
 }
-
+EXPORT_SYMBOL_GPL(usb_copy_descriptors);
index 19d7bb0df75a3515e0347ad6d03cda57c1c6e301..87d16502816298ec059ce5c7b59df7dfe80adb11 100644 (file)
@@ -13,9 +13,6 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
-/* See comments in "zero.c" */
-#include "epautoconf.c"
-
 #ifdef CONFIG_USB_G_DBGP_SERIAL
 #include "u_serial.c"
 #endif
@@ -292,7 +289,8 @@ fail_1:
        return -ENODEV;
 }
 
-static int __init dbgp_bind(struct usb_gadget *gadget)
+static int __init dbgp_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
 {
        int err, stp;
 
@@ -402,9 +400,10 @@ fail:
        return err;
 }
 
-static struct usb_gadget_driver dbgp_driver = {
+static __refdata struct usb_gadget_driver dbgp_driver = {
        .function = "dbgp",
        .max_speed = USB_SPEED_HIGH,
+       .bind = dbgp_bind,
        .unbind = dbgp_unbind,
        .setup = dbgp_setup,
        .disconnect = dbgp_disconnect,
@@ -416,7 +415,7 @@ static struct usb_gadget_driver dbgp_driver = {
 
 static int __init dbgp_init(void)
 {
-       return usb_gadget_probe_driver(&dbgp_driver, dbgp_bind);
+       return usb_gadget_probe_driver(&dbgp_driver);
 }
 
 static void __exit dbgp_exit(void)
index b799106027adfc5d75a45244a47fbd015bedfd20..91916f693ff7462238f8ae0a51f79b00f3c7b9a1 100644 (file)
@@ -909,6 +909,7 @@ static int dummy_udc_start(struct usb_gadget *g,
        dum->devstatus = 0;
 
        dum->driver = driver;
+       dum->gadget.dev.driver = &driver->driver;
        dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
                        driver->driver.name);
        return 0;
@@ -923,6 +924,7 @@ static int dummy_udc_stop(struct usb_gadget *g,
        dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
                        driver->driver.name);
 
+       dum->gadget.dev.driver = NULL;
        dum->driver = NULL;
 
        return 0;
index 51f3d42f5a64808533c4412fb1d632c3accde8d1..a777f7bd11b46971c30d7aaef32080e5c7139e6f 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
 
 #include "gadget_chips.h"
 
-
-/* we must assign addresses for configurable endpoints (like net2280) */
-static unsigned epnum;
-
-// #define MANY_ENDPOINTS
-#ifdef MANY_ENDPOINTS
-/* more than 15 configurable endpoints */
-static unsigned in_epnum;
-#endif
-
-
 /*
  * This should work with endpoints from controller drivers sharing the
  * same endpoint naming convention.  By example:
@@ -176,16 +166,14 @@ ep_matches (
        if (isdigit (ep->name [2])) {
                u8      num = simple_strtoul (&ep->name [2], NULL, 10);
                desc->bEndpointAddress |= num;
-#ifdef MANY_ENDPOINTS
        } else if (desc->bEndpointAddress & USB_DIR_IN) {
-               if (++in_epnum > 15)
+               if (++gadget->in_epnum > 15)
                        return 0;
-               desc->bEndpointAddress = USB_DIR_IN | in_epnum;
-#endif
+               desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
        } else {
-               if (++epnum > 15)
+               if (++gadget->out_epnum > 15)
                        return 0;
-               desc->bEndpointAddress |= epnum;
+               desc->bEndpointAddress |= gadget->out_epnum;
        }
 
        /* report (variable) full speed bulk maxpacket */
@@ -328,6 +316,7 @@ found_ep:
        ep->comp_desc = NULL;
        return ep;
 }
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
 
 /**
  * usb_ep_autoconfig() - choose an endpoint matching the
@@ -367,7 +356,7 @@ struct usb_ep *usb_ep_autoconfig(
 {
        return usb_ep_autoconfig_ss(gadget, desc, NULL);
 }
-
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
 
 /**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
@@ -385,9 +374,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
        list_for_each_entry (ep, &gadget->ep_list, ep_list) {
                ep->driver_data = NULL;
        }
-#ifdef MANY_ENDPOINTS
-       in_epnum = 0;
-#endif
-       epnum = 0;
+       gadget->in_epnum = 0;
+       gadget->out_epnum = 0;
 }
-
+EXPORT_SYMBOL_GPL(usb_ep_autoconfig_reset);
index a28f6ffcd0f31683d701bfd527ba1c110c92be4a..18c3f423706e2855154e74495b6b56ab961995c3 100644 (file)
@@ -14,8 +14,6 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
-
 
 #if defined USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
@@ -102,11 +100,6 @@ static inline bool has_rndis(void)
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_ecm.c"
 #include "f_subset.c"
 #ifdef USB_ETH_RNDIS
@@ -117,6 +110,7 @@ static inline bool has_rndis(void)
 #include "u_ether.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
@@ -195,17 +189,10 @@ static const struct usb_descriptor_header *otg_desc[] = {
        NULL,
 };
 
-
-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        {  } /* end of list */
 };
 
@@ -288,7 +275,6 @@ static struct usb_configuration eth_config_driver = {
 
 static int __init eth_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
 
@@ -323,42 +309,15 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
                device_desc.bNumConfigurations = 2;
        }
 
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       else {
-               /* We assume that can_support_ecm() tells the truth;
-                * but if the controller isn't recognized at all then
-                * that assumption is a bit more likely to be wrong.
-                */
-               dev_warn(&gadget->dev,
-                               "controller '%s' not recognized; trying %s\n",
-                               gadget->name,
-                               eth_config_driver.label);
-               device_desc.bcdDevice =
-                       cpu_to_le16(0x0300 | 0x0099);
-       }
-
-
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
 
-       /* device descriptor strings: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto fail;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        /* register our configuration(s); RNDIS first, if it's used */
        if (has_rndis()) {
@@ -372,6 +331,7 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                goto fail;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
                        DRIVER_DESC);
 
@@ -388,11 +348,12 @@ static int __exit eth_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver eth_driver = {
+static __refdata struct usb_composite_driver eth_driver = {
        .name           = "g_ether",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_SUPER,
+       .bind           = eth_bind,
        .unbind         = __exit_p(eth_unbind),
 };
 
@@ -402,7 +363,7 @@ MODULE_LICENSE("GPL");
 
 static int __init init(void)
 {
-       return usb_composite_probe(&eth_driver, eth_bind);
+       return usb_composite_probe(&eth_driver);
 }
 module_init(init);
 
index 30b908f2a53da7a42b285aad2311a249fda3b776..95bc94f8e57066a743428571707540d71775e751 100644 (file)
@@ -897,10 +897,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
                return -ENOMEM;
 
        /* export host's Ethernet address in CDC format */
-       snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
-               "%02X%02X%02X%02X%02X%02X",
-               ethaddr[0], ethaddr[1], ethaddr[2],
-               ethaddr[3], ethaddr[4], ethaddr[5]);
+       snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
        ecm_string_defs[1].s = ecm->ethaddr;
 
        ecm->port.cdc_filter = DEFAULT_FILTER;
index 16a8b1c15c626bf43dbfa5b2e7f294bf5ecf2385..511e527178e23d0e3cb3787700b5f7cc4f3baa32 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 #include <linux/hid.h>
 #include <linux/cdev.h>
@@ -18,6 +17,7 @@
 #include <linux/poll.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
+#include <linux/sched.h>
 #include <linux/usb/g_hid.h>
 
 static int major, minors;
index 4f1142efa6d13888fc0bc3298ccc1d37775047c8..3a7668bde3ef44bfc752f98ef1ebce7da531e885 100644 (file)
 #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>
@@ -349,7 +348,6 @@ struct fsg_config {
 
        const char *vendor_name;                /*  8 characters or less */
        const char *product_name;               /* 16 characters or less */
-       u16 release;
 
        char                    can_stall;
 };
@@ -2773,18 +2771,7 @@ buffhds_first_it:
        bh->next = common->buffhds;
 
        /* Prepare inquiryString */
-       if (cfg->release != 0xffff) {
-               i = cfg->release;
-       } else {
-               i = usb_gadget_controller_number(gadget);
-               if (i >= 0) {
-                       i = 0x0300 + i;
-               } else {
-                       WARNING(common, "controller '%s' not recognized\n",
-                               gadget->name);
-                       i = 0x0399;
-               }
-       }
+       i = get_default_bcdDevice();
        snprintf(common->inquiry_string, sizeof common->inquiry_string,
                 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
                 /* Assume product name dependent on the first LUN */
@@ -3110,7 +3097,6 @@ fsg_config_from_params(struct fsg_config *cfg,
        /* Let MSF use defaults */
        cfg->vendor_name = 0;
        cfg->product_name = 0;
-       cfg->release = 0xffff;
 
        cfg->ops = NULL;
        cfg->private_data = NULL;
index 2f7e8f2930cc3367847ab68dc06ead22a2a6ab60..8ed1259fe80d0f91bff200abf9d7b6c11966af5a 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 
 #include <sound/core.h>
index aab8eded045b0281aba42ce0844570b25c3396a7..b651b529c67f070dcd4a545cea8cfc40010602f3 100644 (file)
@@ -1346,10 +1346,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
                return -ENOMEM;
 
        /* export host's Ethernet address in CDC format */
-       snprintf(ncm->ethaddr, sizeof ncm->ethaddr,
-               "%02X%02X%02X%02X%02X%02X",
-               ethaddr[0], ethaddr[1], ethaddr[2],
-               ethaddr[3], ethaddr[4], ethaddr[5]);
+       snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr);
        ncm_string_defs[1].s = ncm->ethaddr;
 
        spin_lock_init(&ncm->lock);
index 5c1b68b63c98da1e2182e74a8c92d3b3874fbdb1..3c126fde6e7e7131168c47805a32f94379b68fcc 100644 (file)
@@ -795,7 +795,7 @@ static int sourcesink_setup(struct usb_configuration *c,
        u16                     w_value = le16_to_cpu(ctrl->wValue);
        u16                     w_length = le16_to_cpu(ctrl->wLength);
 
-       req->length = USB_BUFSIZ;
+       req->length = USB_COMP_EP0_BUFSIZ;
 
        /* composite driver infrastructure handles everything except
         * the two control test requests.
index 21ab474aca07ae266a44bc43b3e42dc184a6f318..4060c0bd9785cf5a033b2e30981374fd0cdc5fb0 100644 (file)
@@ -436,10 +436,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
                return -ENOMEM;
 
        /* export host's Ethernet address in CDC format */
-       snprintf(geth->ethaddr, sizeof geth->ethaddr,
-               "%02X%02X%02X%02X%02X%02X",
-               ethaddr[0], ethaddr[1], ethaddr[2],
-               ethaddr[3], ethaddr[4], ethaddr[5]);
+       snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
        geth_string_defs[1].s = geth->ethaddr;
 
        geth->port.cdc_filter = DEFAULT_FILTER;
index e7cc4de93e33d5ce4c61dc3a20f1001ed2c794bf..d3c6cffccb72c0566cb7c1daad4c613d3e501e4c 100644 (file)
@@ -463,7 +463,7 @@ snd_fail:
        return err;
 }
 
-static int __devexit snd_uac2_remove(struct platform_device *pdev)
+static int snd_uac2_remove(struct platform_device *pdev)
 {
        struct snd_card *card = platform_get_drvdata(pdev);
 
index a896d73f7a9336f5a34015c44ea5a6b04ce34f10..3f7d640b6758efd09ab4aa93cfb938c0220dac48 100644 (file)
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
+#include <linux/usb/composite.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"
@@ -3213,7 +3199,6 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 static int __init check_parameters(struct fsg_dev *fsg)
 {
        int     prot;
-       int     gcnum;
 
        /* Store the default values */
        mod_data.transport_type = USB_PR_BULK;
@@ -3228,16 +3213,8 @@ static int __init check_parameters(struct fsg_dev *fsg)
        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;
-               }
-       }
+       if (mod_data.release == 0xffff)
+               mod_data.release = get_default_bcdDevice();
 
        prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
 
@@ -3331,7 +3308,8 @@ static int __init check_parameters(struct fsg_dev *fsg)
 }
 
 
-static int __init fsg_bind(struct usb_gadget *gadget)
+static int __init fsg_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
 {
        struct fsg_dev          *fsg = the_fsg;
        int                     rc;
@@ -3603,9 +3581,10 @@ static void fsg_resume(struct usb_gadget *gadget)
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver                fsg_driver = {
+static __refdata struct usb_gadget_driver              fsg_driver = {
        .max_speed      = USB_SPEED_SUPER,
        .function       = (char *) fsg_string_product,
+       .bind           = fsg_bind,
        .unbind         = fsg_unbind,
        .disconnect     = fsg_disconnect,
        .setup          = fsg_setup,
@@ -3653,7 +3632,8 @@ static int __init fsg_init(void)
        if ((rc = fsg_alloc()) != 0)
                return rc;
        fsg = the_fsg;
-       if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
+       rc = usb_gadget_probe_driver(&fsg_driver);
+       if (rc != 0)
                kref_put(&fsg->ref, fsg_release);
        return rc;
 }
index 3def828f85e7fe5ad31a3eaf5c4bf5e71bbf1458..6ae70cba0c4a99684b51b3e8cbbce890c63aaff1 100644 (file)
@@ -1255,7 +1255,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
 }
 
 static int fsl_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int fsl_stop(struct usb_gadget_driver *driver);
 /* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
@@ -1951,7 +1951,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
  * Called by initialization code of gadget drivers
 *----------------------------------------------------------------*/
 static int fsl_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        int retval = -ENODEV;
        unsigned long flags = 0;
@@ -1976,7 +1976,7 @@ static int fsl_start(struct usb_gadget_driver *driver,
        spin_unlock_irqrestore(&udc_controller->lock, flags);
 
        /* bind udc driver to gadget driver */
-       retval = bind(&udc_controller->gadget);
+       retval = bind(&udc_controller->gadget, driver);
        if (retval) {
                VDBG("bind to %s --> %d", driver->driver.name, retval);
                udc_controller->gadget.dev.driver = NULL;
index cdd94540e1cdf7d1c9ead21f2a6a8b29c6f46f16..72cd5e6719db3e4fde63929b19e579f2fc897ee0 100644 (file)
@@ -1311,7 +1311,7 @@ static void init_controller(struct fusb300 *fusb300)
 static struct fusb300 *the_controller;
 
 static int fusb300_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct fusb300 *fusb300 = the_controller;
        int retval;
@@ -1339,7 +1339,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver,
                goto error;
        }
 
-       retval = bind(&fusb300->gadget);
+       retval = bind(&fusb300->gadget, driver);
        if (retval) {
                pr_err("bind to driver error (%d)\n", retval);
                device_del(&fusb300->gadget.dev);
index d3ace9002a6a1e7413e5efe1b58e48a7f82437b3..3953dd4d7186827d0ee65b3e631701a093e7f618 100644 (file)
@@ -13,7 +13,6 @@
 #define pr_fmt(fmt) "g_ffs: " fmt
 
 #include <linux/module.h>
-#include <linux/utsname.h>
 
 /*
  * kbuild is not very cooperative with respect to linking separately
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
 #  if defined USB_ETH_RNDIS
 #    undef USB_ETH_RNDIS
@@ -76,6 +69,8 @@ struct gfs_ffs_obj {
        struct ffs_data *ffs_data;
 };
 
+USB_GADGET_COMPOSITE_OPTIONS();
+
 static struct usb_device_descriptor gfs_dev_desc = {
        .bLength                = sizeof gfs_dev_desc,
        .bDescriptorType        = USB_DT_DEVICE,
@@ -117,6 +112,9 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
 
 /* String IDs are assigned dynamically */
 static struct usb_string gfs_strings[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        { .s = "FunctionFS + RNDIS" },
 #endif
@@ -163,13 +161,13 @@ static int gfs_bind(struct usb_composite_dev *cdev);
 static int gfs_unbind(struct usb_composite_dev *cdev);
 static int gfs_do_config(struct usb_configuration *c);
 
-static struct usb_composite_driver gfs_driver = {
+static __refdata struct usb_composite_driver gfs_driver = {
        .name           = DRIVER_NAME,
        .dev            = &gfs_dev_desc,
        .strings        = gfs_dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = gfs_bind,
        .unbind         = gfs_unbind,
-       .iProduct       = DRIVER_DESC,
 };
 
 static DEFINE_MUTEX(gfs_lock);
@@ -268,7 +266,7 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
        }
        gfs_registered = true;
 
-       ret = usb_composite_probe(&gfs_driver, gfs_bind);
+       ret = usb_composite_probe(&gfs_driver);
        if (unlikely(ret < 0))
                gfs_registered = false;
 
@@ -357,6 +355,7 @@ static int gfs_bind(struct usb_composite_dev *cdev)
        ret = usb_string_ids_tab(cdev, gfs_strings);
        if (unlikely(ret < 0))
                goto error;
+       gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
 
        for (i = func_num; --i; ) {
                ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
@@ -369,9 +368,10 @@ static int gfs_bind(struct usb_composite_dev *cdev)
 
        for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
                struct gfs_configuration *c = gfs_configurations + i;
+               int sid = USB_GADGET_FIRST_AVAIL_IDX + i;
 
-               c->c.label                      = gfs_strings[i].s;
-               c->c.iConfiguration             = gfs_strings[i].id;
+               c->c.label                      = gfs_strings[sid].s;
+               c->c.iConfiguration             = gfs_strings[sid].id;
                c->c.bConfigurationValue        = 1 + i;
                c->c.bmAttributes               = USB_CONFIG_ATT_SELFPOWER;
 
@@ -379,7 +379,7 @@ static int gfs_bind(struct usb_composite_dev *cdev)
                if (unlikely(ret < 0))
                        goto error_unbind;
        }
-
+       usb_composite_overwrite_options(cdev, &coverwrite);
        return 0;
 
 error_unbind:
index b8b3a3411218d74c48a045b4fb2be63531902fa3..bcd04bc66b98fdd1bc881b4319bd7b35dd78b186 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __GADGET_CHIPS_H
 #define __GADGET_CHIPS_H
 
+#include <linux/usb/gadget.h>
+
 /*
  * NOTICE: the entries below are alphabetical and should be kept
  * that way.
  * If you have forgotten the alphabetical order let VIM/EMACS
  * do that for you.
  */
-#define gadget_is_amd5536udc(g)                (!strcmp("amd5536udc", (g)->name))
 #define gadget_is_at91(g)              (!strcmp("at91_udc", (g)->name))
-#define gadget_is_atmel_usba(g)                (!strcmp("atmel_usba_udc", (g)->name))
-#define gadget_is_ci13xxx_msm(g)       (!strcmp("ci13xxx_msm", (g)->name))
-#define gadget_is_ci13xxx_pci(g)       (!strcmp("ci13xxx_pci", (g)->name))
-#define gadget_is_dummy(g)             (!strcmp("dummy_udc", (g)->name))
-#define gadget_is_dwc3(g)              (!strcmp("dwc3-gadget", (g)->name))
-#define gadget_is_fsl_qe(g)            (!strcmp("fsl_qe_udc", (g)->name))
-#define gadget_is_fsl_usb2(g)          (!strcmp("fsl-usb2-udc", (g)->name))
 #define gadget_is_goku(g)              (!strcmp("goku_udc", (g)->name))
-#define gadget_is_imx(g)               (!strcmp("imx_udc", (g)->name))
-#define gadget_is_langwell(g)          (!strcmp("langwell_udc", (g)->name))
-#define gadget_is_lpc32xx(g)           (!strcmp("lpc32xx_udc", (g)->name))
-#define gadget_is_m66592(g)            (!strcmp("m66592_udc", (g)->name))
 #define gadget_is_musbhdrc(g)          (!strcmp("musb-hdrc", (g)->name))
-#define gadget_is_net2272(g)           (!strcmp("net2272", (g)->name))
 #define gadget_is_net2280(g)           (!strcmp("net2280", (g)->name))
-#define gadget_is_omap(g)              (!strcmp("omap_udc", (g)->name))
-#define gadget_is_pch(g)               (!strcmp("pch_udc", (g)->name))
 #define gadget_is_pxa(g)               (!strcmp("pxa25x_udc", (g)->name))
 #define gadget_is_pxa27x(g)            (!strcmp("pxa27x_udc", (g)->name))
-#define gadget_is_r8a66597(g)          (!strcmp("r8a66597_udc", (g)->name))
-#define gadget_is_renesas_usbhs(g)     (!strcmp("renesas_usbhs_udc", (g)->name))
-#define gadget_is_s3c2410(g)           (!strcmp("s3c2410_udc", (g)->name))
-#define gadget_is_s3c_hsotg(g)         (!strcmp("s3c-hsotg", (g)->name))
-#define gadget_is_s3c_hsudc(g)         (!strcmp("s3c-hsudc", (g)->name))
-
-/**
- * usb_gadget_controller_number - support bcdDevice id convention
- * @gadget: the controller being driven
- *
- * Return a 2-digit BCD value associated with the peripheral controller,
- * suitable for use as part of a bcdDevice value, or a negative error code.
- *
- * NOTE:  this convention is purely optional, and has no meaning in terms of
- * any USB specification.  If you want to use a different convention in your
- * gadget driver firmware -- maybe a more formal revision ID -- feel free.
- *
- * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
- * to change their behavior accordingly.  For example it might help avoiding
- * some chip bug.
- */
-static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
-{
-       if (gadget_is_net2280(gadget))
-               return 0x01;
-       else if (gadget_is_dummy(gadget))
-               return 0x02;
-       else if (gadget_is_pxa(gadget))
-               return 0x03;
-       else if (gadget_is_goku(gadget))
-               return 0x06;
-       else if (gadget_is_omap(gadget))
-               return 0x08;
-       else if (gadget_is_pxa27x(gadget))
-               return 0x11;
-       else if (gadget_is_s3c2410(gadget))
-               return 0x12;
-       else if (gadget_is_at91(gadget))
-               return 0x13;
-       else if (gadget_is_imx(gadget))
-               return 0x14;
-       else if (gadget_is_musbhdrc(gadget))
-               return 0x16;
-       else if (gadget_is_atmel_usba(gadget))
-               return 0x18;
-       else if (gadget_is_fsl_usb2(gadget))
-               return 0x19;
-       else if (gadget_is_amd5536udc(gadget))
-               return 0x20;
-       else if (gadget_is_m66592(gadget))
-               return 0x21;
-       else if (gadget_is_fsl_qe(gadget))
-               return 0x22;
-       else if (gadget_is_ci13xxx_pci(gadget))
-               return 0x23;
-       else if (gadget_is_langwell(gadget))
-               return 0x24;
-       else if (gadget_is_r8a66597(gadget))
-               return 0x25;
-       else if (gadget_is_s3c_hsotg(gadget))
-               return 0x26;
-       else if (gadget_is_pch(gadget))
-               return 0x27;
-       else if (gadget_is_ci13xxx_msm(gadget))
-               return 0x28;
-       else if (gadget_is_renesas_usbhs(gadget))
-               return 0x29;
-       else if (gadget_is_s3c_hsudc(gadget))
-               return 0x30;
-       else if (gadget_is_net2272(gadget))
-               return 0x31;
-       else if (gadget_is_dwc3(gadget))
-               return 0x32;
-       else if (gadget_is_lpc32xx(gadget))
-               return 0x33;
-
-       return -ENOENT;
-}
-
 
 /**
  * gadget_supports_altsettings - return true if altsettings work
index 681bd038b1d8354f6317b7f23652f5667c584a68..881aab86ae990601c3e1af5a036fde190ead41de 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 #include <linux/device.h>
 
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
 #include "gadget_chips.h"
 
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "f_midi.c"
 
 /*-------------------------------------------------------------------------*/
@@ -51,6 +47,8 @@ MODULE_LICENSE("GPL v2");
 static const char shortname[] = "g_midi";
 static const char longname[] = "MIDI Gadget";
 
+USB_GADGET_COMPOSITE_OPTIONS();
+
 static int index = SNDRV_DEFAULT_IDX1;
 module_param(index, int, S_IRUGO);
 MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
@@ -85,9 +83,7 @@ MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-#define STRING_DESCRIPTION_IDX         2
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_device_descriptor device_desc = {
        .bLength =              USB_DT_DEVICE_SIZE,
@@ -102,8 +98,9 @@ static struct usb_device_descriptor device_desc = {
 };
 
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s     = "Grey Innovation",
-       [STRING_PRODUCT_IDX].s          = "MIDI Gadget",
+       [USB_GADGET_MANUFACTURER_IDX].s = "Grey Innovation",
+       [USB_GADGET_PRODUCT_IDX].s      = "MIDI Gadget",
+       [USB_GADGET_SERIAL_IDX].s       = "",
        [STRING_DESCRIPTION_IDX].s      = "MIDI",
        {  } /* end of list */
 };
@@ -140,61 +137,35 @@ static int __init midi_bind_config(struct usb_configuration *c)
 
 static int __init midi_bind(struct usb_composite_dev *cdev)
 {
-       struct usb_gadget *gadget = cdev->gadget;
-       int gcnum, status;
-
-       status = usb_string_id(cdev);
-       if (status < 0)
-               return status;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
+       int status;
 
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                return status;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
-
-       /* config description */
-       status = usb_string_id(cdev);
-       if (status < 0)
-               return status;
-       strings_dev[STRING_DESCRIPTION_IDX].id = status;
-
-       midi_config.iConfiguration = status;
-
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum < 0) {
-               /* gmidi is so simple (no altsettings) that
-                * it SHOULD NOT have problems with bulk-capable hardware.
-                * so warn about unrecognized controllers, don't panic.
-                */
-               pr_warning("%s: controller '%s' not recognized\n",
-                          __func__, gadget->name);
-               device_desc.bcdDevice = cpu_to_le16(0x9999);
-       } else {
-               device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-       }
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id;
 
        status = usb_add_config(cdev, &midi_config, midi_bind_config);
        if (status < 0)
                return status;
-
+       usb_composite_overwrite_options(cdev, &coverwrite);
        pr_info("%s\n", longname);
        return 0;
 }
 
-static struct usb_composite_driver midi_driver = {
+static __refdata struct usb_composite_driver midi_driver = {
        .name           = (char *) longname,
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = midi_bind,
        .unbind         = __exit_p(midi_unbind),
 };
 
 static int __init midi_init(void)
 {
-       return usb_composite_probe(&midi_driver, midi_bind);
+       return usb_composite_probe(&midi_driver);
 }
 module_init(midi_init);
 
index 9fd7886cfa9a7aac60035d7357e5ed00bfff40ff..51037cb7860421bacfa34430f5d6906e0f4a7bb8 100644 (file)
@@ -994,7 +994,7 @@ static int goku_get_frame(struct usb_gadget *_gadget)
 }
 
 static int goku_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int goku_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops goku_ops = {
@@ -1348,7 +1348,7 @@ static struct goku_udc    *the_controller;
  * the driver might get unbound.
  */
 static int goku_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct goku_udc *dev = the_controller;
        int                     retval;
@@ -1368,7 +1368,7 @@ static int goku_start(struct usb_gadget_driver *driver,
        driver->driver.bus = NULL;
        dev->driver = driver;
        dev->gadget.dev.driver = &driver->driver;
-       retval = bind(&dev->gadget);
+       retval = bind(&dev->gadget, driver);
        if (retval) {
                DBG(dev, "bind to driver %s --> error %d\n",
                                driver->driver.name, retval);
index 3493adf064f512bccc28358a202015188ff932e9..74130f6c12c0f2bdc2669ca57b07e8f025efdaeb 100644 (file)
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
 
+#include "gadget_chips.h"
 #define DRIVER_DESC            "HID Gadget"
 #define DRIVER_VERSION         "2010/03/16"
 
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_hid.c"
 
 
@@ -50,6 +47,7 @@ struct hidg_func_node {
 static LIST_HEAD(hidg_func_list);
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor device_desc = {
        .bLength =              sizeof device_desc,
@@ -92,15 +90,10 @@ static const struct usb_descriptor_header *otg_desc[] = {
 
 
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        {  } /* end of list */
 };
 
@@ -150,7 +143,7 @@ static int __init hid_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget *gadget = cdev->gadget;
        struct list_head *tmp;
-       int status, gcnum, funcs = 0;
+       int status, funcs = 0;
 
        list_for_each(tmp, &hidg_func_list)
                funcs++;
@@ -163,38 +156,22 @@ static int __init hid_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                return status;
 
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       else
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
-
-
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
 
-       /* device descriptor strings: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-       status = usb_string_id(cdev);
-       if (status < 0)
-               return status;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                return status;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        /* register our configuration */
        status = usb_add_config(cdev, &config_driver, do_config);
        if (status < 0)
                return status;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 
        return 0;
@@ -242,11 +219,12 @@ static int __devexit hidg_plat_driver_remove(struct platform_device *pdev)
 /****************************** Some noise ******************************/
 
 
-static struct usb_composite_driver hidg_driver = {
+static __refdata struct usb_composite_driver hidg_driver = {
        .name           = "g_hid",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = hid_bind,
        .unbind         = __exit_p(hid_unbind),
 };
 
@@ -272,7 +250,7 @@ static int __init hidg_init(void)
        if (status < 0)
                return status;
 
-       status = usb_composite_probe(&hidg_driver, hid_bind);
+       status = usb_composite_probe(&hidg_driver);
        if (status < 0)
                platform_driver_unregister(&hidg_plat_driver);
 
index e58b1644297172a8c1136fc78b2aea802df17f41..4bb6d53f2de3ff1bc3b97c05a28a8705a133e7a0 100644 (file)
@@ -828,7 +828,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                if (value == 0)
                        data->state = STATE_EP_ENABLED;
                break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
        case USB_SPEED_HIGH:
                /* fails if caller didn't provide that descriptor... */
                ep->desc = &data->hs_desc;
@@ -836,7 +835,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                if (value == 0)
                        data->state = STATE_EP_ENABLED;
                break;
-#endif
        default:
                DBG(data->dev, "unconnected, %s init abandoned\n",
                                data->name);
@@ -1324,7 +1322,6 @@ static const struct file_operations ep0_io_operations = {
  * Unrecognized ep0 requests may be handled in user space.
  */
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static void make_qualifier (struct dev_data *dev)
 {
        struct usb_qualifier_descriptor         qual;
@@ -1347,7 +1344,6 @@ static void make_qualifier (struct dev_data *dev)
 
        memcpy (dev->rbuf, &qual, sizeof qual);
 }
-#endif
 
 static int
 config_buf (struct dev_data *dev, u8 type, unsigned index)
@@ -1427,7 +1423,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
                        req->buf = dev->dev;
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
                        if (!dev->hs_config)
                                break;
@@ -1437,7 +1432,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        break;
                case USB_DT_OTHER_SPEED_CONFIG:
                        // FALLTHROUGH
-#endif
                case USB_DT_CONFIG:
                        value = config_buf (dev,
                                        w_value >> 8,
@@ -1685,8 +1679,8 @@ gadgetfs_unbind (struct usb_gadget *gadget)
 
 static struct dev_data         *the_device;
 
-static int
-gadgetfs_bind (struct usb_gadget *gadget)
+static int gadgetfs_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
 {
        struct dev_data         *dev = the_device;
 
@@ -1763,12 +1757,8 @@ gadgetfs_suspend (struct usb_gadget *gadget)
 }
 
 static struct usb_gadget_driver gadgetfs_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       .max_speed      = USB_SPEED_HIGH,
-#else
-       .max_speed      = USB_SPEED_FULL,
-#endif
        .function       = (char *) driver_desc,
+       .bind           = gadgetfs_bind,
        .unbind         = gadgetfs_unbind,
        .setup          = gadgetfs_setup,
        .disconnect     = gadgetfs_disconnect,
@@ -1783,7 +1773,8 @@ static struct usb_gadget_driver gadgetfs_driver = {
 
 static void gadgetfs_nop(struct usb_gadget *arg) { }
 
-static int gadgetfs_probe (struct usb_gadget *gadget)
+static int gadgetfs_probe(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
 {
        CHIP = gadget->name;
        return -EISNAM;
@@ -1791,6 +1782,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget)
 
 static struct usb_gadget_driver probe_driver = {
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = gadgetfs_probe,
        .unbind         = gadgetfs_nop,
        .setup          = (void *)gadgetfs_nop,
        .disconnect     = gadgetfs_nop,
@@ -1900,7 +1892,12 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 
        /* triggers gadgetfs_bind(); then we can enumerate. */
        spin_unlock_irq (&dev->lock);
-       value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind);
+       if (dev->hs_config)
+               gadgetfs_driver.max_speed = USB_SPEED_HIGH;
+       else
+               gadgetfs_driver.max_speed = USB_SPEED_FULL;
+
+       value = usb_gadget_probe_driver(&gadgetfs_driver);
        if (value != 0) {
                kfree (dev->buf);
                dev->buf = NULL;
@@ -2039,7 +2036,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
                return -ESRCH;
 
        /* fake probe to determine $CHIP */
-       (void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe);
+       usb_gadget_probe_driver(&probe_driver);
        if (!CHIP)
                return -ENODEV;
 
index f1ec99e69cb74bb74933f623238e7db83e2dc02a..f696fb9b136ded4b8c32ba8b360ef2550551f73d 100644 (file)
@@ -141,8 +141,6 @@ struct lpc32xx_ep {
        u32                     totalints;
 
        bool                    wedge;
-
-       const struct usb_endpoint_descriptor *desc;
 };
 
 /*
@@ -556,10 +554,8 @@ static int proc_udc_show(struct seq_file *s, void *unused)
 
        if (udc->enabled && udc->vbus) {
                proc_ep_show(s, &udc->ep[0]);
-               list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
-                       if (ep->desc)
-                               proc_ep_show(s, ep);
-               }
+               list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list)
+                       proc_ep_show(s, ep);
        }
 
        spin_unlock_irqrestore(&udc->lock, flags);
@@ -1453,7 +1449,6 @@ static void udc_reinit(struct lpc32xx_udc *udc)
 
                if (i != 0)
                        list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-               ep->desc = NULL;
                ep->ep.maxpacket = ep->maxpacket;
                INIT_LIST_HEAD(&ep->queue);
                ep->req_pending = 0;
@@ -1515,7 +1510,7 @@ static void nuke(struct lpc32xx_ep *ep, int status)
                done(ep, req, status);
        }
 
-       if (ep->desc && status == -ESHUTDOWN) {
+       if (status == -ESHUTDOWN) {
                uda_disable_hwepint(ep->udc, ep->hwep_num);
                udc_disable_hwep(ep->udc, ep->hwep_num);
        }
@@ -1658,9 +1653,6 @@ static int lpc32xx_ep_disable(struct usb_ep *_ep)
 
        nuke(ep, -ESHUTDOWN);
 
-       /* restore the endpoint's pristine config */
-       ep->desc = NULL;
-
        /* Clear all DMA statuses for this EP */
        udc_ep_dma_disable(udc, ep->hwep_num);
        writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
@@ -1696,7 +1688,7 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep,
        unsigned long flags;
 
        /* Verify EP data */
-       if ((!_ep) || (!ep) || (!desc) || (ep->desc) ||
+       if ((!_ep) || (!ep) || (!desc) ||
            (desc->bDescriptorType != USB_DT_ENDPOINT)) {
                dev_dbg(udc->dev, "bad ep or descriptor\n");
                return -EINVAL;
@@ -1754,7 +1746,6 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep,
 
        /* Initialize endpoint to match the selected descriptor */
        ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
-       ep->desc = desc;
        ep->ep.maxpacket = maxpacket;
 
        /* Map hardware endpoint from base and direction */
@@ -1837,7 +1828,7 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
 
        udc = ep->udc;
 
-       if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) {
+       if (!_ep) {
                dev_dbg(udc->dev, "invalid ep\n");
                return -EINVAL;
        }
@@ -1976,7 +1967,7 @@ static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value)
        struct lpc32xx_udc *udc = ep->udc;
        unsigned long flags;
 
-       if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1))
+       if ((!ep) || (ep->hwep_num <= 1))
                return -EINVAL;
 
        /* Don't halt an IN EP */
@@ -2262,7 +2253,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
        case USB_RECIP_ENDPOINT:
                tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
                ep = &udc->ep[tmp];
-               if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc))
+               if ((tmp == 0) || (tmp >= NUM_ENDPOINTS))
                        return -EOPNOTSUPP;
 
                if (wIndex & USB_DIR_IN) {
@@ -2599,9 +2590,8 @@ static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
-static int lpc32xx_start(struct usb_gadget_driver *driver,
-                        int (*bind)(struct usb_gadget *));
-static int lpc32xx_stop(struct usb_gadget_driver *driver);
+static int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *);
+static int lpc32xx_stop(struct usb_gadget *, struct usb_gadget_driver *);
 
 static const struct usb_gadget_ops lpc32xx_udc_ops = {
        .get_frame              = lpc32xx_get_frame,
@@ -2609,8 +2599,8 @@ static const struct usb_gadget_ops lpc32xx_udc_ops = {
        .set_selfpowered        = lpc32xx_set_selfpowered,
        .vbus_session           = lpc32xx_vbus_session,
        .pullup                 = lpc32xx_pullup,
-       .start                  = lpc32xx_start,
-       .stop                   = lpc32xx_stop,
+       .udc_start              = lpc32xx_start,
+       .udc_stop               = lpc32xx_stop,
 };
 
 static void nop_release(struct device *dev)
@@ -2618,10 +2608,9 @@ static void nop_release(struct device *dev)
        /* nothing to free */
 }
 
-static struct lpc32xx_udc controller = {
+static const struct lpc32xx_udc controller_template = {
        .gadget = {
                .ops    = &lpc32xx_udc_ops,
-               .ep0    = &controller.ep[0].ep,
                .name   = driver_name,
                .dev    = {
                        .init_name = "gadget",
@@ -2633,7 +2622,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep0",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 0,
                .hwep_num       = 0, /* Can be 0 or 1, has special handling */
@@ -2645,7 +2633,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep1-int",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 2,
                .hwep_num       = 0, /* 2 or 3, will be set later */
@@ -2657,7 +2644,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep2-bulk",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 4,
                .hwep_num       = 0, /* 4 or 5, will be set later */
@@ -2669,7 +2655,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep3-iso",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 1023,
                .hwep_num_base  = 6,
                .hwep_num       = 0, /* 6 or 7, will be set later */
@@ -2681,7 +2666,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep4-int",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 8,
                .hwep_num       = 0, /* 8 or 9, will be set later */
@@ -2693,7 +2677,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep5-bulk",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 10,
                .hwep_num       = 0, /* 10 or 11, will be set later */
@@ -2705,7 +2688,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep6-iso",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 1023,
                .hwep_num_base  = 12,
                .hwep_num       = 0, /* 12 or 13, will be set later */
@@ -2717,7 +2699,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep7-int",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 14,
                .hwep_num       = 0,
@@ -2729,7 +2710,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep8-bulk",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 16,
                .hwep_num       = 0,
@@ -2741,7 +2721,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep9-iso",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 1023,
                .hwep_num_base  = 18,
                .hwep_num       = 0,
@@ -2753,7 +2732,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep10-int",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 20,
                .hwep_num       = 0,
@@ -2765,7 +2743,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep11-bulk",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 22,
                .hwep_num       = 0,
@@ -2777,7 +2754,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep12-iso",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 1023,
                .hwep_num_base  = 24,
                .hwep_num       = 0,
@@ -2789,7 +2765,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep13-int",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 26,
                .hwep_num       = 0,
@@ -2801,7 +2776,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep14-bulk",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 64,
                .hwep_num_base  = 28,
                .hwep_num       = 0,
@@ -2813,7 +2787,6 @@ static struct lpc32xx_udc controller = {
                        .name   = "ep15-bulk",
                        .ops    = &lpc32xx_ep_ops,
                },
-               .udc            = &controller,
                .maxpacket      = 1023,
                .hwep_num_base  = 30,
                .hwep_num       = 0,
@@ -2987,14 +2960,13 @@ static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc)
        return IRQ_HANDLED;
 }
 
-static int lpc32xx_start(struct usb_gadget_driver *driver,
-                        int (*bind)(struct usb_gadget *))
+static int lpc32xx_start(struct usb_gadget *gadget,
+                        struct usb_gadget_driver *driver)
 {
-       struct lpc32xx_udc *udc = &controller;
-       int retval, i;
+       struct lpc32xx_udc *udc = to_udc(gadget);
+       int i;
 
-       if (!driver || driver->max_speed < USB_SPEED_FULL ||
-           !bind || !driver->setup) {
+       if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) {
                dev_err(udc->dev, "bad parameter.\n");
                return -EINVAL;
        }
@@ -3011,18 +2983,6 @@ static int lpc32xx_start(struct usb_gadget_driver *driver,
        udc->selfpowered = 1;
        udc->vbus = 0;
 
-       retval = bind(&udc->gadget);
-       if (retval) {
-               dev_err(udc->dev, "bind() returned %d\n", retval);
-               udc->enabled = 0;
-               udc->selfpowered = 0;
-               udc->driver = NULL;
-               udc->gadget.dev.driver = NULL;
-               return retval;
-       }
-
-       dev_dbg(udc->dev, "bound to %s\n", driver->driver.name);
-
        /* Force VBUS process once to check for cable insertion */
        udc->last_vbus = udc->vbus = 0;
        schedule_work(&udc->vbus_job);
@@ -3034,22 +2994,19 @@ static int lpc32xx_start(struct usb_gadget_driver *driver,
        return 0;
 }
 
-static int lpc32xx_stop(struct usb_gadget_driver *driver)
+static int lpc32xx_stop(struct usb_gadget *gadget,
+                       struct usb_gadget_driver *driver)
 {
        int i;
-       struct lpc32xx_udc *udc = &controller;
+       struct lpc32xx_udc *udc = to_udc(gadget);
 
-       if (!driver || driver != udc->driver || !driver->unbind)
+       if (!driver || driver != udc->driver)
                return -EINVAL;
 
-       /* Disable USB pullup */
-       isp1301_pullup_enable(udc, 0, 1);
-
        for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
                disable_irq(udc->udp_irq[i]);
 
        if (udc->clocked) {
-
                spin_lock(&udc->lock);
                stop_activity(udc);
                spin_unlock(&udc->lock);
@@ -3069,20 +3026,16 @@ static int lpc32xx_stop(struct usb_gadget_driver *driver)
        }
 
        udc->enabled = 0;
-       pullup(udc, 0);
-
-       driver->unbind(&udc->gadget);
        udc->gadget.dev.driver = NULL;
        udc->driver = NULL;
 
-       dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name);
        return 0;
 }
 
 static void lpc32xx_udc_shutdown(struct platform_device *dev)
 {
        /* Force disconnect on reboot */
-       struct lpc32xx_udc *udc = &controller;
+       struct lpc32xx_udc *udc = platform_get_drvdata(dev);
 
        pullup(udc, 0);
 }
@@ -3120,12 +3073,21 @@ static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F;
 static int __init lpc32xx_udc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct lpc32xx_udc *udc = &controller;
+       struct lpc32xx_udc *udc;
        int retval, i;
        struct resource *res;
        dma_addr_t dma_handle;
        struct device_node *isp1301_node;
 
+       udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+       if (!udc)
+               return -ENOMEM;
+
+       memcpy(udc, &controller_template, sizeof(*udc));
+       for (i = 0; i <= 15; i++)
+               udc->ep[i].udc = udc;
+       udc->gadget.ep0 = &udc->ep[0].ep;
+
        /* init software state */
        udc->gadget.dev.parent = dev;
        udc->pdev = pdev;
@@ -3140,8 +3102,10 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
        }
 
        udc->isp1301_i2c_client = isp1301_get_client(isp1301_node);
-       if (!udc->isp1301_i2c_client)
-               return -EPROBE_DEFER;
+       if (!udc->isp1301_i2c_client) {
+               retval = -EPROBE_DEFER;
+               goto phy_fail;
+       }
 
        dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n",
                 udc->isp1301_i2c_client->addr);
@@ -3160,8 +3124,10 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
         *  IORESOURCE_IRQ, USB transceiver interrupt number
         */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
+       if (!res) {
+               retval = -ENXIO;
+               goto resource_fail;
+       }
 
        spin_lock_init(&udc->lock);
 
@@ -3171,7 +3137,8 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
                if (udc->udp_irq[i] < 0) {
                        dev_err(udc->dev,
                                "irq resource %d not available!\n", i);
-                       return udc->udp_irq[i];
+                       retval = udc->udp_irq[i];
+                       goto irq_fail;
                }
        }
 
@@ -3179,7 +3146,8 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
        udc->io_p_size = resource_size(res);
        if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) {
                dev_err(udc->dev, "someone's using UDC memory\n");
-               return -EBUSY;
+               retval = -EBUSY;
+               goto request_mem_region_fail;
        }
 
        udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size);
@@ -3208,7 +3176,7 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
        udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
        if (IS_ERR(udc->usb_otg_clk)) {
                dev_err(udc->dev, "failed to acquire USB otg clock\n");
-               retval = PTR_ERR(udc->usb_slv_clk);
+               retval = PTR_ERR(udc->usb_otg_clk);
                goto usb_otg_clk_get_fail;
        }
 
@@ -3376,7 +3344,11 @@ pll_get_fail:
 io_map_fail:
        release_mem_region(udc->io_p_start, udc->io_p_size);
        dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
-
+request_mem_region_fail:
+irq_fail:
+resource_fail:
+phy_fail:
+       kfree(udc);
        return retval;
 }
 
@@ -3414,6 +3386,7 @@ static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
        clk_put(udc->usb_pll_clk);
        iounmap(udc->udp_baseaddr);
        release_mem_region(udc->io_p_start, udc->io_p_size);
+       kfree(udc);
 
        return 0;
 }
index cf6bd626f3fe1e3731b062328226b842a84fcb50..b6401f1b56ce216226c9b5decfa97035ff24b684 100644 (file)
@@ -1466,7 +1466,7 @@ static struct usb_ep_ops m66592_ep_ops = {
 static struct m66592 *the_controller;
 
 static int m66592_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct m66592 *m66592 = the_controller;
        int retval;
@@ -1492,7 +1492,7 @@ static int m66592_start(struct usb_gadget_driver *driver,
                goto error;
        }
 
-       retval = bind(&m66592->gadget);
+       retval = bind(&m66592->gadget, driver);
        if (retval) {
                pr_err("bind to driver error (%d)\n", retval);
                device_del(&m66592->gadget.dev);
index 1f376eba31f6f8a4b4f6abf02577dac5336e0d79..080e577773d527cb12507b9f20a581c45c452a42 100644 (file)
@@ -29,9 +29,8 @@
 
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/usb/ch9.h>
-
+#include <linux/module.h>
 
 /*-------------------------------------------------------------------------*/
 
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
 #include "f_mass_storage.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor msg_device_desc = {
        .bLength =              sizeof msg_device_desc,
@@ -85,6 +80,22 @@ static const struct usb_descriptor_header *otg_desc[] = {
        NULL,
 };
 
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
 
 /****************************** Configurations ******************************/
 
@@ -143,10 +154,15 @@ static int __init msg_bind(struct usb_composite_dev *cdev)
 {
        int status;
 
-       status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                return status;
+       msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
+       if (status < 0)
+               return status;
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&cdev->gadget->dev,
                 DRIVER_DESC ", version: " DRIVER_VERSION "\n");
        set_bit(0, &msg_registered);
@@ -156,12 +172,13 @@ static int __init msg_bind(struct usb_composite_dev *cdev)
 
 /****************************** Some noise ******************************/
 
-static struct usb_composite_driver msg_driver = {
+static __refdata struct usb_composite_driver msg_driver = {
        .name           = "g_mass_storage",
        .dev            = &msg_device_desc,
-       .iProduct       = DRIVER_DESC,
        .max_speed      = USB_SPEED_SUPER,
        .needs_serial   = 1,
+       .strings        = dev_strings,
+       .bind           = msg_bind,
 };
 
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -170,7 +187,7 @@ MODULE_LICENSE("GPL");
 
 static int __init msg_init(void)
 {
-       return usb_composite_probe(&msg_driver, msg_bind);
+       return usb_composite_probe(&msg_driver);
 }
 module_init(msg_init);
 
index c37fb33a3d1bc57718582053a6c308ff2c051a67..88472bf7dbb7f6eb2fe061d91369efc40b53fb17 100644 (file)
 
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/module.h>
 
-
 #if defined USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
 #endif
@@ -42,12 +40,6 @@ MODULE_LICENSE("GPL");
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_mass_storage.c"
 
 #include "u_serial.c"
@@ -61,7 +53,7 @@ MODULE_LICENSE("GPL");
 #endif
 #include "u_ether.c"
 
-
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /***************************** Device Descriptor ****************************/
 
@@ -112,21 +104,16 @@ static const struct usb_descriptor_header *otg_desc[] = {
 
 
 enum {
-#ifdef CONFIG_USB_G_MULTI_RNDIS
-       MULTI_STRING_RNDIS_CONFIG_IDX,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
+       MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX,
        MULTI_STRING_CDC_CONFIG_IDX,
-#endif
 };
 
 static struct usb_string strings_dev[] = {
-#ifdef CONFIG_USB_G_MULTI_RNDIS
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
        [MULTI_STRING_CDC_CONFIG_IDX].s   = "Multifunction with CDC ECM",
-#endif
        {  } /* end of list */
 };
 
@@ -260,7 +247,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
 static int __ref multi_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget *gadget = cdev->gadget;
-       int status, gcnum;
+       int status;
 
        if (!can_support_ecm(cdev->gadget)) {
                dev_err(&gadget->dev, "controller '%s' not usable\n",
@@ -288,19 +275,11 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
                }
        }
 
-       /* set bcdDevice */
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0) {
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       } else {
-               WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
-       }
-
        /* allocate string IDs */
        status = usb_string_ids_tab(cdev, strings_dev);
        if (unlikely(status < 0))
                goto fail2;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        /* register configurations */
        status = rndis_config_register(cdev);
@@ -310,6 +289,7 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
        status = cdc_config_register(cdev);
        if (unlikely(status < 0))
                goto fail2;
+       usb_composite_overwrite_options(cdev, &coverwrite);
 
        /* we're done */
        dev_info(&gadget->dev, DRIVER_DESC "\n");
@@ -338,20 +318,20 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
 /****************************** Some noise ******************************/
 
 
-static struct usb_composite_driver multi_driver = {
+static __refdata struct usb_composite_driver multi_driver = {
        .name           = "g_multi",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = multi_bind,
        .unbind         = __exit_p(multi_unbind),
-       .iProduct       = DRIVER_DESC,
        .needs_serial   = 1,
 };
 
 
 static int __init multi_init(void)
 {
-       return usb_composite_probe(&multi_driver, multi_bind);
+       return usb_composite_probe(&multi_driver);
 }
 module_init(multi_init);
 
index 75db2c306cea24ba3736b1ebd8c689546d02c2c5..ea45224f78c877175004cbc897426161ad0cd965 100644 (file)
@@ -51,9 +51,8 @@
 #define EPSTATUS_TIMEOUT       10000
 #define PRIME_TIMEOUT          10000
 #define READSAFE_TIMEOUT       1000
-#define DTD_TIMEOUT            1000
 
-#define LOOPS_USEC_SHIFT       4
+#define LOOPS_USEC_SHIFT       1
 #define LOOPS_USEC             (1 << LOOPS_USEC_SHIFT)
 #define LOOPS(timeout)         ((timeout) >> LOOPS_USEC_SHIFT)
 
@@ -64,7 +63,6 @@ static const char driver_desc[] = DRIVER_DESC;
 
 /* controller device global variable */
 static struct mv_udc   *the_controller;
-int mv_usb_otgsc;
 
 static void nuke(struct mv_ep *ep, int status);
 static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
@@ -357,17 +355,24 @@ done:
        return retval;
 }
 
-
 static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
                dma_addr_t *dma, int *is_last)
 {
-       u32 temp;
        struct mv_dtd *dtd;
        struct mv_udc *udc;
+       struct mv_dqh *dqh;
+       u32 temp, mult = 0;
 
        /* how big will this transfer be? */
-       *length = min(req->req.length - req->req.actual,
-                       (unsigned)EP_MAX_LENGTH_TRANSFER);
+       if (usb_endpoint_xfer_isoc(req->ep->ep.desc)) {
+               dqh = req->ep->dqh;
+               mult = (dqh->max_packet_length >> EP_QUEUE_HEAD_MULT_POS)
+                               & 0x3;
+               *length = min(req->req.length - req->req.actual,
+                               (unsigned)(mult * req->ep->ep.maxpacket));
+       } else
+               *length = min(req->req.length - req->req.actual,
+                               (unsigned)EP_MAX_LENGTH_TRANSFER);
 
        udc = req->ep->udc;
 
@@ -375,7 +380,7 @@ static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
         * Be careful that no _GFP_HIGHMEM is set,
         * or we can not use dma_to_virt
         */
-       dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma);
+       dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, dma);
        if (dtd == NULL)
                return dtd;
 
@@ -409,6 +414,8 @@ static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
        if (*is_last && !req->req.no_interrupt)
                temp |= DTD_IOC;
 
+       temp |= mult << 10;
+
        dtd->size_ioc_sts = temp;
 
        mb();
@@ -708,6 +715,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        struct mv_req *req = container_of(_req, struct mv_req, req);
        struct mv_udc *udc = ep->udc;
        unsigned long flags;
+       int retval;
 
        /* catch various bogus parameters */
        if (!_req || !req->req.complete || !req->req.buf
@@ -719,10 +727,6 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                dev_err(&udc->dev->dev, "%s, bad ep", __func__);
                return -EINVAL;
        }
-       if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
-               if (req->req.length > ep->ep.maxpacket)
-                       return -EMSGSIZE;
-       }
 
        udc = ep->udc;
        if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
@@ -755,15 +759,17 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        /* build dtds and push them to device queue */
        if (!req_to_dtd(req)) {
-               int retval;
                retval = queue_dtd(ep, req);
                if (retval) {
                        spin_unlock_irqrestore(&udc->lock, flags);
-                       return retval;
+                       dev_err(&udc->dev->dev, "Failed to queue dtd\n");
+                       goto err_unmap_dma;
                }
        } else {
                spin_unlock_irqrestore(&udc->lock, flags);
-               return -ENOMEM;
+               dev_err(&udc->dev->dev, "Failed to dma_pool_alloc\n");
+               retval = -ENOMEM;
+               goto err_unmap_dma;
        }
 
        /* Update ep0 state */
@@ -775,6 +781,22 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        spin_unlock_irqrestore(&udc->lock, flags);
 
        return 0;
+
+err_unmap_dma:
+       if (req->mapped) {
+               dma_unmap_single(ep->udc->gadget.dev.parent,
+                               req->req.dma, req->req.length,
+                               ((ep_dir(ep) == EP_DIR_IN) ?
+                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
+               req->req.dma = DMA_ADDR_INVALID;
+               req->mapped = 0;
+       } else
+               dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+                               req->req.dma, req->req.length,
+                               ((ep_dir(ep) == EP_DIR_IN) ?
+                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
+
+       return retval;
 }
 
 static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
@@ -1065,7 +1087,7 @@ static int udc_reset(struct mv_udc *udc)
        tmp |= USBMODE_CTRL_MODE_DEVICE;
 
        /* turn setup lockout off, require setup tripwire in usbcmd */
-       tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE;
+       tmp |= USBMODE_SETUP_LOCK_OFF;
 
        writel(tmp, &udc->op_regs->usbmode);
 
@@ -1199,12 +1221,16 @@ static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
                        udc_start(udc);
                }
        } else if (udc->driver && udc->softconnect) {
+               if (!udc->active)
+                       goto out;
+
                /* stop all the transfer in queue*/
                stop_activity(udc, udc->driver);
                udc_stop(udc);
                mv_udc_disable(udc);
        }
 
+out:
        spin_unlock_irqrestore(&udc->lock, flags);
        return retval;
 }
@@ -1243,7 +1269,7 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
 }
 
 static int mv_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int mv_udc_stop(struct usb_gadget_driver *driver);
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops mv_ops = {
@@ -1348,7 +1374,7 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
 }
 
 static int mv_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct mv_udc *udc = the_controller;
        int retval = 0;
@@ -1373,7 +1399,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
 
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       retval = bind(&udc->gadget);
+       retval = bind(&udc->gadget, driver);
        if (retval) {
                dev_err(&udc->dev->dev, "bind to driver %s --> %d\n",
                                driver->driver.name, retval);
@@ -1499,15 +1525,17 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
        }
 
        /* prime the data phase */
-       if (!req_to_dtd(req))
+       if (!req_to_dtd(req)) {
                retval = queue_dtd(ep, req);
-       else{   /* no mem */
+               if (retval) {
+                       dev_err(&udc->dev->dev,
+                               "Failed to queue dtd when prime status\n");
+                       goto out;
+               }
+       } else{ /* no mem */
                retval = -ENOMEM;
-               goto out;
-       }
-
-       if (retval) {
-               dev_err(&udc->dev->dev, "response error on GET_STATUS request\n");
+               dev_err(&udc->dev->dev,
+                       "Failed to dma_pool_alloc when prime status\n");
                goto out;
        }
 
@@ -1515,6 +1543,15 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
 
        return 0;
 out:
+       if (req->mapped) {
+               dma_unmap_single(ep->udc->gadget.dev.parent,
+                               req->req.dma, req->req.length,
+                               ((ep_dir(ep) == EP_DIR_IN) ?
+                               DMA_TO_DEVICE : DMA_FROM_DEVICE));
+               req->req.dma = DMA_ADDR_INVALID;
+               req->mapped = 0;
+       }
+
        return retval;
 }
 
@@ -2468,9 +2505,11 @@ static void mv_udc_shutdown(struct platform_device *dev)
        u32 mode;
 
        /* reset controller mode to IDLE */
+       mv_udc_enable(udc);
        mode = readl(&udc->op_regs->usbmode);
        mode &= ~3;
        writel(mode, &udc->op_regs->usbmode);
+       mv_udc_disable(udc);
 }
 
 static struct platform_driver udc_driver = {
index 89530034dff18bbfcf0223b200c0f75b43d0cfb7..a22ad9af0565d3a7132f08b1c21b939679322473 100644 (file)
@@ -20,8 +20,8 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
-
+#include <linux/module.h>
+#include <linux/usb/composite.h>
 
 #include "u_ether.h"
 
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_ncm.c"
 #include "u_ether.c"
 
@@ -57,6 +52,7 @@
 #define CDC_PRODUCT_NUM                0xa4a1  /* Linux-USB Ethernet Gadget */
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 static struct usb_device_descriptor device_desc = {
        .bLength =              sizeof device_desc,
@@ -97,17 +93,11 @@ static const struct usb_descriptor_header *otg_desc[] = {
        NULL,
 };
 
-
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-
-static char manufacturer[50];
-
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
        {  } /* end of list */
 };
 
@@ -149,7 +139,6 @@ static struct usb_configuration ncm_config_driver = {
 
 static int __init gncm_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
 
@@ -158,48 +147,22 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                return status;
 
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
-       else {
-               /* We assume that can_support_ecm() tells the truth;
-                * but if the controller isn't recognized at all then
-                * that assumption is a bit more likely to be wrong.
-                */
-               dev_warn(&gadget->dev,
-                        "controller '%s' not recognized; trying %s\n",
-                        gadget->name,
-                        ncm_config_driver.label);
-               device_desc.bcdDevice =
-                       cpu_to_le16(0x0300 | 0x0099);
-       }
-
-
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
 
-       /* device descriptor strings: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto fail;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-       device_desc.iProduct = status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
        status = usb_add_config(cdev, &ncm_config_driver,
                                ncm_do_config);
        if (status < 0)
                goto fail;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
 
        return 0;
@@ -215,11 +178,12 @@ static int __exit gncm_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver ncm_driver = {
+static __refdata struct usb_composite_driver ncm_driver = {
        .name           = "g_ncm",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = gncm_bind,
        .unbind         = __exit_p(gncm_unbind),
 };
 
@@ -229,7 +193,7 @@ MODULE_LICENSE("GPL");
 
 static int __init init(void)
 {
-       return usb_composite_probe(&ncm_driver, gncm_bind);
+       return usb_composite_probe(&ncm_driver);
 }
 module_init(init);
 
index c7fb7723c014e8491841a531f48c705de21b14ea..661600abace8deb8a17fe0d8318c53c0b291cf02 100644 (file)
@@ -16,7 +16,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 
 #include "u_serial.h"
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "u_serial.c"
 #include "f_acm.c"
 #include "f_ecm.c"
 #include "u_ether.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 #define NOKIA_VENDOR_ID                        0x0421  /* Nokia */
 #define NOKIA_PRODUCT_ID               0x01c8  /* Nokia Gadget */
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-#define STRING_DESCRIPTION_IDX         2
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
 
 static char manufacturer_nokia[] = "Nokia";
 static const char product_nokia[] = NOKIA_LONG_NAME;
 static const char description_nokia[] = "PC-Suite Configuration";
 
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
-       [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+       [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia,
+       [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+       [USB_GADGET_SERIAL_IDX].s = "",
        [STRING_DESCRIPTION_IDX].s = description_nokia,
        {  } /* end of list */
 };
@@ -90,6 +84,7 @@ static struct usb_device_descriptor device_desc = {
        .bDeviceClass           = USB_CLASS_COMM,
        .idVendor               = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
        .idProduct              = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+       .bcdDevice              = cpu_to_le16(NOKIA_VERSION_NUM),
        /* .iManufacturer = DYNAMIC */
        /* .iProduct = DYNAMIC */
        .bNumConfigurations =   1,
@@ -151,7 +146,6 @@ static struct usb_configuration nokia_config_100ma_driver = {
 
 static int __init nokia_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
 
@@ -167,41 +161,17 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                goto err_ether;
 
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto err_usb;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto err_usb;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-
-       device_desc.iProduct = status;
-
-       /* config description */
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto err_usb;
-       strings_dev[STRING_DESCRIPTION_IDX].id = status;
-
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       status = strings_dev[STRING_DESCRIPTION_IDX].id;
        nokia_config_500ma_driver.iConfiguration = status;
        nokia_config_100ma_driver.iConfiguration = status;
 
-       /* set up other descriptors */
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
-       else {
-               /* this should only work with hw that supports altsettings
-                * and several endpoints, anything else, panic.
-                */
-               pr_err("nokia_bind: controller '%s' not recognized\n",
-                       gadget->name);
+       if (!gadget_supports_altsettings(gadget))
                goto err_usb;
-       }
 
        /* finally register the configuration */
        status = usb_add_config(cdev, &nokia_config_500ma_driver,
@@ -214,6 +184,7 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                goto err_usb;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
 
        return 0;
@@ -237,17 +208,18 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver nokia_driver = {
+static __refdata struct usb_composite_driver nokia_driver = {
        .name           = "g_nokia",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = nokia_bind,
        .unbind         = __exit_p(nokia_unbind),
 };
 
 static int __init nokia_init(void)
 {
-       return usb_composite_probe(&nokia_driver, nokia_bind);
+       return usb_composite_probe(&nokia_driver);
 }
 module_init(nokia_init);
 
index f9132ada53b5e267a3bff86aa89bb9e1d037b0f9..2a4749c3eb3f7bd7679f768ca5cdab27de0db72f 100644 (file)
@@ -1308,7 +1308,7 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on)
 }
 
 static int omap_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int omap_udc_stop(struct usb_gadget_driver *driver);
 
 static struct usb_gadget_ops omap_gadget_ops = {
@@ -2040,7 +2040,7 @@ static inline int machine_without_vbus_sense(void)
 }
 
 static int omap_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        int             status = -ENODEV;
        struct omap_ep  *ep;
@@ -2082,7 +2082,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
        if (udc->dc_clk != NULL)
                omap_udc_enable_clock(1);
 
-       status = bind(&udc->gadget);
+       status = bind(&udc->gadget, driver);
        if (status) {
                DBG("bind to %s --> %d\n", driver->driver.name, status);
                udc->gadget.dev.driver = NULL;
index f4fb71c9ae0816d18f18c8b1771cb2f4f8da42e2..6490c0040e3adcc02ea608320412fcfb25aa5241 100644 (file)
@@ -1236,7 +1236,7 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
 }
 
 static int pch_udc_start(struct usb_gadget_driver *driver,
-       int (*bind)(struct usb_gadget *));
+       int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int pch_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops pch_udc_ops = {
        .get_frame = pch_udc_pcd_get_frame,
@@ -2982,7 +2982,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
 }
 
 static int pch_udc_start(struct usb_gadget_driver *driver,
-       int (*bind)(struct usb_gadget *))
+       int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct pch_udc_dev      *dev = pch_udc;
        int                     retval;
@@ -3006,7 +3006,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
        dev->gadget.dev.driver = &driver->driver;
 
        /* Invoke the bind routine of the gadget driver */
-       retval = bind(&dev->gadget);
+       retval = bind(&dev->gadget, driver);
 
        if (retval) {
                dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n",
index f1f9290a2f47d11771108cb99ec53a6b6239117a..e156e3f267273c3a8b45b0a06025fcbd7e1541a1 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 #include <linux/fs.h>
 #include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/g_printer.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 "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
-/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 #define DRIVER_DESC            "Printer Gadget"
 #define DRIVER_VERSION         "2007 OCT 06"
@@ -120,8 +107,7 @@ static struct printer_dev usb_printer_gadget;
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static char *iSerialNum;
-module_param(iSerialNum, charp, S_IRUGO);
+module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO);
 MODULE_PARM_DESC(iSerialNum, "1");
 
 static char *iPNPstring;
@@ -141,18 +127,10 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR);
  * descriptors are built on demand.
  */
 
-#define STRING_MANUFACTURER            1
-#define STRING_PRODUCT                 2
-#define STRING_SERIALNUM               3
-
 /* holds our biggest descriptor */
 #define USB_DESC_BUFSIZE               256
 #define USB_BUFSIZE                    8192
 
-/* This device advertises one configuration. */
-#define DEV_CONFIG_VALUE               1
-#define        PRINTER_INTERFACE               0
-
 static struct usb_device_descriptor device_desc = {
        .bLength =              sizeof device_desc,
        .bDescriptorType =      USB_DT_DEVICE,
@@ -162,16 +140,12 @@ static struct usb_device_descriptor device_desc = {
        .bDeviceProtocol =      0,
        .idVendor =             cpu_to_le16(PRINTER_VENDOR_NUM),
        .idProduct =            cpu_to_le16(PRINTER_PRODUCT_NUM),
-       .iManufacturer =        STRING_MANUFACTURER,
-       .iProduct =             STRING_PRODUCT,
-       .iSerialNumber =        STRING_SERIALNUM,
        .bNumConfigurations =   1
 };
 
 static struct usb_interface_descriptor intf_desc = {
        .bLength =              sizeof intf_desc,
        .bDescriptorType =      USB_DT_INTERFACE,
-       .bInterfaceNumber =     PRINTER_INTERFACE,
        .bNumEndpoints =        2,
        .bInterfaceClass =      USB_CLASS_PRINTER,
        .bInterfaceSubClass =   1,      /* Printer Sub-Class */
@@ -252,7 +226,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
 
 /* descriptors that are built on-demand */
 
-static char                            manufacturer [50];
 static char                            product_desc [40] = DRIVER_DESC;
 static char                            serial_num [40] = "1";
 static char                            pnp_string [1024] =
@@ -260,9 +233,9 @@ static char                         pnp_string [1024] =
 
 /* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
-       { STRING_MANUFACTURER,  manufacturer, },
-       { STRING_PRODUCT,       product_desc, },
-       { STRING_SERIALNUM,     serial_num, },
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = product_desc,
+       [USB_GADGET_SERIAL_IDX].s =     serial_num,
        {  }            /* end of list */
 };
 
@@ -871,25 +844,13 @@ static int set_interface(struct printer_dev *dev, unsigned number)
        int                     result = 0;
 
        /* Free the current interface */
-       switch (dev->interface) {
-       case PRINTER_INTERFACE:
-               printer_reset_interface(dev);
-               break;
-       }
+       printer_reset_interface(dev);
 
-       switch (number) {
-       case PRINTER_INTERFACE:
-               result = set_printer_interface(dev);
-               if (result) {
-                       printer_reset_interface(dev);
-               } else {
-                       dev->interface = PRINTER_INTERFACE;
-               }
-               break;
-       default:
-               result = -EINVAL;
-               /* FALL THROUGH */
-       }
+       result = set_printer_interface(dev);
+       if (result)
+               printer_reset_interface(dev);
+       else
+               dev->interface = number;
 
        if (!result)
                INFO(dev, "Using interface %x\n", number);
@@ -972,7 +933,7 @@ static int printer_func_setup(struct usb_function *f,
                switch (ctrl->bRequest) {
                case 0: /* Get the IEEE-1284 PNP String */
                        /* Only one printer interface is supported. */
-                       if ((wIndex>>8) != PRINTER_INTERFACE)
+                       if ((wIndex>>8) != dev->interface)
                                break;
 
                        value = (pnp_string[0]<<8)|pnp_string[1];
@@ -983,7 +944,7 @@ static int printer_func_setup(struct usb_function *f,
 
                case 1: /* Get Port Status */
                        /* Only one printer interface is supported. */
-                       if (wIndex != PRINTER_INTERFACE)
+                       if (wIndex != dev->interface)
                                break;
 
                        *(u8 *)req->buf = dev->printer_status;
@@ -992,7 +953,7 @@ static int printer_func_setup(struct usb_function *f,
 
                case 2: /* Soft Reset */
                        /* Only one printer interface is supported. */
-                       if (wIndex != PRINTER_INTERFACE)
+                       if (wIndex != dev->interface)
                                break;
 
                        printer_soft_reset(dev);
@@ -1020,6 +981,37 @@ unknown:
 static int __init printer_func_bind(struct usb_configuration *c,
                struct usb_function *f)
 {
+       struct printer_dev *dev = container_of(f, struct printer_dev, function);
+       struct usb_composite_dev *cdev = c->cdev;
+       struct usb_ep           *in_ep, *out_ep;
+       int id;
+
+       id = usb_interface_id(c, f);
+       if (id < 0)
+               return id;
+       intf_desc.bInterfaceNumber = id;
+
+       /* all we really need is bulk IN/OUT */
+       in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
+       if (!in_ep) {
+autoconf_fail:
+               dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
+                       cdev->gadget->name);
+               return -ENODEV;
+       }
+       in_ep->driver_data = in_ep;     /* claim */
+
+       out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
+       if (!out_ep)
+               goto autoconf_fail;
+       out_ep->driver_data = out_ep;   /* claim */
+
+       /* assumes that all endpoints are dual-speed */
+       hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
+       hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+
+       dev->in_ep = in_ep;
+       dev->out_ep = out_ep;
        return 0;
 }
 
@@ -1035,7 +1027,8 @@ static int printer_func_set_alt(struct usb_function *f,
        int ret = -ENOTSUPP;
 
        if (!alt)
-               ret = set_interface(dev, PRINTER_INTERFACE);
+               ret = set_interface(dev, intf);
+
        return ret;
 }
 
@@ -1107,13 +1100,13 @@ static int __init printer_bind_config(struct usb_configuration *c)
 {
        struct usb_gadget       *gadget = c->cdev->gadget;
        struct printer_dev      *dev;
-       struct usb_ep           *in_ep, *out_ep;
        int                     status = -ENOMEM;
-       int                     gcnum;
        size_t                  len;
        u32                     i;
        struct usb_request      *req;
 
+       usb_ep_autoconfig_reset(gadget);
+
        dev = &usb_printer_gadget;
 
        dev->function.name = shortname;
@@ -1125,6 +1118,10 @@ static int __init printer_bind_config(struct usb_configuration *c)
        dev->function.set_alt = printer_func_set_alt;
        dev->function.disable = printer_func_disable;
 
+       status = usb_add_function(c, &dev->function);
+       if (status)
+               return status;
+
        /* Setup the sysfs files for the printer gadget. */
        dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
                                  NULL, "g_printer");
@@ -1145,23 +1142,6 @@ static int __init printer_bind_config(struct usb_configuration *c)
                goto fail;
        }
 
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0) {
-               device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-       } else {
-               dev_warn(&gadget->dev, "controller '%s' not recognized\n",
-                       gadget->name);
-               /* unrecognized, but safe unless bulk is REALLY quirky */
-               device_desc.bcdDevice =
-                       cpu_to_le16(0xFFFF);
-       }
-       snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-
-       if (iSerialNum)
-               strlcpy(serial_num, iSerialNum, sizeof serial_num);
-
        if (iPNPstring)
                strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
 
@@ -1169,26 +1149,6 @@ static int __init printer_bind_config(struct usb_configuration *c)
        pnp_string[0] = (len >> 8) & 0xFF;
        pnp_string[1] = len & 0xFF;
 
-       /* all we really need is bulk IN/OUT */
-       usb_ep_autoconfig_reset(gadget);
-       in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc);
-       if (!in_ep) {
-autoconf_fail:
-               dev_err(&gadget->dev, "can't autoconfigure on %s\n",
-                       gadget->name);
-               return -ENODEV;
-       }
-       in_ep->driver_data = in_ep;     /* claim */
-
-       out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc);
-       if (!out_ep)
-               goto autoconf_fail;
-       out_ep->driver_data = out_ep;   /* claim */
-
-       /* assumes that all endpoints are dual-speed */
-       hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
-       hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-
        usb_gadget_set_selfpowered(gadget);
 
        if (gadget->is_otg) {
@@ -1215,9 +1175,6 @@ autoconf_fail:
        dev->current_rx_bytes = 0;
        dev->current_rx_buf = NULL;
 
-       dev->in_ep = in_ep;
-       dev->out_ep = out_ep;
-
        for (i = 0; i < QLEN; i++) {
                req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
                if (!req) {
@@ -1250,8 +1207,6 @@ autoconf_fail:
        dev->gadget = gadget;
 
        INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
-       INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
-                       in_ep->name);
        return 0;
 
 fail:
@@ -1266,14 +1221,28 @@ static int printer_unbind(struct usb_composite_dev *cdev)
 
 static int __init printer_bind(struct usb_composite_dev *cdev)
 {
-       return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+       int ret;
+
+       ret = usb_string_ids_tab(cdev, strings);
+       if (ret < 0)
+               return ret;
+       device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id;
+       device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id;
+
+       ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+       if (ret)
+               return ret;
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       return ret;
 }
 
-static struct usb_composite_driver printer_driver = {
+static __refdata struct usb_composite_driver printer_driver = {
        .name           = shortname,
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
+       .bind           = printer_bind,
        .unbind         = printer_unbind,
 };
 
@@ -1297,7 +1266,7 @@ init(void)
                return status;
        }
 
-       status = usb_composite_probe(&printer_driver, printer_bind);
+       status = usb_composite_probe(&printer_driver);
        if (status) {
                class_destroy(usb_gadget_class);
                unregister_chrdev_region(g_printer_devno, 1);
index 907ad3ecb341b0c3dc285b478b3d34dc57b450d5..8efbf08c35614dbcd8f3e6138b4cebb55b75e095 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
-#include <linux/err.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/io.h>
@@ -1000,7 +999,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 }
 
 static int pxa25x_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int pxa25x_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops pxa25x_udc_ops = {
@@ -1258,7 +1257,7 @@ static void udc_enable (struct pxa25x_udc *dev)
  * the driver might get unbound.
  */
 static int pxa25x_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct pxa25x_udc       *dev = the_controller;
        int                     retval;
@@ -1286,7 +1285,7 @@ fail:
                dev->gadget.dev.driver = NULL;
                return retval;
        }
-       retval = bind(&dev->gadget);
+       retval = bind(&dev->gadget, driver);
        if (retval) {
                DMSG("bind to driver %s --> error %d\n",
                                driver->driver.name, retval);
index 861f4df6ea22903fad41d216b8c22b5f617aeab2..2eca1e71fecdd6666da6d7feb0d2ce6bea18754e 100644 (file)
@@ -225,7 +225,7 @@ dump_state(struct pxa25x_udc *dev)
                dev->stats.read.bytes, dev->stats.read.ops);
 
        for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
-               if (dev->ep [i].desc == NULL)
+               if (dev->ep[i].ep.desc == NULL)
                        continue;
                DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
        }
index 644b4305cb99fe1653ac8f9d0b5021ac4d8945a1..979ddaddb0f815e740dc7304c6d632a24caf7b68 100644 (file)
@@ -1672,7 +1672,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 }
 
 static int pxa27x_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops pxa_udc_ops = {
@@ -1803,7 +1803,7 @@ static void udc_enable(struct pxa_udc *udc)
  * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
  */
 static int pxa27x_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct pxa_udc *udc = the_controller;
        int retval;
@@ -1826,7 +1826,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
                dev_err(udc->dev, "device_add error %d\n", retval);
                goto add_fail;
        }
-       retval = bind(&udc->gadget);
+       retval = bind(&udc->gadget, driver);
        if (retval) {
                dev_err(udc->dev, "bind to driver %s --> error %d\n",
                        driver->driver.name, retval);
index b35babed6fcbbb9d940ced390c054c0d1de6d9a5..e4192b887de98014c6eb2d6d3090f36607600a4f 100644 (file)
@@ -863,26 +863,8 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
                 */
                pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
                        __func__, MsgType, MsgLength);
-               {
-                       unsigned i;
-                       for (i = 0; i < MsgLength; i += 16) {
-                               pr_debug("%03d: "
-                                       " %02x %02x %02x %02x"
-                                       " %02x %02x %02x %02x"
-                                       " %02x %02x %02x %02x"
-                                       " %02x %02x %02x %02x"
-                                       "\n",
-                                       i,
-                                       buf[i], buf [i+1],
-                                               buf[i+2], buf[i+3],
-                                       buf[i+4], buf [i+5],
-                                               buf[i+6], buf[i+7],
-                                       buf[i+8], buf [i+9],
-                                               buf[i+10], buf[i+11],
-                                       buf[i+12], buf [i+13],
-                                               buf[i+14], buf[i+15]);
-                       }
-               }
+               print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
+                                    buf, MsgLength);
                break;
        }
 
index b13e0bb5f5b8131de7cc26a928449215f2e0334c..6f696ee8b81752e992e3366feaac048cc0aacf2d 100644 (file)
@@ -2197,7 +2197,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
        /* issue soft reset */
        writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL);
 
-       timeout = 1000;
+       timeout = 10000;
        do {
                grstctl = readl(hsotg->regs + GRSTCTL);
        } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0);
@@ -2207,7 +2207,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
                return -EINVAL;
        }
 
-       timeout = 1000;
+       timeout = 10000;
 
        while (1) {
                u32 grstctl = readl(hsotg->regs + GRSTCTL);
@@ -3516,7 +3516,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
        hsotg->dev = dev;
        hsotg->plat = plat;
 
-       hsotg->clk = clk_get(&pdev->dev, "otg");
+       hsotg->clk = devm_clk_get(&pdev->dev, "otg");
        if (IS_ERR(hsotg->clk)) {
                dev_err(dev, "cannot get otg clock\n");
                return PTR_ERR(hsotg->clk);
@@ -3599,6 +3599,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 
        if (hsotg->num_of_eps == 0) {
                dev_err(dev, "wrong number of EPs (zero)\n");
+               ret = -EINVAL;
                goto err_supplies;
        }
 
@@ -3606,6 +3607,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
                      GFP_KERNEL);
        if (!eps) {
                dev_err(dev, "cannot get memory\n");
+               ret = -ENOMEM;
                goto err_supplies;
        }
 
@@ -3622,6 +3624,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
                                                     GFP_KERNEL);
        if (!hsotg->ctrl_req) {
                dev_err(dev, "failed to allocate ctrl req\n");
+               ret = -ENOMEM;
                goto err_ep_mem;
        }
 
@@ -3664,7 +3667,6 @@ err_supplies:
 
 err_clk:
        clk_disable_unprepare(hsotg->clk);
-       clk_put(hsotg->clk);
 
        return ret;
 }
@@ -3690,7 +3692,6 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
        regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
 
        clk_disable_unprepare(hsotg->clk);
-       clk_put(hsotg->clk);
 
        device_unregister(&hsotg->gadget.dev);
        return 0;
index e26a4e7ed2bf978868347ececb4332bb74db2db2..d8e785d4ad590cd0797d51da6de54dda39853e1f 100644 (file)
@@ -135,7 +135,6 @@ struct s3c_hsudc_req {
  * @dev: The device reference used by probe function.
  * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed).
  * @regs: Remapped base address of controller's register space.
- * @mem_rsrc: Device memory resource used for remapping device register space.
  * irq: IRQ number used by the controller.
  * uclk: Reference to the controller clock.
  * ep0state: Current state of EP0.
@@ -150,7 +149,6 @@ struct s3c_hsudc {
        struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
        spinlock_t lock;
        void __iomem *regs;
-       struct resource *mem_rsrc;
        int irq;
        struct clk *uclk;
        int ep0state;
@@ -835,9 +833,9 @@ static struct usb_request *s3c_hsudc_alloc_request(struct usb_ep *_ep,
 {
        struct s3c_hsudc_req *hsreq;
 
-       hsreq = kzalloc(sizeof *hsreq, gfp_flags);
+       hsreq = kzalloc(sizeof(*hsreq), gfp_flags);
        if (!hsreq)
-               return 0;
+               return NULL;
 
        INIT_LIST_HEAD(&hsreq->queue);
        return &hsreq->req;
@@ -906,16 +904,16 @@ static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req,
                        csr = readl((u32)hsudc->regs + offset);
                        if (!(csr & S3C_ESR_TX_SUCCESS) &&
                                (s3c_hsudc_write_fifo(hsep, hsreq) == 1))
-                               hsreq = 0;
+                               hsreq = NULL;
                } else {
                        csr = readl((u32)hsudc->regs + offset);
                        if ((csr & S3C_ESR_RX_SUCCESS)
                                   && (s3c_hsudc_read_fifo(hsep, hsreq) == 1))
-                               hsreq = 0;
+                               hsreq = NULL;
                }
        }
 
-       if (hsreq != 0)
+       if (hsreq)
                list_add_tail(&hsreq->queue, &hsep->queue);
 
        spin_unlock_irqrestore(&hsudc->lock, flags);
@@ -1271,7 +1269,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
        struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
        int ret, i;
 
-       hsudc = kzalloc(sizeof(struct s3c_hsudc) +
+       hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
                        sizeof(struct s3c_hsudc_ep) * pd->epnum,
                        GFP_KERNEL);
        if (!hsudc) {
@@ -1296,25 +1294,12 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(dev, "unable to obtain driver resource data\n");
-               ret = -ENODEV;
-               goto err_res;
-       }
-
-       hsudc->mem_rsrc = request_mem_region(res->start, resource_size(res),
-                               dev_name(&pdev->dev));
-       if (!hsudc->mem_rsrc) {
-               dev_err(dev, "failed to reserve register area\n");
-               ret = -ENODEV;
-               goto err_res;
-       }
 
-       hsudc->regs = ioremap(res->start, resource_size(res));
+       hsudc->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hsudc->regs) {
                dev_err(dev, "error mapping device register area\n");
                ret = -EBUSY;
-               goto err_remap;
+               goto err_res;
        }
 
        spin_lock_init(&hsudc->lock);
@@ -1337,21 +1322,22 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
        ret = platform_get_irq(pdev, 0);
        if (ret < 0) {
                dev_err(dev, "unable to obtain IRQ number\n");
-               goto err_irq;
+               goto err_res;
        }
        hsudc->irq = ret;
 
-       ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
+       ret = devm_request_irq(&pdev->dev, hsudc->irq, s3c_hsudc_irq, 0,
+                               driver_name, hsudc);
        if (ret < 0) {
                dev_err(dev, "irq request failed\n");
-               goto err_irq;
+               goto err_res;
        }
 
-       hsudc->uclk = clk_get(&pdev->dev, "usb-device");
+       hsudc->uclk = devm_clk_get(&pdev->dev, "usb-device");
        if (IS_ERR(hsudc->uclk)) {
                dev_err(dev, "failed to find usb-device clock source\n");
                ret = PTR_ERR(hsudc->uclk);
-               goto err_clk;
+               goto err_res;
        }
        clk_enable(hsudc->uclk);
 
@@ -1377,21 +1363,12 @@ err_add_udc:
        device_unregister(&hsudc->gadget.dev);
 err_add_device:
        clk_disable(hsudc->uclk);
-       clk_put(hsudc->uclk);
-err_clk:
-       free_irq(hsudc->irq, hsudc);
-err_irq:
-       iounmap(hsudc->regs);
-
-err_remap:
-       release_mem_region(res->start, resource_size(res));
 err_res:
        if (!IS_ERR_OR_NULL(hsudc->transceiver))
                usb_put_phy(hsudc->transceiver);
 
        regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
-       kfree(hsudc);
        return ret;
 }
 
index f2e51f50e528d8b532d7fcac3558c58e8554f382..c33e942d119c0fc1c9a776693c7ea45fbcd7c0f6 100644 (file)
@@ -12,6 +12,8 @@
  * (at your option) any later version.
  */
 
+#define pr_fmt(fmt) "s3c2410_udc: " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -27,6 +29,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/prefetch.h>
+#include <linux/io.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -35,7 +38,6 @@
 #include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/unaligned.h>
 #include <mach/irqs.h>
@@ -115,7 +117,7 @@ static int dprintk(int level, const char *fmt, ...)
                        sizeof(printk_buf)-len, fmt, args);
        va_end(args);
 
-       return printk(KERN_DEBUG "%s", printk_buf);
+       return pr_debug("%s", printk_buf);
 }
 #else
 static int dprintk(int level, const char *fmt, ...)
@@ -125,10 +127,10 @@ static int dprintk(int level, const char *fmt, ...)
 #endif
 static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
 {
-       u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+       u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg;
        u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
-       u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;
-       u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;
+       u32 ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2;
+       u32 ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2;
 
        addr_reg       = udc_read(S3C2410_UDC_FUNC_ADDR_REG);
        pwr_reg        = udc_read(S3C2410_UDC_PWR_REG);
@@ -164,10 +166,10 @@ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
                 "EP2_I_CSR2     : 0x%04X\n"
                 "EP2_O_CSR1     : 0x%04X\n"
                 "EP2_O_CSR2     : 0x%04X\n",
-                       addr_reg,pwr_reg,ep_int_reg,usb_int_reg,
+                       addr_reg, pwr_reg, ep_int_reg, usb_int_reg,
                        ep_int_en_reg, usb_int_en_reg, ep0_csr,
-                       ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2,
-                       ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2
+                       ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2,
+                       ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2
                );
 
        return 0;
@@ -230,7 +232,7 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
 {
        udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
 
-       udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY
+       udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
                                | S3C2410_UDC_EP0_CSR_DE),
                        S3C2410_UDC_EP0_CSR_REG);
 }
@@ -263,7 +265,7 @@ static void s3c2410_udc_done(struct s3c2410_ep *ep,
 
        list_del_init(&req->queue);
 
-       if (likely (req->req.status == -EINPROGRESS))
+       if (likely(req->req.status == -EINPROGRESS))
                req->req.status = status;
        else
                status = req->req.status;
@@ -280,9 +282,9 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
        if (&ep->queue == NULL)
                return;
 
-       while (!list_empty (&ep->queue)) {
+       while (!list_empty(&ep->queue)) {
                struct s3c2410_request *req;
-               req = list_entry (ep->queue.next, struct s3c2410_request,
+               req = list_entry(ep->queue.next, struct s3c2410_request,
                                queue);
                s3c2410_udc_done(ep, req, status);
        }
@@ -389,10 +391,10 @@ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep,
 
                if (idx == 0) {
                        /* Reset signal => no need to say 'data sent' */
-                       if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+                       if (!(udc_read(S3C2410_UDC_USB_INT_REG)
                                        & S3C2410_UDC_USBINT_RESET))
                                s3c2410_udc_set_ep0_de_in(base_addr);
-                       ep->dev->ep0state=EP0_IDLE;
+                       ep->dev->ep0state = EP0_IDLE;
                } else {
                        udc_write(idx, S3C2410_UDC_INDEX_REG);
                        ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
@@ -406,7 +408,7 @@ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep,
        } else {
                if (idx == 0) {
                        /* Reset signal => no need to say 'data sent' */
-                       if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+                       if (!(udc_read(S3C2410_UDC_USB_INT_REG)
                                        & S3C2410_UDC_USBINT_RESET))
                                s3c2410_udc_set_ep0_ipr(base_addr);
                } else {
@@ -442,7 +444,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
        u8              *buf;
        u32             ep_csr;
        unsigned        bufferspace;
-       int             is_last=1;
+       int             is_last = 1;
        unsigned        avail;
        int             fifo_count = 0;
        u32             idx;
@@ -510,7 +512,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
        /* Only ep0 debug messages are interesting */
        if (idx == 0)
                dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n",
-                       __func__, fifo_count,is_last);
+                       __func__, fifo_count, is_last);
 
        if (is_last) {
                if (idx == 0) {
@@ -542,7 +544,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
 
 static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq)
 {
-       unsigned char *outbuf = (unsigned char*)crq;
+       unsigned char *outbuf = (unsigned char *)crq;
        int bytes_read = 0;
 
        udc_write(0, S3C2410_UDC_INDEX_REG);
@@ -648,7 +650,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
 
        switch (crq->bRequest) {
        case USB_REQ_SET_CONFIGURATION:
-               dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
+               dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ...\n");
 
                if (crq->bRequestType == USB_RECIP_DEVICE) {
                        dev->req_config = 1;
@@ -657,7 +659,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
                break;
 
        case USB_REQ_SET_INTERFACE:
-               dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+               dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ...\n");
 
                if (crq->bRequestType == USB_RECIP_INTERFACE) {
                        dev->req_config = 1;
@@ -666,7 +668,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
                break;
 
        case USB_REQ_SET_ADDRESS:
-               dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
+               dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ...\n");
 
                if (crq->bRequestType == USB_RECIP_DEVICE) {
                        tmp = crq->wValue & 0x7F;
@@ -679,13 +681,12 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
                break;
 
        case USB_REQ_GET_STATUS:
-               dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
+               dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ...\n");
                s3c2410_udc_clear_ep0_opr(base_addr);
 
                if (dev->req_std) {
-                       if (!s3c2410_udc_get_status(dev, crq)) {
+                       if (!s3c2410_udc_get_status(dev, crq))
                                return;
-                       }
                }
                break;
 
@@ -750,7 +751,7 @@ static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
                /* deferred i/o == no response yet */
        } else if (dev->req_pending) {
                dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
-               dev->req_pending=0;
+               dev->req_pending = 0;
        }
 
        dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);
@@ -801,16 +802,14 @@ static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
 
        case EP0_IN_DATA_PHASE:                 /* GET_DESCRIPTOR etc */
                dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
-               if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
+               if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req)
                        s3c2410_udc_write_fifo(ep, req);
-               }
                break;
 
        case EP0_OUT_DATA_PHASE:                /* SET_DESCRIPTOR etc */
                dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
-               if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
-                       s3c2410_udc_read_fifo(ep,req);
-               }
+               if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req)
+                       s3c2410_udc_read_fifo(ep, req);
                break;
 
        case EP0_END_XFER:
@@ -836,7 +835,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
        u32                     ep_csr1;
        u32                     idx;
 
-       if (likely (!list_empty(&ep->queue)))
+       if (likely(!list_empty(&ep->queue)))
                req = list_entry(ep->queue.next,
                                struct s3c2410_request, queue);
        else
@@ -858,9 +857,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
                        return;
                }
 
-               if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) {
-                       s3c2410_udc_write_fifo(ep,req);
-               }
+               if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req)
+                       s3c2410_udc_write_fifo(ep, req);
        } else {
                udc_write(idx, S3C2410_UDC_INDEX_REG);
                ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG);
@@ -873,9 +871,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
                        return;
                }
 
-               if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
-                       s3c2410_udc_read_fifo(ep,req);
-               }
+               if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req)
+                       s3c2410_udc_read_fifo(ep, req);
        }
 }
 
@@ -1057,7 +1054,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
        struct s3c2410_ep       *ep;
        u32                     max, tmp;
        unsigned long           flags;
-       u32                     csr1,csr2;
+       u32                     csr1, csr2;
        u32                     int_en_reg;
 
        ep = to_s3c2410_ep(_ep);
@@ -1073,7 +1070,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
 
        max = usb_endpoint_maxp(desc) & 0x1fff;
 
-       local_irq_save (flags);
+       local_irq_save(flags);
        _ep->maxpacket = max & 0x7ff;
        ep->ep.desc = desc;
        ep->halted = 0;
@@ -1117,11 +1114,11 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
 
        /* print some debug message */
        tmp = desc->bEndpointAddress;
-       dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
-                _ep->name,ep->num, tmp,
+       dprintk(DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
+                _ep->name, ep->num, tmp,
                 desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
 
-       local_irq_restore (flags);
+       local_irq_restore(flags);
        s3c2410_udc_set_halt(_ep, 0);
 
        return 0;
@@ -1149,7 +1146,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
        ep->ep.desc = NULL;
        ep->halted = 1;
 
-       s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
+       s3c2410_udc_nuke(ep->dev, ep, -ESHUTDOWN);
 
        /* disable irqs */
        int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
@@ -1170,16 +1167,16 @@ s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags)
 {
        struct s3c2410_request *req;
 
-       dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags);
+       dprintk(DEBUG_VERBOSE, "%s(%p,%d)\n", __func__, _ep, mem_flags);
 
        if (!_ep)
                return NULL;
 
-       req = kzalloc (sizeof(struct s3c2410_request), mem_flags);
+       req = kzalloc(sizeof(struct s3c2410_request), mem_flags);
        if (!req)
                return NULL;
 
-       INIT_LIST_HEAD (&req->queue);
+       INIT_LIST_HEAD(&req->queue);
        return &req->req;
 }
 
@@ -1197,7 +1194,7 @@ s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
        if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name))
                return;
 
-       WARN_ON (!list_empty (&req->queue));
+       WARN_ON(!list_empty(&req->queue));
        kfree(req);
 }
 
@@ -1220,12 +1217,12 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
        }
 
        dev = ep->dev;
-       if (unlikely (!dev->driver
+       if (unlikely(!dev->driver
                        || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
                return -ESHUTDOWN;
        }
 
-       local_irq_save (flags);
+       local_irq_save(flags);
 
        if (unlikely(!_req || !_req->complete
                        || !_req->buf || !list_empty(&req->queue))) {
@@ -1233,7 +1230,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
                        dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);
                else {
                        dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",
-                               __func__, !_req->complete,!_req->buf,
+                               __func__, !_req->complete, !_req->buf,
                                !list_empty(&req->queue));
                }
 
@@ -1299,7 +1296,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
        }
 
        /* pio or dma irq handler advances the queue. */
-       if (likely (req != 0))
+       if (likely(req))
                list_add_tail(&req->queue, &ep->queue);
 
        local_irq_restore(flags);
@@ -1329,11 +1326,11 @@ static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 
        udc = to_s3c2410_udc(ep->gadget);
 
-       local_irq_save (flags);
+       local_irq_save(flags);
 
-       list_for_each_entry (req, &ep->queue, queue) {
+       list_for_each_entry(req, &ep->queue, queue) {
                if (&req->req == _req) {
-                       list_del_init (&req->queue);
+                       list_del_init(&req->queue);
                        _req->status = -ECONNRESET;
                        retval = 0;
                        break;
@@ -1348,7 +1345,7 @@ static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
                s3c2410_udc_done(ep, req, -ECONNRESET);
        }
 
-       local_irq_restore (flags);
+       local_irq_restore(flags);
        return retval;
 }
 
@@ -1367,7 +1364,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
                return -EINVAL;
        }
 
-       local_irq_save (flags);
+       local_irq_save(flags);
 
        idx = ep->bEndpointAddress & 0x7F;
 
@@ -1376,7 +1373,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
                s3c2410_udc_set_ep0_de_out(base_addr);
        } else {
                udc_write(idx, S3C2410_UDC_INDEX_REG);
-               ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN)
+               ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
                                ? S3C2410_UDC_IN_CSR1_REG
                                : S3C2410_UDC_OUT_CSR1_REG);
 
@@ -1404,7 +1401,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
        }
 
        ep->halted = value ? 1 : 0;
-       local_irq_restore (flags);
+       local_irq_restore(flags);
 
        return 0;
 }
@@ -1484,9 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
                        }
                        s3c2410_udc_disable(udc);
                }
-       }
-       else
+       } else {
                return -EOPNOTSUPP;
+       }
 
        return 0;
 }
@@ -1542,7 +1539,7 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
 }
 
 static int s3c2410_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
 static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops s3c2410_ops = {
@@ -1617,20 +1614,20 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
        u32 i;
 
        /* device/ep0 records init */
-       INIT_LIST_HEAD (&dev->gadget.ep_list);
-       INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+       INIT_LIST_HEAD(&dev->gadget.ep_list);
+       INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
        dev->ep0state = EP0_IDLE;
 
        for (i = 0; i < S3C2410_ENDPOINTS; i++) {
                struct s3c2410_ep *ep = &dev->ep[i];
 
                if (i != 0)
-                       list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+                       list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
 
                ep->dev = dev;
                ep->ep.desc = NULL;
                ep->halted = 0;
-               INIT_LIST_HEAD (&ep->queue);
+               INIT_LIST_HEAD(&ep->queue);
        }
 }
 
@@ -1668,7 +1665,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
 }
 
 static int s3c2410_udc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        struct s3c2410_udc *udc = the_controller;
        int             retval;
@@ -1683,13 +1680,13 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver,
                return -EBUSY;
 
        if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) {
-               printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
+               dev_err(&udc->gadget.dev, "Invalid driver: bind %p setup %p speed %d\n",
                        bind, driver->setup, driver->max_speed);
                return -EINVAL;
        }
 #if defined(MODULE)
        if (!driver->unbind) {
-               printk(KERN_ERR "Invalid driver: no unbind method\n");
+               dev_err(&udc->gadget.dev, "Invalid driver: no unbind method\n");
                return -EINVAL;
        }
 #endif
@@ -1699,15 +1696,17 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver,
        udc->gadget.dev.driver = &driver->driver;
 
        /* Bind the driver */
-       if ((retval = device_add(&udc->gadget.dev)) != 0) {
-               printk(KERN_ERR "Error in device_add() : %d\n",retval);
+       retval = device_add(&udc->gadget.dev);
+       if (retval) {
+               dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
                goto register_error;
        }
 
        dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
                driver->driver.name);
 
-       if ((retval = bind(&udc->gadget)) != 0) {
+       retval = bind(&udc->gadget, driver);
+       if (retval) {
                device_del(&udc->gadget.dev);
                goto register_error;
        }
@@ -1865,7 +1864,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
                memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
        }
 
-       spin_lock_init (&udc->lock);
+       spin_lock_init(&udc->lock);
        udc_info = pdev->dev.platform_data;
 
        rsrc_start = S3C2410_PA_USBDEV;
@@ -2028,7 +2027,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
+static int
+s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
 {
        s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
 
@@ -2073,7 +2073,7 @@ static int __init udc_init(void)
 
        s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
        if (IS_ERR(s3c2410_udc_debugfs_root)) {
-               printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+               pr_err("%s: debugfs dir creation failed %ld\n",
                        gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
                s3c2410_udc_debugfs_root = NULL;
        }
index 665c07422c2670236495e028ebe203d38922ed75..44752f531e85e7d75ccf1698a3dd0bb482dfcbfc 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_acm.c"
 #include "f_obex.c"
 #include "f_serial.c"
 #include "u_serial.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 /* Thanks to NetChip Technologies for donating this product ID.
 *
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-#define STRING_DESCRIPTION_IDX         2
-
-static char manufacturer[50];
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = GS_VERSION_NAME,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME,
+       [USB_GADGET_SERIAL_IDX].s = "",
        [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
        {  } /* end of list */
 };
@@ -94,7 +86,7 @@ static struct usb_device_descriptor device_desc = {
        /* .bMaxPacketSize0 = f(hardware) */
        .idVendor =             cpu_to_le16(GS_VENDOR_ID),
        /* .idProduct = f(use_acm) */
-       /* .bcdDevice = f(hardware) */
+       .bcdDevice = cpu_to_le16(GS_VERSION_NUM),
        /* .iManufacturer = DYNAMIC */
        /* .iProduct = DYNAMIC */
        .bNumConfigurations =   1,
@@ -162,8 +154,6 @@ static struct usb_configuration serial_config_driver = {
 
 static int __init gs_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
-       struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
 
        status = gserial_setup(cdev->gadget, n_ports);
@@ -174,50 +164,14 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
         * contents can be overridden by the composite_dev glue.
         */
 
-       /* device description: manufacturer, product */
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-       status = usb_string_id(cdev);
+       status = usb_string_ids_tab(cdev, strings_dev);
        if (status < 0)
                goto fail;
-       strings_dev[STRING_MANUFACTURER_IDX].id = status;
-
-       device_desc.iManufacturer = status;
-
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail;
-       strings_dev[STRING_PRODUCT_IDX].id = status;
-
-       device_desc.iProduct = status;
-
-       /* config description */
-       status = usb_string_id(cdev);
-       if (status < 0)
-               goto fail;
-       strings_dev[STRING_DESCRIPTION_IDX].id = status;
-
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       status = strings_dev[STRING_DESCRIPTION_IDX].id;
        serial_config_driver.iConfiguration = status;
 
-       /* set up other descriptors */
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum);
-       else {
-               /* this is so simple (for now, no altsettings) that it
-                * SHOULD NOT have problems with bulk-capable hardware.
-                * so warn about unrcognized controllers -- don't panic.
-                *
-                * things like configuration and altsetting numbering
-                * can need hardware-specific attention though.
-                */
-               pr_warning("gs_bind: controller '%s' not recognized\n",
-                       gadget->name);
-               device_desc.bcdDevice =
-                       cpu_to_le16(GS_VERSION_NUM | 0x0099);
-       }
-
        if (gadget_is_otg(cdev->gadget)) {
                serial_config_driver.descriptors = otg_desc;
                serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -229,6 +183,7 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
        if (status < 0)
                goto fail;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        INFO(cdev, "%s\n", GS_VERSION_NAME);
 
        return 0;
@@ -238,11 +193,12 @@ fail:
        return status;
 }
 
-static struct usb_composite_driver gserial_driver = {
+static __refdata struct usb_composite_driver gserial_driver = {
        .name           = "g_serial",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_SUPER,
+       .bind           = gs_bind,
 };
 
 static int __init init(void)
@@ -271,7 +227,7 @@ static int __init init(void)
        }
        strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
 
-       return usb_composite_probe(&gserial_driver, gs_bind);
+       return usb_composite_probe(&gserial_driver);
 }
 module_init(init);
 
index 5444866e13ef72c8ddd7c9a693803c02cd37a61a..eaa1005377fc58ff9304ced98db1169823d8d81d 100644 (file)
 #include <target/configfs_macros.h>
 #include <asm/unaligned.h>
 
-#include "usbstring.c"
-#include "epautoconf.c"
-#include "config.c"
-#include "composite.c"
-
 #include "tcm_usb_gadget.h"
 
+USB_GADGET_COMPOSITE_OPTIONS();
+
 static struct target_fabric_configfs *usbg_fabric_configfs;
 
 static inline struct f_uas *to_f_uas(struct usb_function *f)
@@ -1977,7 +1974,6 @@ static struct usb_interface_descriptor bot_intf_desc = {
        .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
        .bInterfaceSubClass =   USB_SC_SCSI,
        .bInterfaceProtocol =   USB_PR_BULK,
-       .iInterface =           USB_G_STR_INT_UAS,
 };
 
 static struct usb_interface_descriptor uasp_intf_desc = {
@@ -1988,7 +1984,6 @@ static struct usb_interface_descriptor uasp_intf_desc = {
        .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
        .bInterfaceSubClass =   USB_SC_SCSI,
        .bInterfaceProtocol =   USB_PR_UAS,
-       .iInterface =           USB_G_STR_INT_BBB,
 };
 
 static struct usb_endpoint_descriptor uasp_bi_desc = {
@@ -2209,20 +2204,16 @@ static struct usb_device_descriptor usbg_device_desc = {
        .bDeviceClass =         USB_CLASS_PER_INTERFACE,
        .idVendor =             cpu_to_le16(UAS_VENDOR_ID),
        .idProduct =            cpu_to_le16(UAS_PRODUCT_ID),
-       .iManufacturer =        USB_G_STR_MANUFACTOR,
-       .iProduct =             USB_G_STR_PRODUCT,
-       .iSerialNumber =        USB_G_STR_SERIAL,
-
        .bNumConfigurations =   1,
 };
 
 static struct usb_string       usbg_us_strings[] = {
-       { USB_G_STR_MANUFACTOR, "Target Manufactor"},
-       { USB_G_STR_PRODUCT,    "Target Product"},
-       { USB_G_STR_SERIAL,     "000000000001"},
-       { USB_G_STR_CONFIG,     "default config"},
-       { USB_G_STR_INT_UAS,    "USB Attached SCSI"},
-       { USB_G_STR_INT_BBB,    "Bulk Only Transport"},
+       [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor",
+       [USB_GADGET_PRODUCT_IDX].s      = "Target Product",
+       [USB_GADGET_SERIAL_IDX].s       = "000000000001",
+       [USB_G_STR_CONFIG].s            = "default config",
+       [USB_G_STR_INT_UAS].s           = "USB Attached SCSI",
+       [USB_G_STR_INT_BBB].s           = "Bulk Only Transport",
        { },
 };
 
@@ -2244,7 +2235,6 @@ static int guas_unbind(struct usb_composite_dev *cdev)
 static struct usb_configuration usbg_config_driver = {
        .label                  = "Linux Target",
        .bConfigurationValue    = 1,
-       .iConfiguration         = USB_G_STR_CONFIG,
        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 };
 
@@ -2417,6 +2407,9 @@ static int usbg_cfg_bind(struct usb_configuration *c)
        fu->function.disable = usbg_disable;
        fu->tpg = the_only_tpg_I_currently_have;
 
+       bot_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_BBB].id;
+       uasp_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_UAS].id;
+
        ret = usb_add_function(c, &fu->function);
        if (ret)
                goto err;
@@ -2431,22 +2424,38 @@ static int usb_target_bind(struct usb_composite_dev *cdev)
 {
        int ret;
 
+       ret = usb_string_ids_tab(cdev, usbg_us_strings);
+       if (ret)
+               return ret;
+
+       usbg_device_desc.iManufacturer =
+               usbg_us_strings[USB_GADGET_MANUFACTURER_IDX].id;
+       usbg_device_desc.iProduct = usbg_us_strings[USB_GADGET_PRODUCT_IDX].id;
+       usbg_device_desc.iSerialNumber =
+               usbg_us_strings[USB_GADGET_SERIAL_IDX].id;
+       usbg_config_driver.iConfiguration =
+               usbg_us_strings[USB_G_STR_CONFIG].id;
+
        ret = usb_add_config(cdev, &usbg_config_driver,
                        usbg_cfg_bind);
+       if (ret)
+               return ret;
+       usb_composite_overwrite_options(cdev, &coverwrite);
        return 0;
 }
 
-static struct usb_composite_driver usbg_driver = {
+static __refdata struct usb_composite_driver usbg_driver = {
        .name           = "g_target",
        .dev            = &usbg_device_desc,
        .strings        = usbg_strings,
        .max_speed      = USB_SPEED_SUPER,
+       .bind           = usb_target_bind,
        .unbind         = guas_unbind,
 };
 
 static int usbg_attach(struct usbg_tpg *tpg)
 {
-       return usb_composite_probe(&usbg_driver, usb_target_bind);
+       return usb_composite_probe(&usbg_driver);
 }
 
 static void usbg_detach(struct usbg_tpg *tpg)
index bb18999a9a8d9bccc8c40ad44e092ddb636eb4ae..8289219925b87dd7b99bedd3f5c2b4205f401862 100644 (file)
 #define UASP_SS_EP_COMP_LOG_STREAMS 4
 #define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
 
-#define USB_G_STR_MANUFACTOR    1
-#define USB_G_STR_PRODUCT       2
-#define USB_G_STR_SERIAL        3
-#define USB_G_STR_CONFIG        4
-#define USB_G_STR_INT_UAS       5
-#define USB_G_STR_INT_BBB       6
+enum {
+       USB_G_STR_CONFIG = USB_GADGET_FIRST_AVAIL_IDX,
+       USB_G_STR_INT_UAS,
+       USB_G_STR_INT_BBB,
+};
 
 #define USB_G_ALT_INT_BBB       0
 #define USB_G_ALT_INT_UAS       1
index 90e82e288eb9f25b6aad4842db1a001f174a0515..b9c46900c2c16bac8577876b42cfa52953ce0846 100644 (file)
@@ -14,6 +14,7 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/device.h>
 #include <linux/ctype.h>
@@ -83,17 +84,10 @@ struct eth_dev {
 
 #define DEFAULT_QLEN   2       /* double buffering by default */
 
-
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 static unsigned qmult = 5;
 module_param(qmult, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
 
-#else  /* full speed (low speed doesn't do bulk) */
-#define qmult          1
-#endif
-
 /* for dual-speed hardware, use deeper queues at high/super speed */
 static inline int qlen(struct usb_gadget *gadget)
 {
@@ -669,6 +663,8 @@ static int eth_stop(struct net_device *net)
        spin_lock_irqsave(&dev->lock, flags);
        if (dev->port_usb) {
                struct gether   *link = dev->port_usb;
+               const struct usb_endpoint_descriptor *in;
+               const struct usb_endpoint_descriptor *out;
 
                if (link->close)
                        link->close(link);
@@ -682,10 +678,14 @@ static int eth_stop(struct net_device *net)
                 * their own pace; the network stack can handle old packets.
                 * For the moment we leave this here, since it works.
                 */
+               in = link->in_ep->desc;
+               out = link->out_ep->desc;
                usb_ep_disable(link->in_ep);
                usb_ep_disable(link->out_ep);
                if (netif_carrier_ok(net)) {
                        DBG(dev, "host still using in/out endpoints\n");
+                       link->in_ep->desc = in;
+                       link->out_ep->desc = out;
                        usb_ep_enable(link->in_ep);
                        usb_ep_enable(link->out_ep);
                }
index e5e44f8cde9a3c99052e19e5e8c641ab3123a534..f3cd9690b101d6945fca7924e40ebfdd5df608f1 100644 (file)
@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
  */
 static inline int usb_gadget_start(struct usb_gadget *gadget,
                struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+               int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
 {
        return gadget->ops->start(driver, bind);
 }
@@ -262,8 +262,8 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
        if (udc_is_newstyle(udc)) {
-               udc->driver->disconnect(udc->gadget);
                usb_gadget_disconnect(udc->gadget);
+               udc->driver->disconnect(udc->gadget);
                udc->driver->unbind(udc->gadget);
                usb_gadget_udc_stop(udc->gadget, udc->driver);
        } else {
@@ -311,13 +311,12 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
 
 /* ------------------------------------------------------------------------- */
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
 {
        struct usb_udc          *udc = NULL;
        int                     ret;
 
-       if (!driver || !bind || !driver->setup)
+       if (!driver || !driver->bind || !driver->setup)
                return -EINVAL;
 
        mutex_lock(&udc_lock);
@@ -339,7 +338,7 @@ found:
        udc->dev.driver = &driver->driver;
 
        if (udc_is_newstyle(udc)) {
-               ret = bind(udc->gadget);
+               ret = driver->bind(udc->gadget, driver);
                if (ret)
                        goto err1;
                ret = usb_gadget_udc_start(udc->gadget, driver);
@@ -350,7 +349,7 @@ found:
                usb_gadget_connect(udc->gadget);
        } else {
 
-               ret = usb_gadget_start(udc->gadget, driver, bind);
+               ret = usb_gadget_start(udc->gadget, driver, driver->bind);
                if (ret)
                        goto err1;
 
index 4d25b9009edf4175d3a5e648c877fad6d2890925..1f49fce0f0b73aa220d8cb388923ea4a7d1631f8 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/device.h>
@@ -68,4 +69,4 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
        buf [1] = USB_DT_STRING;
        return buf [0];
 }
-
+EXPORT_SYMBOL_GPL(usb_gadget_get_string);
index 120e134e805ed9ad2101a752e303aa878b18de3b..69cf5c2cd33532ab75b313dcba80d347e17462b3 100644 (file)
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "uvc_queue.c"
 #include "uvc_video.c"
 #include "uvc_v4l2.c"
 #include "f_uvc.c"
 
+USB_GADGET_COMPOSITE_OPTIONS();
 /* --------------------------------------------------------------------------
  * Device descriptor
  */
@@ -47,13 +43,12 @@ static char webcam_config_label[] = "Video";
 
 /* string IDs are assigned dynamically */
 
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-#define STRING_DESCRIPTION_IDX         2
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_string webcam_strings[] = {
-       [STRING_MANUFACTURER_IDX].s = webcam_vendor_label,
-       [STRING_PRODUCT_IDX].s = webcam_product_label,
+       [USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
+       [USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
+       [USB_GADGET_SERIAL_IDX].s = "",
        [STRING_DESCRIPTION_IDX].s = webcam_config_label,
        {  }
 };
@@ -358,26 +353,22 @@ webcam_bind(struct usb_composite_dev *cdev)
        /* Allocate string descriptor numbers ... note that string contents
         * can be overridden by the composite_dev glue.
         */
-       if ((ret = usb_string_id(cdev)) < 0)
-               goto error;
-       webcam_strings[STRING_MANUFACTURER_IDX].id = ret;
-       webcam_device_descriptor.iManufacturer = ret;
-
-       if ((ret = usb_string_id(cdev)) < 0)
-               goto error;
-       webcam_strings[STRING_PRODUCT_IDX].id = ret;
-       webcam_device_descriptor.iProduct = ret;
-
-       if ((ret = usb_string_id(cdev)) < 0)
+       ret = usb_string_ids_tab(cdev, webcam_strings);
+       if (ret < 0)
                goto error;
-       webcam_strings[STRING_DESCRIPTION_IDX].id = ret;
-       webcam_config_driver.iConfiguration = ret;
+       webcam_device_descriptor.iManufacturer =
+               webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
+       webcam_device_descriptor.iProduct =
+               webcam_strings[USB_GADGET_PRODUCT_IDX].id;
+       webcam_config_driver.iConfiguration =
+               webcam_strings[STRING_DESCRIPTION_IDX].id;
 
        /* Register our configuration. */
        if ((ret = usb_add_config(cdev, &webcam_config_driver,
                                        webcam_config_bind)) < 0)
                goto error;
 
+       usb_composite_overwrite_options(cdev, &coverwrite);
        INFO(cdev, "Webcam Video Gadget\n");
        return 0;
 
@@ -390,18 +381,19 @@ error:
  * Driver
  */
 
-static struct usb_composite_driver webcam_driver = {
+static __refdata struct usb_composite_driver webcam_driver = {
        .name           = "g_webcam",
        .dev            = &webcam_device_descriptor,
        .strings        = webcam_device_strings,
        .max_speed      = USB_SPEED_SUPER,
+       .bind           = webcam_bind,
        .unbind         = webcam_unbind,
 };
 
 static int __init
 webcam_init(void)
 {
-       return usb_composite_probe(&webcam_driver, webcam_bind);
+       return usb_composite_probe(&webcam_driver);
 }
 
 static void __exit
index 12ad516ada77110a236600647feeaf3bbdbf954d..6bf4c06113656905b3042c346ede6c08f8a26deb 100644 (file)
@@ -42,7 +42,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/utsname.h>
 #include <linux/device.h>
 
 #include "g_zero.h"
  * the runtime footprint, and giving us at least some parts of what
  * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  */
-#include "composite.c"
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-
 #include "f_sourcesink.c"
 #include "f_loopback.c"
 
 /*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
 
 #define DRIVER_VERSION         "Cinco de Mayo 2008"
 
@@ -141,20 +136,13 @@ const struct usb_descriptor_header *otg_desc[] = {
 #endif
 
 /* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX                0
-#define STRING_PRODUCT_IDX             1
-#define STRING_SERIAL_IDX              2
-
-static char manufacturer[50];
-
 /* default serial number takes at least two packets */
 static char serial[] = "0123456789.0123456789.0123456789";
 
 static struct usb_string strings_dev[] = {
-       [STRING_MANUFACTURER_IDX].s = manufacturer,
-       [STRING_PRODUCT_IDX].s = longname,
-       [STRING_SERIAL_IDX].s = serial,
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = longname,
+       [USB_GADGET_SERIAL_IDX].s = serial,
        {  }                    /* end of list */
 };
 
@@ -265,30 +253,18 @@ static void zero_resume(struct usb_composite_dev *cdev)
 
 static int __init zero_bind(struct usb_composite_dev *cdev)
 {
-       int                     gcnum;
-       struct usb_gadget       *gadget = cdev->gadget;
-       int                     id;
+       int                     status;
 
        /* Allocate string descriptor numbers ... note that string
         * contents can be overridden by the composite_dev glue.
         */
-       id = usb_string_id(cdev);
-       if (id < 0)
-               return id;
-       strings_dev[STRING_MANUFACTURER_IDX].id = id;
-       device_desc.iManufacturer = id;
-
-       id = usb_string_id(cdev);
-       if (id < 0)
-               return id;
-       strings_dev[STRING_PRODUCT_IDX].id = id;
-       device_desc.iProduct = id;
-
-       id = usb_string_id(cdev);
-       if (id < 0)
-               return id;
-       strings_dev[STRING_SERIAL_IDX].id = id;
-       device_desc.iSerialNumber = id;
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               return status;
+
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id;
 
        setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
 
@@ -303,28 +279,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
                loopback_add(cdev, autoresume != 0);
        }
 
-       gcnum = usb_gadget_controller_number(gadget);
-       if (gcnum >= 0)
-               device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-       else {
-               /* gadget zero is so simple (for now, no altsettings) that
-                * it SHOULD NOT have problems with bulk-capable hardware.
-                * so just warn about unrcognized controllers -- don't panic.
-                *
-                * things like configuration and altsetting numbering
-                * can need hardware-specific attention though.
-                */
-               pr_warning("%s: controller '%s' not recognized\n",
-                       longname, gadget->name);
-               device_desc.bcdDevice = cpu_to_le16(0x9999);
-       }
+       usb_composite_overwrite_options(cdev, &coverwrite);
 
        INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
 
-       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
-               init_utsname()->sysname, init_utsname()->release,
-               gadget->name);
-
        return 0;
 }
 
@@ -334,11 +292,12 @@ static int zero_unbind(struct usb_composite_dev *cdev)
        return 0;
 }
 
-static struct usb_composite_driver zero_driver = {
+static __refdata struct usb_composite_driver zero_driver = {
        .name           = "zero",
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_SUPER,
+       .bind           = zero_bind,
        .unbind         = zero_unbind,
        .suspend        = zero_suspend,
        .resume         = zero_resume,
@@ -349,7 +308,7 @@ MODULE_LICENSE("GPL");
 
 static int __init init(void)
 {
-       return usb_composite_probe(&zero_driver, zero_bind);
+       return usb_composite_probe(&zero_driver);
 }
 module_init(init);
 
index 075d2eca8108c59d3af002122248ecf44cd6f2bb..13cd6d558ebac6c7bc2c26f1f12b4400e36af6c5 100644 (file)
@@ -292,7 +292,7 @@ config USB_OHCI_HCD
        depends on USB && USB_ARCH_HAS_OHCI
        select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
        select USB_OTG_UTILS if ARCH_OMAP
-       select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008
+       depends on USB_ISP1301 || !(ARCH_LPC32XX || ARCH_PNX4008)
        ---help---
          The Open Host Controller Interface (OHCI) is a standard for accessing
          USB 1.1 host controller hardware.  It does more in hardware than Intel's
@@ -418,7 +418,7 @@ config USB_OHCI_HCD_PLATFORM
        default n
        ---help---
          Adds an OHCI host driver for a generic platform device, which
-         provieds a memory space and an irq.
+         provides a memory space and an irq.
 
          If unsure, say N.
 
@@ -428,7 +428,7 @@ config USB_EHCI_HCD_PLATFORM
        default n
        ---help---
          Adds an EHCI host driver for a generic platform device, which
-         provieds a memory space and an irq.
+         provides a memory space and an irq.
 
          If unsure, say N.
 
@@ -450,7 +450,7 @@ config USB_OHCI_LITTLE_ENDIAN
 
 config USB_UHCI_HCD
        tristate "UHCI HCD (most Intel and VIA) support"
-       depends on USB && (PCI || SPARC_LEON)
+       depends on USB && (PCI || SPARC_LEON || ARCH_VT8500)
        ---help---
          The Universal Host Controller Interface is a standard by Intel for
          accessing the USB hardware in the PC (which is also called the USB
@@ -468,7 +468,15 @@ config USB_UHCI_HCD
 config USB_UHCI_SUPPORT_NON_PCI_HC
        bool
        depends on USB_UHCI_HCD
-       default y if SPARC_LEON
+       default y if (SPARC_LEON || ARCH_VT8500)
+
+config USB_UHCI_PLATFORM
+       bool "Generic UHCI Platform Driver support"
+       depends on USB_UHCI_SUPPORT_NON_PCI_HC
+       default y if ARCH_VT8500
+       ---help---
+         Enable support for generic UHCI platform devices that require no
+         additional configuration.
 
 config USB_UHCI_BIG_ENDIAN_MMIO
        bool
index a47e2cffaaf84a752b709f7e812b85b1dbd4481a..411bb74152ebe2ba3b063fb0e5e3445626d61af1 100644 (file)
@@ -150,31 +150,24 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               retval = -EBUSY;
-               goto fail_request_resource;
-       }
-
-       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                retval = -EFAULT;
-               goto fail_ioremap;
+               goto fail_request_resource;
        }
 
-       iclk = clk_get(&pdev->dev, "ehci_clk");
+       iclk = devm_clk_get(&pdev->dev, "ehci_clk");
        if (IS_ERR(iclk)) {
                dev_err(&pdev->dev, "Error getting interface clock\n");
                retval = -ENOENT;
-               goto fail_get_iclk;
+               goto fail_request_resource;
        }
-       fclk = clk_get(&pdev->dev, "uhpck");
+       fclk = devm_clk_get(&pdev->dev, "uhpck");
        if (IS_ERR(fclk)) {
                dev_err(&pdev->dev, "Error getting function clock\n");
                retval = -ENOENT;
-               goto fail_get_fclk;
+               goto fail_request_resource;
        }
 
        atmel_start_ehci(pdev);
@@ -187,13 +180,6 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
 
 fail_add_hcd:
        atmel_stop_ehci(pdev);
-       clk_put(fclk);
-fail_get_fclk:
-       clk_put(iclk);
-fail_get_iclk:
-       iounmap(hcd->regs);
-fail_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
        usb_put_hcd(hcd);
 fail_create_hcd:
@@ -209,13 +195,9 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
 
        ehci_shutdown(hcd);
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
        atmel_stop_ehci(pdev);
-       clk_put(fclk);
-       clk_put(iclk);
        fclk = iclk = NULL;
 
        return 0;
index cba10d625a5d6430d8343717bb80b7cbd0f3ca9a..65c945eb4144a2d9d9f23dcd8685b1e1aade52d6 100644 (file)
@@ -98,23 +98,17 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
-               ret = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
-               pr_debug("ioremap failed");
+               pr_debug("devm_request_and_ioremap failed");
                ret = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) {
                printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
                ret = -ENODEV;
-               goto err3;
+               goto err1;
        }
 
        ret = usb_add_hcd(hcd, pdev->resource[1].start,
@@ -125,10 +119,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
        }
 
        alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
-err3:
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
        return ret;
@@ -140,8 +130,6 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 
        usb_remove_hcd(hcd);
        alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
index caaa3e5be3347360d8a228838f26bb8e70d875f6..d91708d2e7298f7072c5cb77ff1bcefb396efb12 100644 (file)
@@ -105,27 +105,17 @@ static int cns3xxx_ehci_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(dev, "controller already in use\n");
-               retval = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(dev, "error mapping memory\n");
                retval = -EFAULT;
-               goto err2;
+               goto err1;
        }
 
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval == 0)
                return retval;
 
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
 
@@ -137,8 +127,6 @@ static int cns3xxx_ehci_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
        /*
         * EHCI and OHCI share the same clock and power,
index b7451b29c5acbae4d0895035a04a6c2aa67e803d..11ff4b4dc7ad0e782ee9b8b0e02add9dd8aecb19 100644 (file)
@@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
        usb_put_hcd(hcd);
 }
 
-static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
+static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                               enum fsl_usb2_phy_modes phy_mode,
                               unsigned int port_offset)
 {
-       u32 portsc, temp;
+       u32 portsc;
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        void __iomem *non_ehci = hcd->regs;
        struct device *dev = hcd->self.controller;
@@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
        case FSL_USB2_PHY_ULPI:
                if (pdata->controller_ver) {
                        /* controller version 1.6 or above */
-                       temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-                       out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-                               USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+                       setbits32(non_ehci + FSL_SOC_USB_CTRL,
+                                       ULPI_PHY_CLK_SEL);
+                       /*
+                        * Due to controller issue of PHY_CLK_VALID in ULPI
+                        * mode, we set USB_CTRL_USB_EN before checking
+                        * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work.
+                        */
+                       clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
+                                       UTMI_PHY_EN, USB_CTRL_USB_EN);
                }
                portsc |= PORT_PTS_ULPI;
                break;
@@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
        case FSL_USB2_PHY_UTMI:
                if (pdata->controller_ver) {
                        /* controller version 1.6 or above */
-                       temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-                       out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-                               UTMI_PHY_EN | USB_CTRL_USB_EN);
+                       setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
                        mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
                                                become stable - 10ms*/
                }
@@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
        case FSL_USB2_PHY_NONE:
                break;
        }
+
+       if ((pdata->controller_ver) && ((phy_mode == FSL_USB2_PHY_ULPI) ||
+                       (phy_mode == FSL_USB2_PHY_UTMI))) {
+               /* check PHY_CLK_VALID to get phy clk valid */
+               if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
+                               PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
+                       printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
+                       return -EINVAL;
+               }
+       }
+
        ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
+
+       if (phy_mode != FSL_USB2_PHY_ULPI)
+               setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN);
+
+       return 0;
 }
 
-static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
        struct usb_hcd *hcd = ehci_to_hcd(ehci);
        struct fsl_usb2_platform_data *pdata;
        void __iomem *non_ehci = hcd->regs;
-       u32 temp;
 
        pdata = hcd->self.controller->platform_data;
 
-       /* Enable PHY interface in the control reg. */
        if (pdata->have_sysif_regs) {
-               temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-               out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-
                /*
                * Turn on cache snooping hardware, since some PowerPC platforms
                * wholly rely on hardware to deal with cache coherent
@@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 
        if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
                        (pdata->operating_mode == FSL_USB2_DR_OTG))
-               ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+               if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+                       return -EINVAL;
 
        if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
                unsigned int chip, rev, svr;
@@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
                        ehci->has_fsl_port_bug = 1;
 
                if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-                       ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+                       if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+                               return -EINVAL;
+
                if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-                       ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
+                       if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1))
+                               return -EINVAL;
        }
 
        if (pdata->have_sysif_regs) {
@@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 #endif
                out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
        }
+
+       return 0;
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-       ehci_fsl_usb_setup(ehci);
+       if (ehci_fsl_usb_setup(ehci))
+               return -EINVAL;
        ehci_port_power(ehci, 0);
 
        return 0;
index 88403684d10b4ae1c0571d3af6285fe6042cdd2c..dbd292e9f0a7d5a7a31b9a2dcb1bf968b2ed7fa4 100644 (file)
@@ -61,4 +61,5 @@
 #define PLL_RESET               (1<<8)
 #define UTMI_PHY_EN             (1<<9)
 #define ULPI_PHY_CLK_SEL        (1<<10)
+#define PHY_CLK_VALID          (1<<17)
 #endif                         /* _EHCI_FSL_H */
index 22ca45c079a4223ed1cae600c83133881d327a99..3180cb3624d9839d90846c1dceea48ab5ac817c1 100644 (file)
@@ -127,12 +127,6 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
        hcd->rsrc_start = res.start;
        hcd->rsrc_len = resource_size(&res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-               rv = -EBUSY;
-               goto err_rmr;
-       }
-
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -140,9 +134,9 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
                goto err_irq;
        }
 
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&op->dev, &res);
        if (!hcd->regs) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+               pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                goto err_ioremap;
        }
@@ -161,17 +155,13 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
 
        rv = usb_add_hcd(hcd, irq, 0);
        if (rv)
-               goto err_ehci;
+               goto err_ioremap;
 
        return 0;
 
-err_ehci:
-       iounmap(hcd->regs);
 err_ioremap:
        irq_dispose_mapping(irq);
 err_irq:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
        usb_put_hcd(hcd);
 
        return rv;
@@ -188,9 +178,7 @@ static int ehci_hcd_grlib_remove(struct platform_device *op)
 
        usb_remove_hcd(hcd);
 
-       iounmap(hcd->regs);
        irq_dispose_mapping(hcd->irq);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
        usb_put_hcd(hcd);
 
index 488d401942e90c784e02d687087773324b178b8a..f224c0a48bed117ef3ab475941839f6617be9086 100644 (file)
@@ -98,30 +98,19 @@ static int ixp4xx_ehci_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               retval = -EBUSY;
-               goto fail_request_resource;
-       }
-
-       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                retval = -EFAULT;
-               goto fail_ioremap;
+               goto fail_request_resource;
        }
 
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval)
-               goto fail_add_hcd;
+               goto fail_request_resource;
 
        return retval;
 
-fail_add_hcd:
-       iounmap(hcd->regs);
-fail_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
        usb_put_hcd(hcd);
 fail_create_hcd:
@@ -134,8 +123,6 @@ static int ixp4xx_ehci_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
        return 0;
index a283e59709d6ce8a4cf0ba50dc7b8e229d65654a..ca759652626bcf5f823a32bf9e6640acda23a02b 100644 (file)
@@ -106,29 +106,19 @@ static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len   = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               ret = -EBUSY;
-               goto err_put_hcd;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                ret = -EFAULT;
-               goto err_release_region;
+               goto err_put_hcd;
        }
 
-       ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+       ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret)
-               goto err_iounmap;
+               goto err_put_hcd;
 
        return ret;
 
-err_iounmap:
-       iounmap(hcd->regs);
-err_release_region:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
        usb_put_hcd(hcd);
        return ret;
@@ -139,8 +129,6 @@ static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
        return 0;
index 17dd9e94001ec679329b2492f6620b51b7ac373a..4af4dc5b618c5710bd4f6226361916763122ac53 100644 (file)
@@ -133,7 +133,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
 
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
@@ -145,17 +145,17 @@ static int ehci_msm_probe(struct platform_device *pdev)
         * powering up VBUS, mapping of registers address space and power
         * management.
         */
-       phy = usb_get_phy(USB_PHY_TYPE_USB2);
+       phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
        if (IS_ERR_OR_NULL(phy)) {
                dev_err(&pdev->dev, "unable to find transceiver\n");
                ret = -ENODEV;
-               goto unmap;
+               goto put_hcd;
        }
 
        ret = otg_set_host(phy->otg, &hcd->self);
        if (ret < 0) {
                dev_err(&pdev->dev, "unable to register with transceiver\n");
-               goto put_transceiver;
+               goto put_hcd;
        }
 
        device_init_wakeup(&pdev->dev, 1);
@@ -168,10 +168,6 @@ static int ehci_msm_probe(struct platform_device *pdev)
 
        return 0;
 
-put_transceiver:
-       usb_put_phy(phy);
-unmap:
-       iounmap(hcd->regs);
 put_hcd:
        usb_put_hcd(hcd);
 
@@ -187,7 +183,6 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
        pm_runtime_set_suspended(&pdev->dev);
 
        otg_set_host(phy->otg, NULL);
-       usb_put_phy(phy);
 
        usb_put_hcd(hcd);
 
index f6df1ccc961775ac182ce32838c71360bce8611d..f7bfc0b898b97a90dfece792fe40ca16ef4a2f73 100644 (file)
@@ -161,7 +161,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
-       ehci_mv = kzalloc(size, GFP_KERNEL);
+       ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
        if (ehci_mv == NULL) {
                dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
                retval = -ENOMEM;
@@ -175,12 +175,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
        ehci_mv->clknum = pdata->clknum;
        for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
                ehci_mv->clk[clk_i] =
-                   clk_get(&pdev->dev, pdata->clkname[clk_i]);
+                   devm_clk_get(&pdev->dev, pdata->clkname[clk_i]);
                if (IS_ERR(ehci_mv->clk[clk_i])) {
                        dev_err(&pdev->dev, "error get clck \"%s\"\n",
                                pdata->clkname[clk_i]);
                        retval = PTR_ERR(ehci_mv->clk[clk_i]);
-                       goto err_put_clk;
+                       goto err_clear_drvdata;
                }
        }
 
@@ -188,34 +188,36 @@ static int mv_ehci_probe(struct platform_device *pdev)
        if (r == NULL) {
                dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
                retval = -ENODEV;
-               goto err_put_clk;
+               goto err_clear_drvdata;
        }
 
-       ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
+       ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start,
+                                        resource_size(r));
        if (ehci_mv->phy_regs == 0) {
                dev_err(&pdev->dev, "failed to map phy I/O memory\n");
                retval = -EFAULT;
-               goto err_put_clk;
+               goto err_clear_drvdata;
        }
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
        if (!r) {
                dev_err(&pdev->dev, "no I/O memory resource defined\n");
                retval = -ENODEV;
-               goto err_iounmap_phyreg;
+               goto err_clear_drvdata;
        }
 
-       ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
+       ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start,
+                                        resource_size(r));
        if (ehci_mv->cap_regs == NULL) {
                dev_err(&pdev->dev, "failed to map I/O memory\n");
                retval = -EFAULT;
-               goto err_iounmap_phyreg;
+               goto err_clear_drvdata;
        }
 
        retval = mv_ehci_enable(ehci_mv);
        if (retval) {
                dev_err(&pdev->dev, "init phy error %d\n", retval);
-               goto err_iounmap_capreg;
+               goto err_clear_drvdata;
        }
 
        offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
@@ -239,7 +241,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
        ehci_mv->mode = pdata->mode;
        if (ehci_mv->mode == MV_USB_MODE_OTG) {
 #ifdef CONFIG_USB_OTG_UTILS
-               ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+               ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
                if (IS_ERR_OR_NULL(ehci_mv->otg)) {
                        dev_err(&pdev->dev,
                                "unable to find transceiver\n");
@@ -252,7 +254,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "unable to register with transceiver\n");
                        retval = -ENODEV;
-                       goto err_put_transceiver;
+                       goto err_disable_clk;
                }
                /* otg will enable clock before use as host */
                mv_ehci_disable(ehci_mv);
@@ -286,22 +288,10 @@ static int mv_ehci_probe(struct platform_device *pdev)
 err_set_vbus:
        if (pdata->set_vbus)
                pdata->set_vbus(0);
-#ifdef CONFIG_USB_OTG_UTILS
-err_put_transceiver:
-       if (!IS_ERR_OR_NULL(ehci_mv->otg))
-               usb_put_phy(ehci_mv->otg);
-#endif
 err_disable_clk:
        mv_ehci_disable(ehci_mv);
-err_iounmap_capreg:
-       iounmap(ehci_mv->cap_regs);
-err_iounmap_phyreg:
-       iounmap(ehci_mv->phy_regs);
-err_put_clk:
-       for (clk_i--; clk_i >= 0; clk_i--)
-               clk_put(ehci_mv->clk[clk_i]);
+err_clear_drvdata:
        platform_set_drvdata(pdev, NULL);
-       kfree(ehci_mv);
 err_put_hcd:
        usb_put_hcd(hcd);
 
@@ -317,10 +307,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
        if (hcd->rh_registered)
                usb_remove_hcd(hcd);
 
-       if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
+       if (!IS_ERR_OR_NULL(ehci_mv->otg))
                otg_set_host(ehci_mv->otg->otg, NULL);
-               usb_put_phy(ehci_mv->otg);
-       }
 
        if (ehci_mv->mode == MV_USB_MODE_HOST) {
                if (ehci_mv->pdata->set_vbus)
@@ -329,15 +317,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
                mv_ehci_disable(ehci_mv);
        }
 
-       iounmap(ehci_mv->cap_regs);
-       iounmap(ehci_mv->phy_regs);
-
-       for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
-               clk_put(ehci_mv->clk[clk_i]);
-
        platform_set_drvdata(pdev, NULL);
 
-       kfree(ehci_mv);
        usb_put_hcd(hcd);
 
        return 0;
index 34201372c85f57c799c13e4d8ceb7561629bb7e8..959e1a4c34911c5919e133c1320c779f50454e0d 100644 (file)
@@ -121,7 +121,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (!hcd)
                return -ENOMEM;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                ret = -ENOMEM;
                goto err_alloc;
@@ -131,34 +131,28 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(dev, "Found HC with no register addr. Check setup!\n");
                ret = -ENODEV;
-               goto err_get_resource;
+               goto err_alloc;
        }
 
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               dev_dbg(dev, "controller already in use\n");
-               ret = -EBUSY;
-               goto err_request_mem;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
                dev_err(dev, "error mapping memory\n");
                ret = -EFAULT;
-               goto err_ioremap;
+               goto err_alloc;
        }
 
        /* enable clocks */
-       priv->usbclk = clk_get(dev, "ipg");
+       priv->usbclk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(priv->usbclk)) {
                ret = PTR_ERR(priv->usbclk);
-               goto err_clk;
+               goto err_alloc;
        }
        clk_prepare_enable(priv->usbclk);
 
-       priv->ahbclk = clk_get(dev, "ahb");
+       priv->ahbclk = devm_clk_get(&pdev->dev, "ahb");
        if (IS_ERR(priv->ahbclk)) {
                ret = PTR_ERR(priv->ahbclk);
                goto err_clk_ahb;
@@ -166,7 +160,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        clk_prepare_enable(priv->ahbclk);
 
        /* "dr" device has its own clock on i.MX51 */
-       priv->phyclk = clk_get(dev, "phy");
+       priv->phyclk = devm_clk_get(&pdev->dev, "phy");
        if (IS_ERR(priv->phyclk))
                priv->phyclk = NULL;
        if (priv->phyclk)
@@ -245,23 +239,12 @@ err_add:
        if (pdata && pdata->exit)
                pdata->exit(pdev);
 err_init:
-       if (priv->phyclk) {
+       if (priv->phyclk)
                clk_disable_unprepare(priv->phyclk);
-               clk_put(priv->phyclk);
-       }
 
        clk_disable_unprepare(priv->ahbclk);
-       clk_put(priv->ahbclk);
 err_clk_ahb:
        clk_disable_unprepare(priv->usbclk);
-       clk_put(priv->usbclk);
-err_clk:
-       iounmap(hcd->regs);
-err_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_request_mem:
-err_get_resource:
-       kfree(priv);
 err_alloc:
        usb_put_hcd(hcd);
        return ret;
@@ -280,22 +263,14 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
                usb_phy_shutdown(pdata->otg);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
        clk_disable_unprepare(priv->usbclk);
-       clk_put(priv->usbclk);
        clk_disable_unprepare(priv->ahbclk);
-       clk_put(priv->ahbclk);
 
-       if (priv->phyclk) {
+       if (priv->phyclk)
                clk_disable_unprepare(priv->phyclk);
-               clk_put(priv->phyclk);
-       }
-
-       kfree(priv);
 
        return 0;
 }
index bb55eb4a7d485b806e69ba0c5141912f04bd6791..d7fe287d067803e484d56efdf53060546634ea1e 100644 (file)
 #define        EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT             8
 #define        EHCI_INSNREG05_ULPI_WRDATA_SHIFT                0
 
-/* Errata i693 */
-static struct clk      *utmi_p1_fck;
-static struct clk      *utmi_p2_fck;
-static struct clk      *xclk60mhsp1_ck;
-static struct clk      *xclk60mhsp2_ck;
-static struct clk      *usbhost_p1_fck;
-static struct clk      *usbhost_p2_fck;
-static struct clk      *init_60m_fclk;
-
 /*-------------------------------------------------------------------------*/
 
 static const struct hc_driver ehci_omap_hc_driver;
@@ -80,40 +71,6 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
        return __raw_readl(base + reg);
 }
 
-/* Erratum i693 workaround sequence */
-static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
-{
-       int ret = 0;
-
-       /* Switch to the internal 60 MHz clock */
-       ret = clk_set_parent(utmi_p1_fck, init_60m_fclk);
-       if (ret != 0)
-               ehci_err(ehci, "init_60m_fclk set parent"
-                       "failed error:%d\n", ret);
-
-       ret = clk_set_parent(utmi_p2_fck, init_60m_fclk);
-       if (ret != 0)
-               ehci_err(ehci, "init_60m_fclk set parent"
-                       "failed error:%d\n", ret);
-
-       clk_enable(usbhost_p1_fck);
-       clk_enable(usbhost_p2_fck);
-
-       /* Wait 1ms and switch back to the external clock */
-       mdelay(1);
-       ret = clk_set_parent(utmi_p1_fck, xclk60mhsp1_ck);
-       if (ret != 0)
-               ehci_err(ehci, "xclk60mhsp1_ck set parent"
-                       "failed error:%d\n", ret);
-
-       ret = clk_set_parent(utmi_p2_fck, xclk60mhsp2_ck);
-       if (ret != 0)
-               ehci_err(ehci, "xclk60mhsp2_ck set parent"
-                       "failed error:%d\n", ret);
-
-       clk_disable(usbhost_p1_fck);
-       clk_disable(usbhost_p2_fck);
-}
 
 static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
 {
@@ -195,50 +152,6 @@ static int omap_ehci_init(struct usb_hcd *hcd)
        return rc;
 }
 
-static int omap_ehci_hub_control(
-       struct usb_hcd  *hcd,
-       u16             typeReq,
-       u16             wValue,
-       u16             wIndex,
-       char            *buf,
-       u16             wLength
-)
-{
-       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-       u32 __iomem *status_reg = &ehci->regs->port_status[
-                               (wIndex & 0xff) - 1];
-       u32             temp;
-       unsigned long   flags;
-       int             retval = 0;
-
-       spin_lock_irqsave(&ehci->lock, flags);
-
-       if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
-               temp = ehci_readl(ehci, status_reg);
-               if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
-                       retval = -EPIPE;
-                       goto done;
-               }
-
-               temp &= ~PORT_WKCONN_E;
-               temp |= PORT_WKDISC_E | PORT_WKOC_E;
-               ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
-
-               omap_ehci_erratum_i693(ehci);
-
-               set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
-               goto done;
-       }
-
-       spin_unlock_irqrestore(&ehci->lock, flags);
-
-       /* Handle the hub control events here */
-       return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
-done:
-       spin_unlock_irqrestore(&ehci->lock, flags);
-       return retval;
-}
-
 static void disable_put_regulator(
                struct ehci_hcd_omap_platform_data *pdata)
 {
@@ -351,79 +264,9 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
                goto err_pm_runtime;
        }
 
-       /* get clocks */
-       utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
-       if (IS_ERR(utmi_p1_fck)) {
-               ret = PTR_ERR(utmi_p1_fck);
-               dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
-               goto err_add_hcd;
-       }
-
-       xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
-       if (IS_ERR(xclk60mhsp1_ck)) {
-               ret = PTR_ERR(xclk60mhsp1_ck);
-               dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
-               goto err_utmi_p1_fck;
-       }
-
-       utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
-       if (IS_ERR(utmi_p2_fck)) {
-               ret = PTR_ERR(utmi_p2_fck);
-               dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
-               goto err_xclk60mhsp1_ck;
-       }
-
-       xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
-       if (IS_ERR(xclk60mhsp2_ck)) {
-               ret = PTR_ERR(xclk60mhsp2_ck);
-               dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
-               goto err_utmi_p2_fck;
-       }
-
-       usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
-       if (IS_ERR(usbhost_p1_fck)) {
-               ret = PTR_ERR(usbhost_p1_fck);
-               dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
-               goto err_xclk60mhsp2_ck;
-       }
-
-       usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
-       if (IS_ERR(usbhost_p2_fck)) {
-               ret = PTR_ERR(usbhost_p2_fck);
-               dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
-               goto err_usbhost_p1_fck;
-       }
-
-       init_60m_fclk = clk_get(dev, "init_60m_fclk");
-       if (IS_ERR(init_60m_fclk)) {
-               ret = PTR_ERR(init_60m_fclk);
-               dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
-               goto err_usbhost_p2_fck;
-       }
 
        return 0;
 
-err_usbhost_p2_fck:
-       clk_put(usbhost_p2_fck);
-
-err_usbhost_p1_fck:
-       clk_put(usbhost_p1_fck);
-
-err_xclk60mhsp2_ck:
-       clk_put(xclk60mhsp2_ck);
-
-err_utmi_p2_fck:
-       clk_put(utmi_p2_fck);
-
-err_xclk60mhsp1_ck:
-       clk_put(xclk60mhsp1_ck);
-
-err_utmi_p1_fck:
-       clk_put(utmi_p1_fck);
-
-err_add_hcd:
-       usb_remove_hcd(hcd);
-
 err_pm_runtime:
        disable_put_regulator(pdata);
        pm_runtime_put_sync(dev);
@@ -454,14 +297,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
        iounmap(hcd->regs);
        usb_put_hcd(hcd);
 
-       clk_put(utmi_p1_fck);
-       clk_put(utmi_p2_fck);
-       clk_put(xclk60mhsp1_ck);
-       clk_put(xclk60mhsp2_ck);
-       clk_put(usbhost_p1_fck);
-       clk_put(usbhost_p2_fck);
-       clk_put(init_60m_fclk);
-
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
@@ -532,7 +367,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
         * root hub support
         */
        .hub_status_data        = ehci_hub_status_data,
-       .hub_control            = omap_ehci_hub_control,
+       .hub_control            = ehci_hub_control,
        .bus_suspend            = ehci_bus_suspend,
        .bus_resume             = ehci_bus_resume,
 
index 4b1d896d5a2214f75f32a5e943e9a4e5804f24f9..764e0100b6f438d82ab64057e8cb37abd638fa79 100644 (file)
@@ -82,10 +82,14 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
        struct resource *res_mem;
+       struct usb_ehci_pdata *pdata = dev->dev.platform_data;
        int irq;
        int err = -ENOMEM;
 
-       BUG_ON(!dev->dev.platform_data);
+       if (!pdata) {
+               WARN_ON(1);
+               return -ENODEV;
+       }
 
        if (usb_disabled())
                return -ENODEV;
@@ -101,10 +105,18 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
                return -ENXIO;
        }
 
+       if (pdata->power_on) {
+               err = pdata->power_on(dev);
+               if (err < 0)
+                       return err;
+       }
+
        hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
                             dev_name(&dev->dev));
-       if (!hcd)
-               return -ENOMEM;
+       if (!hcd) {
+               err = -ENOMEM;
+               goto err_power;
+       }
 
        hcd->rsrc_start = res_mem->start;
        hcd->rsrc_len = resource_size(res_mem);
@@ -116,8 +128,10 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
        }
 
        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-       if (!hcd->regs)
+       if (!hcd->regs) {
+               err = -ENOMEM;
                goto err_release_region;
+       }
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err)
                goto err_iounmap;
@@ -132,12 +146,17 @@ err_release_region:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
        usb_put_hcd(hcd);
+err_power:
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return err;
 }
 
 static int __devexit ehci_platform_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
+       struct usb_ehci_pdata *pdata = dev->dev.platform_data;
 
        usb_remove_hcd(hcd);
        iounmap(hcd->regs);
@@ -145,6 +164,9 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
        usb_put_hcd(hcd);
        platform_set_drvdata(dev, NULL);
 
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return 0;
 }
 
@@ -153,14 +175,32 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
 static int ehci_platform_suspend(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct usb_ehci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
        bool do_wakeup = device_may_wakeup(dev);
+       int ret;
+
+       ret = ehci_suspend(hcd, do_wakeup);
 
-       return ehci_suspend(hcd, do_wakeup);
+       if (pdata->power_suspend)
+               pdata->power_suspend(pdev);
+
+       return ret;
 }
 
 static int ehci_platform_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct usb_ehci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
+
+       if (pdata->power_on) {
+               int err = pdata->power_on(pdev);
+               if (err < 0)
+                       return err;
+       }
 
        ehci_resume(hcd, false);
        return 0;
index bbbe89dfd886b8ef250217cb18c25bc9eb0e0a74..fa937d05a02b9adbb4639c6269e987e620027cfc 100644 (file)
@@ -114,12 +114,6 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
        hcd->rsrc_start = res.start;
        hcd->rsrc_len = resource_size(&res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-               rv = -EBUSY;
-               goto err_rmr;
-       }
-
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -127,9 +121,9 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
                goto err_irq;
        }
 
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&op->dev, &res);
        if (!hcd->regs) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+               pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                goto err_ioremap;
        }
@@ -139,8 +133,10 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
        if (np != NULL) {
                /* claim we really affected by usb23 erratum */
                if (!of_address_to_resource(np, 0, &res))
-                       ehci->ohci_hcctrl_reg = ioremap(res.start +
-                                       OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
+                       ehci->ohci_hcctrl_reg =
+                               devm_ioremap(&op->dev,
+                                            res.start + OHCI_HCCTRL_OFFSET,
+                                            OHCI_HCCTRL_LEN);
                else
                        pr_debug("%s: no ohci offset in fdt\n", __FILE__);
                if (!ehci->ohci_hcctrl_reg) {
@@ -169,19 +165,13 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
 
        rv = usb_add_hcd(hcd, irq, 0);
        if (rv)
-               goto err_ehci;
+               goto err_ioremap;
 
        return 0;
 
-err_ehci:
-       if (ehci->has_amcc_usb23)
-               iounmap(ehci->ohci_hcctrl_reg);
-       iounmap(hcd->regs);
 err_ioremap:
        irq_dispose_mapping(irq);
 err_irq:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
        usb_put_hcd(hcd);
 
        return rv;
@@ -202,9 +192,7 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op)
 
        usb_remove_hcd(hcd);
 
-       iounmap(hcd->regs);
        irq_dispose_mapping(hcd->irq);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
        /* use request_mem_region to test if the ohci driver is loaded.  if so
         * ensure the ohci core is operational.
@@ -222,8 +210,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op)
                                pr_debug("%s: no ohci offset in fdt\n", __FILE__);
                        of_node_put(np);
                }
-
-               iounmap(ehci->ohci_hcctrl_reg);
        }
        usb_put_hcd(hcd);
 
index 9d8f1dd57cb36a5041ec22ef9c60b28923fbcf83..d055503e4183fbefa68b8e572c8e64f1ed1008df 100644 (file)
@@ -128,7 +128,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
        }
 
        s5p_ehci->hcd = hcd;
-       s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
+       s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
 
        if (IS_ERR(s5p_ehci->clk)) {
                dev_err(&pdev->dev, "Failed to get usbhost clock\n");
@@ -138,7 +138,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 
        err = clk_enable(s5p_ehci->clk);
        if (err)
-               goto fail_clken;
+               goto fail_clk;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -184,8 +184,6 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 
 fail_io:
        clk_disable(s5p_ehci->clk);
-fail_clken:
-       clk_put(s5p_ehci->clk);
 fail_clk:
        usb_put_hcd(hcd);
        return err;
@@ -203,7 +201,6 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev)
                pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 
        clk_disable(s5p_ehci->clk);
-       clk_put(s5p_ehci->clk);
 
        usb_put_hcd(hcd);
 
index 58c96bd50d22853d10a8ac423b39acf0e375eeb7..efad02d947f2dff039e519f105cb4b85682e7ba1 100644 (file)
@@ -40,7 +40,7 @@ static int ehci_sead3_setup(struct usb_hcd *hcd)
        ehci->need_io_watchdog = 0;
 
        /* Set burst length to 16 words. */
-       ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]);
+       ehci_writel(ehci, 0x1010, &ehci->regs->reserved1[1]);
 
        return ret;
 }
@@ -112,17 +112,11 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
-               ret = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
                pr_debug("ioremap failed");
                ret = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        /* Root hub has integrated TT. */
@@ -135,9 +129,6 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
                return ret;
        }
 
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
        return ret;
@@ -148,8 +139,6 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
index b3f1e3650da0a455bcea891f231308270dd99a4b..6081e1ed3ac9d9e8338c233829103661d1d46a99 100644 (file)
@@ -125,33 +125,27 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               ret = -EBUSY;
-               goto fail_request_resource;
-       }
-
-       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                ret = -ENXIO;
-               goto fail_ioremap;
+               goto fail_request_resource;
        }
 
-       priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL);
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv),
+                           GFP_KERNEL);
        if (!priv) {
                dev_dbg(&pdev->dev, "error allocating priv data\n");
                ret = -ENOMEM;
-               goto fail_alloc;
+               goto fail_request_resource;
        }
 
        /* These are optional, we don't care if they fail */
-       priv->fclk = clk_get(&pdev->dev, "usb_fck");
+       priv->fclk = devm_clk_get(&pdev->dev, "usb_fck");
        if (IS_ERR(priv->fclk))
                priv->fclk = NULL;
 
-       priv->iclk = clk_get(&pdev->dev, "usb_ick");
+       priv->iclk = devm_clk_get(&pdev->dev, "usb_ick");
        if (IS_ERR(priv->iclk))
                priv->iclk = NULL;
 
@@ -176,14 +170,6 @@ fail_add_hcd:
        clk_disable(priv->iclk);
        clk_disable(priv->fclk);
 
-       clk_put(priv->iclk);
-       clk_put(priv->fclk);
-
-       kfree(priv);
-fail_alloc:
-       iounmap(hcd->regs);
-fail_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
        usb_put_hcd(hcd);
 fail_create_hcd:
@@ -198,19 +184,12 @@ static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = priv->hcd;
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
        clk_disable(priv->fclk);
        clk_disable(priv->iclk);
 
-       clk_put(priv->fclk);
-       clk_put(priv->iclk);
-
-       kfree(priv);
-
        return 0;
 }
 
index 950e95efa381bce88d7c6c148ac90609755ee83b..6223d1757848c6d43db7aa59d7042b1c8c736f02 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 
-#include <mach/usb_phy.h>
+#include <linux/usb/tegra_usb_phy.h>
 #include <mach/iomap.h>
 
 #define TEGRA_USB_DMA_ALIGN 32
@@ -49,7 +49,7 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd)
 
        clk_prepare_enable(tegra->emc_clk);
        clk_prepare_enable(tegra->clk);
-       tegra_usb_phy_power_on(tegra->phy);
+       usb_phy_set_suspend(&tegra->phy->u_phy, 0);
        tegra->host_resumed = 1;
 }
 
@@ -58,7 +58,7 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd)
        struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
 
        tegra->host_resumed = 0;
-       tegra_usb_phy_power_off(tegra->phy);
+       usb_phy_set_suspend(&tegra->phy->u_phy, 1);
        clk_disable_unprepare(tegra->clk);
        clk_disable_unprepare(tegra->emc_clk);
 }
@@ -634,7 +634,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
        setup_vbus_gpio(pdev, pdata);
 
-       tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
+       tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd),
+                            GFP_KERNEL);
        if (!tegra)
                return -ENOMEM;
 
@@ -642,13 +643,12 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                                        dev_name(&pdev->dev));
        if (!hcd) {
                dev_err(&pdev->dev, "Unable to create HCD\n");
-               err = -ENOMEM;
-               goto fail_hcd;
+               return -ENOMEM;
        }
 
        platform_set_drvdata(pdev, tegra);
 
-       tegra->clk = clk_get(&pdev->dev, NULL);
+       tegra->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(tegra->clk)) {
                dev_err(&pdev->dev, "Can't get ehci clock\n");
                err = PTR_ERR(tegra->clk);
@@ -657,9 +657,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
        err = clk_prepare_enable(tegra->clk);
        if (err)
-               goto fail_clken;
+               goto fail_clk;
 
-       tegra->emc_clk = clk_get(&pdev->dev, "emc");
+       tegra->emc_clk = devm_clk_get(&pdev->dev, "emc");
        if (IS_ERR(tegra->emc_clk)) {
                dev_err(&pdev->dev, "Can't get emc clock\n");
                err = PTR_ERR(tegra->emc_clk);
@@ -677,7 +677,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        }
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
-       hcd->regs = ioremap(res->start, resource_size(res));
+       hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!hcd->regs) {
                dev_err(&pdev->dev, "Failed to remap I/O memory\n");
                err = -ENOMEM;
@@ -702,7 +702,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                default:
                        err = -ENODEV;
                        dev_err(&pdev->dev, "unknown usb instance\n");
-                       goto fail_phy;
+                       goto fail_io;
                }
        }
 
@@ -712,10 +712,12 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        if (IS_ERR(tegra->phy)) {
                dev_err(&pdev->dev, "Failed to open USB phy\n");
                err = -ENXIO;
-               goto fail_phy;
+               goto fail_io;
        }
 
-       err = tegra_usb_phy_power_on(tegra->phy);
+       usb_phy_init(&tegra->phy->u_phy);
+
+       err = usb_phy_set_suspend(&tegra->phy->u_phy, 0);
        if (err) {
                dev_err(&pdev->dev, "Failed to power on the phy\n");
                goto fail;
@@ -733,7 +735,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_USB_OTG_UTILS
        if (pdata->operating_mode == TEGRA_USB_OTG) {
-               tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+               tegra->transceiver =
+                       devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
                if (!IS_ERR_OR_NULL(tegra->transceiver))
                        otg_set_host(tegra->transceiver->otg, &hcd->self);
        }
@@ -757,25 +760,16 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
 fail:
 #ifdef CONFIG_USB_OTG_UTILS
-       if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+       if (!IS_ERR_OR_NULL(tegra->transceiver))
                otg_set_host(tegra->transceiver->otg, NULL);
-               usb_put_phy(tegra->transceiver);
-       }
 #endif
-       tegra_usb_phy_close(tegra->phy);
-fail_phy:
-       iounmap(hcd->regs);
+       usb_phy_shutdown(&tegra->phy->u_phy);
 fail_io:
        clk_disable_unprepare(tegra->emc_clk);
-       clk_put(tegra->emc_clk);
 fail_emc_clk:
        clk_disable_unprepare(tegra->clk);
-fail_clken:
-       clk_put(tegra->clk);
 fail_clk:
        usb_put_hcd(hcd);
-fail_hcd:
-       kfree(tegra);
        return err;
 }
 
@@ -792,25 +786,19 @@ static int tegra_ehci_remove(struct platform_device *pdev)
        pm_runtime_put_noidle(&pdev->dev);
 
 #ifdef CONFIG_USB_OTG_UTILS
-       if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+       if (!IS_ERR_OR_NULL(tegra->transceiver))
                otg_set_host(tegra->transceiver->otg, NULL);
-               usb_put_phy(tegra->transceiver);
-       }
 #endif
 
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
 
-       tegra_usb_phy_close(tegra->phy);
-       iounmap(hcd->regs);
+       usb_phy_shutdown(&tegra->phy->u_phy);
 
        clk_disable_unprepare(tegra->clk);
-       clk_put(tegra->clk);
 
        clk_disable_unprepare(tegra->emc_clk);
-       clk_put(tegra->emc_clk);
 
-       kfree(tegra);
        return 0;
 }
 
index 4d147c4e33f5343802787d5db358b25fcfae0244..96722bfebc84ba0bed49f6cd4c0aa3313f7f55dd 100644 (file)
@@ -16,6 +16,7 @@
  *
  */
 
+#include <linux/of.h>
 #include <linux/platform_device.h>
 
 static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
@@ -106,17 +107,11 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
-               ret = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
                pr_debug("ioremap failed");
                ret = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        ehci = hcd_to_ehci(hcd);
@@ -129,9 +124,6 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
                return ret;
        }
 
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
        return ret;
@@ -142,14 +134,18 @@ static int vt8500_ehci_drv_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
+static const struct of_device_id vt8500_ehci_ids[] = {
+       { .compatible = "via,vt8500-ehci", },
+       { .compatible = "wm,prizm-ehci", },
+       {}
+};
+
 static struct platform_driver vt8500_ehci_driver = {
        .probe          = vt8500_ehci_drv_probe,
        .remove         = vt8500_ehci_drv_remove,
@@ -157,7 +153,9 @@ static struct platform_driver vt8500_ehci_driver = {
        .driver = {
                .name   = "vt8500-ehci",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(vt8500_ehci_ids),
        }
 };
 
 MODULE_ALIAS("platform:vt8500-ehci");
+MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
index 39f24fa37ebe9fff07c3f38087dbf6f04bedaaa8..6a3f921a5d7683f1434e972a4b59c5fabf470dbc 100644 (file)
@@ -152,12 +152,6 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
        hcd->rsrc_start = res.start;
        hcd->rsrc_len = resource_size(&res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-               rv = -EBUSY;
-               goto err_rmr;
-       }
-
        irq = irq_of_parse_and_map(dn, 0);
        if (!irq) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -165,11 +159,11 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
                goto err_irq;
        }
 
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&op->dev, &res);
        if (!hcd->regs) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+               pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
                rv = -ENOMEM;
-               goto err_ioremap;
+               goto err_irq;
        }
 
        ehci = hcd_to_ehci(hcd);
@@ -200,12 +194,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
        if (rv == 0)
                return 0;
 
-       iounmap(hcd->regs);
-
-err_ioremap:
 err_irq:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
        usb_put_hcd(hcd);
 
        return rv;
@@ -227,9 +216,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op)
 
        usb_remove_hcd(hcd);
 
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
        usb_put_hcd(hcd);
 
        return 0;
index 2dc8a40e39d76e5d73023fdd7e433173ef5b01cf..8f18538e0ff752ceef59e44381a5a00bc2e9ce6b 100644 (file)
@@ -261,8 +261,7 @@ static void move_head_to_tail(struct list_head *list)
        struct list_head *node = list->next;
 
        if (!list_empty(list)) {
-               list_del(node);
-               list_add_tail(node, list);
+               list_move_tail(node, list);
        }
 }
 
index 2ed112d3e1595d45c5d6a8ab4053c883310124d1..256326322cfd8b96dd5ee686c0f1a769be52a074 100644 (file)
@@ -543,12 +543,12 @@ static void postproc_ep(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep)
                            usb_pipein(urb->pipe) ? "IN" : "OUT", ep->nextpid,
                            short_ok ? "" : "not_",
                            PTD_GET_COUNT(ptd), ep->maxpacket, len);
+                       /* save the data underrun error code for later and
+                        * proceed with the status stage
+                        */
+                       urb->actual_length += PTD_GET_COUNT(ptd);
                        if (usb_pipecontrol(urb->pipe)) {
                                ep->nextpid = USB_PID_ACK;
-                               /* save the data underrun error code for later and
-                                * proceed with the status stage
-                                */
-                               urb->actual_length += PTD_GET_COUNT(ptd);
                                BUG_ON(urb->actual_length > urb->transfer_buffer_length);
 
                                if (urb->status == -EINPROGRESS)
index a446386bf779208518b760ffcfb94cc346dc4f5b..c60066a636068addf10ad8b66539fd370ce6af71 100644 (file)
@@ -355,7 +355,7 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
        usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
        if (IS_ERR(usb_otg_clk)) {
                dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
-               ret = PTR_ERR(usb_dev_clk);
+               ret = PTR_ERR(usb_otg_clk);
                goto out6;
        }
 
index e7d75d295988c3fabc64c36fdf6d1db23f70b7d0..f8b2d91851f7cbfd509aa35b98119acdc544e948 100644 (file)
@@ -403,8 +403,6 @@ err0:
 static inline void
 usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 {
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
-
        usb_remove_hcd(hcd);
        if (!IS_ERR_OR_NULL(hcd->phy)) {
                (void) otg_set_host(hcd->phy->otg, 0);
index 670c7059c9ae3aaa8fc3530d17639005cf36bbac..e24ec9f79164afc9e6563a147cb76d4c0f3c96c3 100644 (file)
@@ -83,10 +83,14 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
        struct resource *res_mem;
+       struct usb_ohci_pdata *pdata = dev->dev.platform_data;
        int irq;
        int err = -ENOMEM;
 
-       BUG_ON(!dev->dev.platform_data);
+       if (!pdata) {
+               WARN_ON(1);
+               return -ENODEV;
+       }
 
        if (usb_disabled())
                return -ENODEV;
@@ -103,10 +107,18 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
                return -ENXIO;
        }
 
+       if (pdata->power_on) {
+               err = pdata->power_on(dev);
+               if (err < 0)
+                       return err;
+       }
+
        hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
                        dev_name(&dev->dev));
-       if (!hcd)
-               return -ENOMEM;
+       if (!hcd) {
+               err = -ENOMEM;
+               goto err_power;
+       }
 
        hcd->rsrc_start = res_mem->start;
        hcd->rsrc_len = resource_size(res_mem);
@@ -118,8 +130,10 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
        }
 
        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-       if (!hcd->regs)
+       if (!hcd->regs) {
+               err = -ENOMEM;
                goto err_release_region;
+       }
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err)
                goto err_iounmap;
@@ -134,12 +148,17 @@ err_release_region:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
        usb_put_hcd(hcd);
+err_power:
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return err;
 }
 
 static int __devexit ohci_platform_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
+       struct usb_ohci_pdata *pdata = dev->dev.platform_data;
 
        usb_remove_hcd(hcd);
        iounmap(hcd->regs);
@@ -147,6 +166,9 @@ static int __devexit ohci_platform_remove(struct platform_device *dev)
        usb_put_hcd(hcd);
        platform_set_drvdata(dev, NULL);
 
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return 0;
 }
 
@@ -154,12 +176,28 @@ static int __devexit ohci_platform_remove(struct platform_device *dev)
 
 static int ohci_platform_suspend(struct device *dev)
 {
+       struct usb_ohci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
+
+       if (pdata->power_suspend)
+               pdata->power_suspend(pdev);
+
        return 0;
 }
 
 static int ohci_platform_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct usb_ohci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
+
+       if (pdata->power_on) {
+               int err = pdata->power_on(pdev);
+               if (err < 0)
+                       return err;
+       }
 
        ohci_finish_controller_resume(hcd);
        return 0;
index e1a3cc6d28dcc0ba69917bfb7a8b92d96c10c86b..77f4402aca03e0a16a9875431df8ec51bd60e311 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/signal.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 #include <mach/hardware.h>
 #include <mach/ohci.h>
 #include <mach/pxa3xx-u2d.h>
@@ -272,6 +274,67 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
        clk_disable_unprepare(ohci->clk);
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ohci_dt_ids[] = {
+       { .compatible = "marvell,pxa-ohci" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids);
+
+static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_pxa_of_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct pxaohci_platform_data *pdata;
+       u32 tmp;
+
+       if (!np)
+               return 0;
+
+       /* Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &pxa_ohci_dma_mask;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       if (of_get_property(np, "marvell,enable-port1", NULL))
+               pdata->flags |= ENABLE_PORT1;
+       if (of_get_property(np, "marvell,enable-port2", NULL))
+               pdata->flags |= ENABLE_PORT2;
+       if (of_get_property(np, "marvell,enable-port3", NULL))
+               pdata->flags |= ENABLE_PORT3;
+       if (of_get_property(np, "marvell,port-sense-low", NULL))
+               pdata->flags |= POWER_SENSE_LOW;
+       if (of_get_property(np, "marvell,power-control-low", NULL))
+               pdata->flags |= POWER_CONTROL_LOW;
+       if (of_get_property(np, "marvell,no-oc-protection", NULL))
+               pdata->flags |= NO_OC_PROTECTION;
+       if (of_get_property(np, "marvell,oc-mode-perport", NULL))
+               pdata->flags |= OC_MODE_PERPORT;
+       if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp))
+               pdata->power_on_delay = tmp;
+       if (!of_property_read_u32(np, "marvell,port-mode", &tmp))
+               pdata->port_mode = tmp;
+       if (!of_property_read_u32(np, "marvell,power-budget", &tmp))
+               pdata->power_budget = tmp;
+
+       pdev->dev.platform_data = pdata;
+
+       return 0;
+}
+#else
+static int __devinit ohci_pxa_of_init(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -297,6 +360,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
        struct resource *r;
        struct clk *usb_clk;
 
+       retval = ohci_pxa_of_init(pdev);
+       if (retval)
+               return retval;
+
        inf = pdev->dev.platform_data;
 
        if (!inf)
@@ -544,6 +611,7 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
        .driver         = {
                .name   = "pxa27x-ohci",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pxa_ohci_dt_ids),
 #ifdef CONFIG_PM
                .pm     = &ohci_hcd_pxa27x_pm_ops,
 #endif
index 41e378f17c66ac453f2aabfd25640c8e77120224..84201cd1a472cd5b00bd959b28bcf35af24137e6 100644 (file)
@@ -56,7 +56,7 @@ static int ohci_xls_probe_internal(const struct hc_driver *driver,
                goto err3;
        }
 
-       retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval != 0)
                goto err4;
        return retval;
index df0828cb2aa328ecf06cb37cb1a6981fa41d52f3..c5e9e4a76f148d4eed0c4785cf46fb38d143a074 100644 (file)
@@ -800,6 +800,13 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
 }
 EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
 
+void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
+{
+       pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, 0x0);
+       pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, 0x0);
+}
+EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
+
 /**
  * PCI Quirks for xHCI.
  *
index b1002a8ef96f58fc46039d6c37b4bcca18d056cb..ef004a5de20f176c27801f83bd9ae2456570e6b1 100644 (file)
@@ -10,6 +10,7 @@ void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
 bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
 void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
+void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 #else
 static inline void usb_amd_quirk_pll_disable(void) {}
 static inline void usb_amd_quirk_pll_enable(void) {}
index 4c634eb56358a1231a6c9fcb1dc05c1b983bf99d..fcc09e5ec0addc9cd9661086b1e18165bd5f8ba4 100644 (file)
@@ -2029,15 +2029,14 @@ static int r8a66597_get_frame(struct usb_hcd *hcd)
 static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
 {
        int chix;
+       struct usb_device *childdev;
 
        if (udev->state == USB_STATE_CONFIGURED &&
            udev->parent && udev->parent->devnum > 1 &&
            udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB)
                map[udev->devnum/32] |= (1 << (udev->devnum % 32));
 
-       for (chix = 0; chix < udev->maxchild; chix++) {
-               struct usb_device *childdev = udev->children[chix];
-
+       usb_hub_for_each_child(udev, chix, childdev) {
                if (childdev)
                        collect_usb_address_map(childdev, map);
        }
index e4db350602b8ea639aca1a1d30a069901f0e4db8..4b9e9aba26654e3f70f5801bf2ada2438a739c94 100644 (file)
@@ -846,6 +846,11 @@ static const char hcd_name[] = "uhci_hcd";
 #define PLATFORM_DRIVER                uhci_grlib_driver
 #endif
 
+#ifdef CONFIG_USB_UHCI_PLATFORM
+#include "uhci-platform.c"
+#define PLATFORM_DRIVER                uhci_platform_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
 #error "missing bus glue for uhci-hcd"
 #endif
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
new file mode 100644 (file)
index 0000000..e478049
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Generic UHCI HCD (Host Controller Driver) for Platform Devices
+ *
+ * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This file is based on uhci-grlib.c
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+static int uhci_platform_init(struct usb_hcd *hcd)
+{
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+       uhci->rh_numports = uhci_count_ports(hcd);
+
+       /* Set up pointers to to generic functions */
+       uhci->reset_hc = uhci_generic_reset_hc;
+       uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
+
+       /* No special actions need to be taken for the functions below */
+       uhci->configure_hc = NULL;
+       uhci->resume_detect_interrupts_are_broken = NULL;
+       uhci->global_suspend_mode_is_broken = NULL;
+
+       /* Reset if the controller isn't already safely quiescent. */
+       check_and_reset_hc(uhci);
+       return 0;
+}
+
+static const struct hc_driver uhci_platform_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "Generic UHCI Host Controller",
+       .hcd_priv_size =        sizeof(struct uhci_hcd),
+
+       /* Generic hardware linkage */
+       .irq =                  uhci_irq,
+       .flags =                HCD_MEMORY | HCD_USB11,
+
+       /* Basic lifecycle operations */
+       .reset =                uhci_platform_init,
+       .start =                uhci_start,
+#ifdef CONFIG_PM
+       .pci_suspend =          NULL,
+       .pci_resume =           NULL,
+       .bus_suspend =          uhci_rh_suspend,
+       .bus_resume =           uhci_rh_resume,
+#endif
+       .stop =                 uhci_stop,
+
+       .urb_enqueue =          uhci_urb_enqueue,
+       .urb_dequeue =          uhci_urb_dequeue,
+
+       .endpoint_disable =     uhci_hcd_endpoint_disable,
+       .get_frame_number =     uhci_hcd_get_frame_number,
+
+       .hub_status_data =      uhci_hub_status_data,
+       .hub_control =          uhci_hub_control,
+};
+
+
+static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+       struct uhci_hcd *uhci;
+       struct resource *res;
+       int ret;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
+                       pdev->name);
+       if (!hcd)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               pr_err("%s: request_mem_region failed\n", __func__);
+               ret = -EBUSY;
+               goto err_rmr;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               pr_err("%s: ioremap failed\n", __func__);
+               ret = -ENOMEM;
+               goto err_irq;
+       }
+       uhci = hcd_to_uhci(hcd);
+
+       uhci->regs = hcd->regs;
+
+       ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED |
+                                                               IRQF_SHARED);
+       if (ret)
+               goto err_uhci;
+
+       return 0;
+
+err_uhci:
+       iounmap(hcd->regs);
+err_irq:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+       usb_put_hcd(hcd);
+
+       return ret;
+}
+
+static int uhci_hcd_platform_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+/* Make sure the controller is quiescent and that we're not using it
+ * any more.  This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel.  Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_hcd_platform_shutdown(struct platform_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+       uhci_hc_died(hcd_to_uhci(hcd));
+}
+
+static const struct of_device_id platform_uhci_ids[] = {
+       { .compatible = "platform-uhci", },
+       {}
+};
+
+static struct platform_driver uhci_platform_driver = {
+       .probe          = uhci_hcd_platform_probe,
+       .remove         = uhci_hcd_platform_remove,
+       .shutdown       = uhci_hcd_platform_shutdown,
+       .driver = {
+               .name = "platform-uhci",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(platform_uhci_ids),
+       },
+};
index 1e141f755b26dd22836461a28ac0d2f1c9a7bcbd..c3a647816af0b7b690172cbf4e90799b47718dd3 100644 (file)
@@ -238,16 +238,16 @@ static struct hc_driver whc_hc_driver = {
 
 static int whc_probe(struct umc_dev *umc)
 {
-       int ret = -ENOMEM;
+       int ret;
        struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc = NULL;
-       struct whc *whc = NULL;
+       struct wusbhc *wusbhc;
+       struct whc *whc;
        struct device *dev = &umc->dev;
 
        usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
        if (usb_hcd == NULL) {
                dev_err(dev, "unable to create hcd\n");
-               goto error;
+               return -ENOMEM;
        }
 
        usb_hcd->wireless = 1;
index 76083ae9213800cf48ecc1fa2208def7c1cf4542..dc31c425ce0179551b27e2d7a900f1bb7b411ad8 100644 (file)
@@ -436,7 +436,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
        int i;
        int ntds = 0;
        struct whc_std *std = NULL;
-       struct whc_page_list_entry *entry;
+       struct whc_page_list_entry *new_pl_virt;
        dma_addr_t prev_end = 0;
        size_t pl_len;
        int p = 0;
@@ -508,12 +508,15 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
 
                        pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
 
-                       std->pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
-                       if (std->pl_virt == NULL) {
+                       new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
+                       if (new_pl_virt == NULL) {
+                               kfree(std->pl_virt);
+                               std->pl_virt = NULL;
                                return -ENOMEM;
                        }
+                       std->pl_virt = new_pl_virt;
 
-                       for (;p < std->num_pointers; p++, entry++) {
+                       for (;p < std->num_pointers; p++) {
                                std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
                                dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
                        }
index 74bfc868b7ade609dc67cea66195bd499f92b067..630e9e6e06b5a92819005e3c4ea13a949abf336a 100644 (file)
@@ -766,6 +766,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
                        temp = xhci_readl(xhci, port_array[wIndex]);
                        xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp);
+
+                       temp = usb_acpi_power_manageable(hcd->self.root_hub,
+                                       wIndex);
+                       if (temp)
+                               usb_acpi_set_power_state(hcd->self.root_hub,
+                                               wIndex, true);
                        break;
                case USB_PORT_FEAT_RESET:
                        temp = (temp | PORT_RESET);
@@ -865,6 +871,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        xhci_disable_port(hcd, xhci, wIndex,
                                        port_array[wIndex], temp);
                        break;
+               case USB_PORT_FEAT_POWER:
+                       xhci_writel(xhci, temp & ~PORT_POWER,
+                               port_array[wIndex]);
+
+                       temp = usb_acpi_power_manageable(hcd->self.root_hub,
+                                       wIndex);
+                       if (temp)
+                               usb_acpi_set_power_state(hcd->self.root_hub,
+                                               wIndex, false);
+                       break;
                default:
                        goto error;
                }
index 18b231b0c5d373afbec7efde87faed879ca26889..9bfd4ca1153c32cd51d3468608948a31a3a08953 100644 (file)
@@ -94,11 +94,21 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
                xhci->limit_active_eps = 64;
                xhci->quirks |= XHCI_SW_BW_CHECKING;
+               /*
+                * PPT desktop boards DH77EB and DH77DF will power back on after
+                * a few seconds of being shutdown.  The fix for this is to
+                * switch the ports from xHCI to EHCI on shutdown.  We can't use
+                * DMI information to find those particular boards (since each
+                * vendor will change the board name), so we have to key off all
+                * PPT chipsets.
+                */
+               xhci->quirks |= XHCI_SPURIOUS_REBOOT;
        }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
                xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
+               xhci->quirks |= XHCI_TRUST_TX_LENGTH;
        }
        if (pdev->vendor == PCI_VENDOR_ID_VIA)
                xhci->quirks |= XHCI_RESET_ON_RESUME;
index 8275645889da4ce779c08c88ac4ea06473f222e0..643c2f3f3e738e1785447fd2d8c27559e0fb0d24 100644 (file)
@@ -145,29 +145,37 @@ static void next_trb(struct xhci_hcd *xhci,
  */
 static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-       union xhci_trb *next;
        unsigned long long addr;
 
        ring->deq_updates++;
 
-       /* If this is not event ring, there is one more usable TRB */
+       /*
+        * If this is not event ring, and the dequeue pointer
+        * is not on a link TRB, there is one more usable TRB
+        */
        if (ring->type != TYPE_EVENT &&
                        !last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
                ring->num_trbs_free++;
-       next = ++(ring->dequeue);
 
-       /* Update the dequeue pointer further if that was a link TRB or we're at
-        * the end of an event ring segment (which doesn't have link TRBS)
-        */
-       while (last_trb(xhci, ring, ring->deq_seg, next)) {
-               if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci,
-                               ring, ring->deq_seg, next)) {
-                       ring->cycle_state = (ring->cycle_state ? 0 : 1);
+       do {
+               /*
+                * Update the dequeue pointer further if that was a link TRB or
+                * we're at the end of an event ring segment (which doesn't have
+                * link TRBS)
+                */
+               if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) {
+                       if (ring->type == TYPE_EVENT &&
+                                       last_trb_on_last_seg(xhci, ring,
+                                               ring->deq_seg, ring->dequeue)) {
+                               ring->cycle_state = (ring->cycle_state ? 0 : 1);
+                       }
+                       ring->deq_seg = ring->deq_seg->next;
+                       ring->dequeue = ring->deq_seg->trbs;
+               } else {
+                       ring->dequeue++;
                }
-               ring->deq_seg = ring->deq_seg->next;
-               ring->dequeue = ring->deq_seg->trbs;
-               next = ring->dequeue;
-       }
+       } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue));
+
        addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
 }
 
@@ -2073,8 +2081,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
                        trb_comp_code = COMP_SHORT_TX;
                else
-                       xhci_warn(xhci, "WARN Successful completion on short TX: "
-                                       "needs XHCI_TRUST_TX_LENGTH quirk?\n");
+                       xhci_warn_ratelimited(xhci,
+                                       "WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n");
        case COMP_SHORT_TX:
                break;
        case COMP_STOP:
index 7648b2d4b268182b4e9097db1bab61b97b86a0d4..c59d5b5b6c7d227a8005ca520e8b9badad5207b1 100644 (file)
@@ -166,7 +166,7 @@ int xhci_reset(struct xhci_hcd *xhci)
        xhci_writel(xhci, command, &xhci->op_regs->command);
 
        ret = handshake(xhci, &xhci->op_regs->command,
-                       CMD_RESET, 0, 250 * 1000);
+                       CMD_RESET, 0, 10 * 1000 * 1000);
        if (ret)
                return ret;
 
@@ -175,7 +175,8 @@ int xhci_reset(struct xhci_hcd *xhci)
         * xHCI cannot write to any doorbells or operational registers other
         * than status until the "Controller Not Ready" flag is cleared.
         */
-       ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+       ret = handshake(xhci, &xhci->op_regs->status,
+                       STS_CNR, 0, 10 * 1000 * 1000);
 
        for (i = 0; i < 2; ++i) {
                xhci->bus_state[i].port_c_suspend = 0;
@@ -658,6 +659,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
+       if (xhci->quirks && XHCI_SPURIOUS_REBOOT)
+               usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
+
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
        spin_unlock_irq(&xhci->lock);
index 55c0785810c99fb5286e29d39cd4d7ff2b98addb..c713256297acd073e7589f2fdfd936390fb8bbd0 100644 (file)
@@ -1494,6 +1494,7 @@ struct xhci_hcd {
 #define XHCI_TRUST_TX_LENGTH   (1 << 10)
 #define XHCI_LPM_SUPPORT       (1 << 11)
 #define XHCI_INTEL_HOST                (1 << 12)
+#define XHCI_SPURIOUS_REBOOT   (1 << 13)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
@@ -1537,6 +1538,8 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
        dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_warn(xhci, fmt, args...) \
        dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+#define xhci_warn_ratelimited(xhci, fmt, args...) \
+       dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 
 /* TODO: copied from ehci.h - can be refactored? */
 /* xHCI spec says all registers are little endian */
index ff08015b230c8064b81be97e8946b0c8bf91b108..ae794b90766ba627c94712f52a899ba244f95479 100644 (file)
@@ -232,7 +232,7 @@ wraperr:
        return err;
 }
 
-static const struct usb_device_id id_table[] __devinitconst = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) },
        { }                                             /* Terminating entry */
 };
index a2702cbfe804c9629005184f17c78ca16918d247..80894791c02003fb8ee628e8ed722411bb174ee9 100644 (file)
@@ -868,9 +868,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
 
        dbg(2, "%s: enter", __func__);
 
-       if (udev == NULL)
-               dev_info(&interface->dev, "udev is NULL.\n");
-
        /* allocate memory for our device state and initialize it */
 
        dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
index ef0c3f9f0947a8718d5d5362ba9025df84a696fa..09f6856865003ad678c7eb15019577cdda11fa8f 100644 (file)
@@ -8,11 +8,10 @@ config USB_MUSB_HDRC
        tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
        depends on USB && USB_GADGET
        select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
-       select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX)
+       select NOP_USB_XCEIV if (SOC_TI81XX || SOC_AM33XX)
        select TWL4030_USB if MACH_OMAP_3430SDP
        select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
        select USB_OTG_UTILS
-       select USB_GADGET_DUALSPEED
        help
          Say Y here if your system has a dual role high speed USB
          controller based on the Mentor Graphics silicon IP.  Then
@@ -57,7 +56,7 @@ config USB_MUSB_AM35X
 
 config USB_MUSB_DSPS
        tristate "TI DSPS platforms"
-       depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX
+       depends on SOC_TI81XX || SOC_AM33XX
 
 config USB_MUSB_BLACKFIN
        tristate "Blackfin"
index 7a95ab87ac00feaafe788342305cfb1d36255fbc..5d64c5b5ef52377110e5973f08983b1c2ba9830e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <plat/usb.h>
 
index 428e6aa3e78a46a3b917fe6a079434d933caf4e6..b562623a8971f37beb9d47b55a7ab5c20653f996 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <asm/cacheflush.h>
 
index 0f9fcec4e1d3075d8c4e44c4aaa39066bece4f5c..16798c9e6f38553865ee3cad2c167ddbefa9e566 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <mach/da8xx.h>
 #include <mach/usb.h>
index 472c8b42d38b3a2007d3afa74c526b6431b031cf..863a9b6286c3a26f5f4a9e0b81ca4abce8ed3597 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <mach/cputype.h>
 #include <mach/hardware.h>
index 217808d9fbe1991298da67295404d50cd71e593a..c20b8776aafad60b703d3b56132c535fa7eba79c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -479,9 +480,9 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
                ret = -ENODEV;
                goto err0;
        }
-       strcpy((u8 *)res->name, "mc");
        res->parent = NULL;
        resources[1] = *res;
+       resources[1].name = "mc";
 
        /* allocate the child platform device */
        musb = platform_device_alloc("musb-hdrc", -1);
@@ -566,27 +567,28 @@ static int __devinit dsps_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, glue);
 
-       /* create the child platform device for first instances of musb */
-       ret = dsps_create_musb_pdev(glue, 0);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "failed to create child pdev\n");
-               goto err2;
-       }
-
        /* enable the usbss clocks */
        pm_runtime_enable(&pdev->dev);
 
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+               goto err2;
+       }
+
+       /* create the child platform device for first instances of musb */
+       ret = dsps_create_musb_pdev(glue, 0);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to create child pdev\n");
                goto err3;
        }
 
        return 0;
 
 err3:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_put(&pdev->dev);
 err2:
+       pm_runtime_disable(&pdev->dev);
        kfree(glue->wrp);
 err1:
        kfree(glue);
index 1a1bd9cf40c5ce7c1d6f7ef1ac46360d0b6884a4..00f21dfee5d77cd761cb68b24e6493f581fea87e 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/nop-usb-xceiv.h>
 
 #include "musb_core.h"
 
index 13fd1ddf742f2ac3c79db66f1b28c4c18f687fce..d8c8a42bff3eb0bb9187849e8136a6ba358a92cf 100644 (file)
@@ -68,7 +68,7 @@ config TWL4030_USB
 
 config TWL6030_USB
        tristate "TWL6030 USB Transceiver Driver"
-       depends on TWL4030_CORE
+       depends on TWL4030_CORE && OMAP_USB2
        select USB_OTG_UTILS
        help
          Enable this to support the USB OTG transceiver on TWL6030
index 23c798cb2d7f23e9ce83ace89265b576fe816152..c19d1d7173a90790bf9a20cc5c1f5bea533125dc 100644 (file)
@@ -544,9 +544,13 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
  */
 static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 {
-       struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       struct fsl_otg *otg_dev;
+
+       if (!otg)
+               return -ENODEV;
 
-       if (!otg || otg_dev != fsl_otg_dev)
+       otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       if (otg_dev != fsl_otg_dev)
                return -ENODEV;
 
        otg->host = host;
@@ -590,12 +594,15 @@ static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
 static int fsl_otg_set_peripheral(struct usb_otg *otg,
                                        struct usb_gadget *gadget)
 {
-       struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       struct fsl_otg *otg_dev;
 
+       if (!otg)
+               return -ENODEV;
+
+       otg_dev = container_of(otg->phy, struct fsl_otg, phy);
        VDBG("otg_dev 0x%x\n", (int)otg_dev);
        VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
-
-       if (!otg || otg_dev != fsl_otg_dev)
+       if (otg_dev != fsl_otg_dev)
                return -ENODEV;
 
        if (!gadget) {
@@ -660,10 +667,13 @@ static void fsl_otg_event(struct work_struct *work)
 /* B-device start SRP */
 static int fsl_otg_start_srp(struct usb_otg *otg)
 {
-       struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       struct fsl_otg *otg_dev;
+
+       if (!otg || otg->phy->state != OTG_STATE_B_IDLE)
+               return -ENODEV;
 
-       if (!otg || otg_dev != fsl_otg_dev
-           || otg->phy->state != OTG_STATE_B_IDLE)
+       otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       if (otg_dev != fsl_otg_dev)
                return -ENODEV;
 
        otg_dev->fsm.b_bus_req = 1;
@@ -675,9 +685,13 @@ static int fsl_otg_start_srp(struct usb_otg *otg)
 /* A_host suspend will call this function to start hnp */
 static int fsl_otg_start_hnp(struct usb_otg *otg)
 {
-       struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       struct fsl_otg *otg_dev;
+
+       if (!otg)
+               return -ENODEV;
 
-       if (!otg || otg_dev != fsl_otg_dev)
+       otg_dev = container_of(otg->phy, struct fsl_otg, phy);
+       if (otg_dev != fsl_otg_dev)
                return -ENODEV;
 
        DBG("start_hnp...n");
index c1a67cb8e24483272a78834f934e112ccbac7d87..88db976647cf35dc1bdb014aef4ba185bc5d9008 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/workqueue.h>
 
 #define DRIVER_NAME "mxs_phy"
 
 #define BM_USBPHY_CTRL_ENUTMILEVEL2            BIT(14)
 #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT      BIT(1)
 
+/*
+ * Amount of delay in miliseconds to safely enable ENHOSTDISCONDETECT bit
+ * so that connection and reset processing can be completed for the root hub.
+ */
+#define MXY_PHY_ENHOSTDISCONDETECT_DELAY       250
+
 struct mxs_phy {
        struct usb_phy phy;
        struct clk *clk;
+       struct delayed_work enhostdiscondetect_work;
 };
 
 #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
@@ -62,6 +70,7 @@ static int mxs_phy_init(struct usb_phy *phy)
 
        clk_prepare_enable(mxs_phy->clk);
        mxs_phy_hw_init(mxs_phy);
+       INIT_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work, NULL);
 
        return 0;
 }
@@ -76,13 +85,34 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
        clk_disable_unprepare(mxs_phy->clk);
 }
 
+static void mxs_phy_enhostdiscondetect_delay(struct work_struct *ws)
+{
+       struct mxs_phy *mxs_phy = container_of(ws, struct mxs_phy,
+                                               enhostdiscondetect_work.work);
+
+       /* Enable HOSTDISCONDETECT after delay. */
+       dev_dbg(mxs_phy->phy.dev, "Setting ENHOSTDISCONDETECT\n");
+       writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+                               mxs_phy->phy.io_priv + HW_USBPHY_CTRL_SET);
+}
+
 static int mxs_phy_on_connect(struct usb_phy *phy, int port)
 {
+       struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
        dev_dbg(phy->dev, "Connect on port %d\n", port);
 
-       mxs_phy_hw_init(to_mxs_phy(phy));
-       writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
-                       phy->io_priv + HW_USBPHY_CTRL_SET);
+       mxs_phy_hw_init(mxs_phy);
+
+       /*
+        * Delay enabling ENHOSTDISCONDETECT so that connection and
+        * reset processing can be completed for the root hub.
+        */
+       dev_dbg(phy->dev, "Delaying setting ENHOSTDISCONDETECT\n");
+       PREPARE_DELAYED_WORK(&mxs_phy->enhostdiscondetect_work,
+                       mxs_phy_enhostdiscondetect_delay);
+       schedule_delayed_work(&mxs_phy->enhostdiscondetect_work,
+                       msecs_to_jiffies(MXY_PHY_ENHOSTDISCONDETECT_DELAY));
 
        return 0;
 }
@@ -91,6 +121,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy, int port)
 {
        dev_dbg(phy->dev, "Disconnect on port %d\n", port);
 
+       /* No need to delay before clearing ENHOSTDISCONDETECT. */
+       dev_dbg(phy->dev, "Clearing ENHOSTDISCONDETECT\n");
        writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
                        phy->io_priv + HW_USBPHY_CTRL_CLR);
 
index 803f958f413398400346977ae76c417c64302206..e52e35e7adaf9bea0b85a3b6ca3b1790a1c4bda1 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/nop-usb-xceiv.h>
 #include <linux/slab.h>
 
 struct nop_usb_xceiv {
@@ -94,7 +95,9 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
 
 static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
 {
+       struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
        struct nop_usb_xceiv    *nop;
+       enum usb_phy_type       type = USB_PHY_TYPE_USB2;
        int err;
 
        nop = kzalloc(sizeof *nop, GFP_KERNEL);
@@ -107,6 +110,9 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       if (pdata)
+               type = pdata->type;
+
        nop->dev                = &pdev->dev;
        nop->phy.dev            = nop->dev;
        nop->phy.label          = "nop-xceiv";
@@ -117,7 +123,7 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
        nop->phy.otg->set_host          = nop_set_host;
        nop->phy.otg->set_peripheral    = nop_set_peripheral;
 
-       err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2);
+       err = usb_add_phy(&nop->phy, type);
        if (err) {
                dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
                        err);
index 1bf60a22595c706c2213720b1514391002e6284b..a30c04115115046e9c1c43e4e1bbced59b73e441 100644 (file)
@@ -159,7 +159,7 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
        unsigned long   flags;
        struct usb_phy  *phy;
 
-       if (x && x->type != USB_PHY_TYPE_UNDEFINED) {
+       if (x->type != USB_PHY_TYPE_UNDEFINED) {
                dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
                return -EINVAL;
        }
index 523cad5bfea947deca4d288a338cc3acc4c9c3a1..f0d2e7530cfea4ecb01bdec31411de4afd1e7097 100644 (file)
@@ -585,23 +585,28 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
        struct twl4030_usb      *twl;
        int                     status, err;
        struct usb_otg          *otg;
-
-       if (!pdata) {
-               dev_dbg(&pdev->dev, "platform_data not available\n");
-               return -EINVAL;
-       }
+       struct device_node      *np = pdev->dev.of_node;
 
        twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
        if (!twl)
                return -ENOMEM;
 
+       if (np)
+               of_property_read_u32(np, "usb_mode",
+                               (enum twl4030_usb_mode *)&twl->usb_mode);
+       else if (pdata)
+               twl->usb_mode = pdata->usb_mode;
+       else {
+               dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
+               return -EINVAL;
+       }
+
        otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
        if (!otg)
                return -ENOMEM;
 
        twl->dev                = &pdev->dev;
        twl->irq                = platform_get_irq(pdev, 0);
-       twl->usb_mode           = pdata->usb_mode;
        twl->vbus_supplied      = false;
        twl->asleep             = 1;
        twl->linkstat           = OMAP_MUSB_UNKNOWN;
@@ -690,12 +695,21 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_usb_id_table[] = {
+       { .compatible = "ti,twl4030-usb" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);
+#endif
+
 static struct platform_driver twl4030_usb_driver = {
        .probe          = twl4030_usb_probe,
        .remove         = __exit_p(twl4030_usb_remove),
        .driver         = {
                .name   = "twl4030_usb",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(twl4030_usb_id_table),
        },
 };
 
index 6907d8df7a2715b3c8fc06e290f593cb94f737bb..fcadef7864f12a11a36dbab5967315669a09c3b3 100644 (file)
@@ -25,8 +25,9 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/usb/otg.h>
 #include <linux/usb/musb-omap.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/omap_usb.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
@@ -87,7 +88,7 @@
 #define        VBUS_DET                        BIT(2)
 
 struct twl6030_usb {
-       struct usb_phy          phy;
+       struct phy_companion    comparator;
        struct device           *dev;
 
        /* for vbus reporting with irqs disabled */
@@ -104,10 +105,10 @@ struct twl6030_usb {
        u8                      asleep;
        bool                    irq_enabled;
        bool                    vbus_enable;
-       unsigned long           features;
+       const char              *regulator;
 };
 
-#define phy_to_twl(x)          container_of((x), struct twl6030_usb, phy)
+#define        comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
 
 /*-------------------------------------------------------------------------*/
 
@@ -137,50 +138,9 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
        return ret;
 }
 
-static int twl6030_phy_init(struct usb_phy *x)
+static int twl6030_start_srp(struct phy_companion *comparator)
 {
-       struct twl6030_usb *twl;
-       struct device *dev;
-       struct twl4030_usb_data *pdata;
-
-       twl = phy_to_twl(x);
-       dev  = twl->dev;
-       pdata = dev->platform_data;
-
-       if (twl->linkstat == OMAP_MUSB_ID_GROUND)
-               pdata->phy_power(twl->dev, 1, 1);
-       else
-               pdata->phy_power(twl->dev, 0, 1);
-
-       return 0;
-}
-
-static void twl6030_phy_shutdown(struct usb_phy *x)
-{
-       struct twl6030_usb *twl;
-       struct device *dev;
-       struct twl4030_usb_data *pdata;
-
-       twl = phy_to_twl(x);
-       dev  = twl->dev;
-       pdata = dev->platform_data;
-       pdata->phy_power(twl->dev, 0, 0);
-}
-
-static int twl6030_phy_suspend(struct usb_phy *x, int suspend)
-{
-       struct twl6030_usb *twl = phy_to_twl(x);
-       struct device *dev = twl->dev;
-       struct twl4030_usb_data *pdata = dev->platform_data;
-
-       pdata->phy_suspend(dev, suspend);
-
-       return 0;
-}
-
-static int twl6030_start_srp(struct usb_otg *otg)
-{
-       struct twl6030_usb *twl = phy_to_twl(otg->phy);
+       struct twl6030_usb *twl = comparator_to_twl(comparator);
 
        twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
        twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
@@ -193,13 +153,6 @@ static int twl6030_start_srp(struct usb_otg *otg)
 
 static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
 {
-       char *regulator_name;
-
-       if (twl->features & TWL6025_SUBCLASS)
-               regulator_name = "ldousb";
-       else
-               regulator_name = "vusb";
-
        /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
        twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
 
@@ -209,7 +162,7 @@ static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
        /* Program MISC2 register and set bit VUSB_IN_VBAT */
        twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
 
-       twl->usb3v3 = regulator_get(twl->dev, regulator_name);
+       twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
        if (IS_ERR(twl->usb3v3))
                return -ENODEV;
 
@@ -313,23 +266,8 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
        return IRQ_HANDLED;
 }
 
-static int twl6030_set_peripheral(struct usb_otg *otg,
-               struct usb_gadget *gadget)
-{
-       if (!otg)
-               return -ENODEV;
-
-       otg->gadget = gadget;
-       if (!gadget)
-               otg->phy->state = OTG_STATE_UNDEFINED;
-
-       return 0;
-}
-
-static int twl6030_enable_irq(struct usb_phy *x)
+static int twl6030_enable_irq(struct twl6030_usb *twl)
 {
-       struct twl6030_usb *twl = phy_to_twl(x);
-
        twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
        twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
        twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
@@ -362,9 +300,9 @@ static void otg_set_vbus_work(struct work_struct *data)
                                                        CHARGERUSB_CTRL1);
 }
 
-static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
+static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
 {
-       struct twl6030_usb *twl = phy_to_twl(otg->phy);
+       struct twl6030_usb *twl = comparator_to_twl(comparator);
 
        twl->vbus_enable = enabled;
        schedule_work(&twl->set_vbus_work);
@@ -372,52 +310,44 @@ static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
        return 0;
 }
 
-static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
-       if (!otg)
-               return -ENODEV;
-
-       otg->host = host;
-       if (!host)
-               otg->phy->state = OTG_STATE_UNDEFINED;
-       return 0;
-}
-
 static int __devinit twl6030_usb_probe(struct platform_device *pdev)
 {
+       u32 ret;
        struct twl6030_usb      *twl;
        int                     status, err;
-       struct twl4030_usb_data *pdata;
-       struct usb_otg          *otg;
-       struct device *dev = &pdev->dev;
-       pdata = dev->platform_data;
+       struct device_node      *np = pdev->dev.of_node;
+       struct device           *dev = &pdev->dev;
+       struct twl4030_usb_data *pdata = dev->platform_data;
 
        twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
        if (!twl)
                return -ENOMEM;
 
-       otg = devm_kzalloc(dev, sizeof *otg, GFP_KERNEL);
-       if (!otg)
-               return -ENOMEM;
-
        twl->dev                = &pdev->dev;
        twl->irq1               = platform_get_irq(pdev, 0);
        twl->irq2               = platform_get_irq(pdev, 1);
-       twl->features           = pdata->features;
        twl->linkstat           = OMAP_MUSB_UNKNOWN;
 
-       twl->phy.dev            = twl->dev;
-       twl->phy.label          = "twl6030";
-       twl->phy.otg            = otg;
-       twl->phy.init           = twl6030_phy_init;
-       twl->phy.shutdown       = twl6030_phy_shutdown;
-       twl->phy.set_suspend    = twl6030_phy_suspend;
+       twl->comparator.set_vbus        = twl6030_set_vbus;
+       twl->comparator.start_srp       = twl6030_start_srp;
+
+       ret = omap_usb2_set_comparator(&twl->comparator);
+       if (ret == -ENODEV) {
+               dev_info(&pdev->dev, "phy not ready, deferring probe");
+               return -EPROBE_DEFER;
+       }
 
-       otg->phy                = &twl->phy;
-       otg->set_host           = twl6030_set_host;
-       otg->set_peripheral     = twl6030_set_peripheral;
-       otg->set_vbus           = twl6030_set_vbus;
-       otg->start_srp          = twl6030_start_srp;
+       if (np) {
+               twl->regulator = "usb";
+       } else if (pdata) {
+               if (pdata->features & TWL6025_SUBCLASS)
+                       twl->regulator = "ldousb";
+               else
+                       twl->regulator = "vusb";
+       } else {
+               dev_err(&pdev->dev, "twl6030 initialized without pdata\n");
+               return -EINVAL;
+       }
 
        /* init spinlock for workqueue */
        spin_lock_init(&twl->lock);
@@ -427,7 +357,6 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "ldo init failed\n");
                return err;
        }
-       usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
 
        platform_set_drvdata(pdev, twl);
        if (device_create_file(&pdev->dev, &dev_attr_vbus))
@@ -458,9 +387,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
        }
 
        twl->asleep = 0;
-       pdata->phy_init(dev);
-       twl6030_phy_suspend(&twl->phy, 0);
-       twl6030_enable_irq(&twl->phy);
+       twl6030_enable_irq(twl);
        dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
 
        return 0;
@@ -470,10 +397,6 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
 {
        struct twl6030_usb *twl = platform_get_drvdata(pdev);
 
-       struct twl4030_usb_data *pdata;
-       struct device *dev = &pdev->dev;
-       pdata = dev->platform_data;
-
        twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
                REG_INT_MSK_LINE_C);
        twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
@@ -481,19 +404,27 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
        free_irq(twl->irq1, twl);
        free_irq(twl->irq2, twl);
        regulator_put(twl->usb3v3);
-       pdata->phy_exit(twl->dev);
        device_remove_file(twl->dev, &dev_attr_vbus);
        cancel_work_sync(&twl->set_vbus_work);
 
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id twl6030_usb_id_table[] = {
+       { .compatible = "ti,twl6030-usb" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
+#endif
+
 static struct platform_driver twl6030_usb_driver = {
        .probe          = twl6030_usb_probe,
        .remove         = __exit_p(twl6030_usb_remove),
        .driver         = {
                .name   = "twl6030_usb",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(twl6030_usb_id_table),
        },
 };
 
index e7cf84f0751a2a6f1d8ea27614c59abf8a7303fa..63c339b3e676f2f439db0178c9debc627d8aa5ac 100644 (file)
@@ -4,6 +4,15 @@
 comment "USB Physical Layer drivers"
        depends on USB || USB_GADGET
 
+config OMAP_USB2
+       tristate "OMAP USB2 PHY Driver"
+       select USB_OTG_UTILS
+       help
+         Enable this to support the transceiver that is part of SOC. This
+         driver takes care of all the PHY functionality apart from comparator.
+         The USB OTG controller communicates with the comparator using this
+         driver.
+
 config USB_ISP1301
        tristate "NXP ISP1301 USB transceiver support"
        depends on USB || USB_GADGET
@@ -15,3 +24,11 @@ config USB_ISP1301
 
          To compile this driver as a module, choose M here: the
          module will be called isp1301.
+
+config MV_U3D_PHY
+       bool "Marvell USB 3.0 PHY controller Driver"
+       depends on USB_MV_U3D
+       select USB_OTG_UTILS
+       help
+         Enable this to support Marvell USB 3.0 phy controller for Marvell
+         SoC.
index eca095b1a890f0b896cec70c70ecbe2b39996e98..b069f29f122590a5b76dccb96acbe38d06250668 100644 (file)
@@ -4,4 +4,7 @@
 
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
+obj-$(CONFIG_OMAP_USB2)                        += omap-usb2.o
 obj-$(CONFIG_USB_ISP1301)              += isp1301.o
+obj-$(CONFIG_MV_U3D_PHY)               += mv_u3d_phy.o
+obj-$(CONFIG_USB_EHCI_TEGRA)   += tegra_usb_phy.o
index b19f4932a0371675315b9495413df4a535102978..18dbf7e37607262059b7a1bb9a8f5b4e9ef6e86f 100644 (file)
 
 #define DRV_NAME               "isp1301"
 
-#define ISP1301_I2C_ADDR       0x2C
-
-static const unsigned short normal_i2c[] = {
-       ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
-};
-
 static const struct i2c_device_id isp1301_id[] = {
        { "isp1301", 0 },
        { }
diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/mv_u3d_phy.c
new file mode 100644 (file)
index 0000000..9f1c5d3
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/mv_usb.h>
+
+#include "mv_u3d_phy.h"
+
+/*
+ * struct mv_u3d_phy - transceiver driver state
+ * @phy: transceiver structure
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @base: usb phy register memory base
+ */
+struct mv_u3d_phy {
+       struct usb_phy  phy;
+       struct mv_usb_platform_data *plat;
+       struct device   *dev;
+       struct clk      *clk;
+       void __iomem    *base;
+};
+
+static u32 mv_u3d_phy_read(void __iomem *base, u32 reg)
+{
+       void __iomem *addr, *data;
+
+       addr = base;
+       data = base + 0x4;
+
+       writel_relaxed(reg, addr);
+       return readl_relaxed(data);
+}
+
+static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value)
+{
+       void __iomem *addr, *data;
+       u32 tmp;
+
+       addr = base;
+       data = base + 0x4;
+
+       writel_relaxed(reg, addr);
+       tmp = readl_relaxed(data);
+       tmp |= value;
+       writel_relaxed(tmp, data);
+}
+
+static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value)
+{
+       void __iomem *addr, *data;
+       u32 tmp;
+
+       addr = base;
+       data = base + 0x4;
+
+       writel_relaxed(reg, addr);
+       tmp = readl_relaxed(data);
+       tmp &= ~value;
+       writel_relaxed(tmp, data);
+}
+
+static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value)
+{
+       void __iomem *addr, *data;
+
+       addr = base;
+       data = base + 0x4;
+
+       writel_relaxed(reg, addr);
+       writel_relaxed(value, data);
+}
+
+void mv_u3d_phy_shutdown(struct usb_phy *phy)
+{
+       struct mv_u3d_phy *mv_u3d_phy;
+       void __iomem *base;
+       u32 val;
+
+       mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
+       base = mv_u3d_phy->base;
+
+       /* Power down Reference Analog current, bit 15
+        * Power down PLL, bit 14
+        * Power down Receiver, bit 13
+        * Power down Transmitter, bit 12
+        * of USB3_POWER_PLL_CONTROL register
+        */
+       val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+       val &= ~(USB3_POWER_PLL_CONTROL_PU);
+       mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+
+       if (mv_u3d_phy->clk)
+               clk_disable(mv_u3d_phy->clk);
+}
+
+static int mv_u3d_phy_init(struct usb_phy *phy)
+{
+       struct mv_u3d_phy *mv_u3d_phy;
+       void __iomem *base;
+       u32 val, count;
+
+       /* enable usb3 phy */
+       mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy);
+
+       if (mv_u3d_phy->clk)
+               clk_enable(mv_u3d_phy->clk);
+
+       base = mv_u3d_phy->base;
+
+       val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+       val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK);
+       val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT;
+       mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+       udelay(100);
+
+       mv_u3d_phy_write(base, USB3_RESET_CONTROL,
+                       USB3_RESET_CONTROL_RESET_PIPE);
+       udelay(100);
+
+       mv_u3d_phy_write(base, USB3_RESET_CONTROL,
+                       USB3_RESET_CONTROL_RESET_PIPE
+                       | USB3_RESET_CONTROL_RESET_PHY);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL);
+       val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK
+               | USB3_POWER_PLL_CONTROL_PHY_MODE_MASK);
+       val |=  (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT)
+               | (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT);
+       mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val);
+       udelay(100);
+
+       mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL,
+               USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE);
+       val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK
+               | USB3_SQUELCH_FFE_FFE_RES_SEL_MASK
+               | USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK);
+       val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT)
+               | (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT)
+               | (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT));
+       mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_GEN1_SET0);
+       val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK;
+       val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT;
+       mv_u3d_phy_write(base, USB3_GEN1_SET0, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_GEN2_SET0);
+       val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK
+               | USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK
+               | USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK);
+       val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT)
+               | (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT)
+               | (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT)
+               | (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT));
+       mv_u3d_phy_write(base, USB3_GEN2_SET0, val);
+       udelay(100);
+
+       mv_u3d_phy_read(base, USB3_TX_EMPPH);
+       val &= ~(USB3_TX_EMPPH_AMP_MASK
+               | USB3_TX_EMPPH_EN_MASK
+               | USB3_TX_EMPPH_AMP_FORCE_MASK
+               | USB3_TX_EMPPH_PAR1_MASK
+               | USB3_TX_EMPPH_PAR2_MASK);
+       val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT)
+               | (1 << USB3_TX_EMPPH_EN_SHIFT)
+               | (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT)
+               | (0x1C << USB3_TX_EMPPH_PAR1_SHIFT)
+               | (1 << USB3_TX_EMPPH_PAR2_SHIFT));
+
+       mv_u3d_phy_write(base, USB3_TX_EMPPH, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_GEN2_SET1);
+       val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK
+               | USB3_GEN2_SET1_G2_RX_SELMUPF_MASK
+               | USB3_GEN2_SET1_G2_RX_SELMUFI_MASK
+               | USB3_GEN2_SET1_G2_RX_SELMUFF_MASK);
+       val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT)
+               | (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT)
+               | (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT)
+               | (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT));
+       mv_u3d_phy_write(base, USB3_GEN2_SET1, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN);
+       val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK;
+       val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT;
+       mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC);
+       val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK;
+       val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT;
+       mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL);
+       val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK;
+       val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT;
+       mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE);
+       val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK
+               | USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK
+               | USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK);
+       val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT)
+               | (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT));
+       mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val);
+       udelay(100);
+
+       val = mv_u3d_phy_read(base, USB3_TXDETRX);
+       val &= ~(USB3_TXDETRX_VTHSEL_MASK);
+       val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT;
+       mv_u3d_phy_write(base, USB3_TXDETRX, val);
+       udelay(100);
+
+       dev_dbg(mv_u3d_phy->dev, "start calibration\n");
+
+calstart:
+       /* Perform Manual Calibration */
+       mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL,
+               1 << USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT);
+
+       mdelay(1);
+
+       count = 0;
+       while (1) {
+               val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL);
+               if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT))
+                       break;
+               else if (count > 50) {
+                       dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n");
+                       goto calstart;
+               }
+               count++;
+               mdelay(1);
+       }
+
+       /* active PIPE interface */
+       mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL,
+               1 << USB3_PIPE_SM_CTRL_PHY_INIT_DONE);
+
+       return 0;
+}
+
+static int __devinit mv_u3d_phy_probe(struct platform_device *pdev)
+{
+       struct mv_u3d_phy *mv_u3d_phy;
+       struct mv_usb_platform_data *pdata;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       void __iomem    *phy_base;
+       int     ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "missing mem resource\n");
+               return -ENODEV;
+       }
+
+       phy_base = devm_request_and_ioremap(dev, res);
+       if (!phy_base) {
+               dev_err(dev, "%s: register mapping failed\n", __func__);
+               return -ENXIO;
+       }
+
+       mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL);
+       if (!mv_u3d_phy)
+               return -ENOMEM;
+
+       mv_u3d_phy->dev                 = &pdev->dev;
+       mv_u3d_phy->plat                = pdata;
+       mv_u3d_phy->base                = phy_base;
+       mv_u3d_phy->phy.dev             = mv_u3d_phy->dev;
+       mv_u3d_phy->phy.label           = "mv-u3d-phy";
+       mv_u3d_phy->phy.init            = mv_u3d_phy_init;
+       mv_u3d_phy->phy.shutdown        = mv_u3d_phy_shutdown;
+
+       ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3);
+       if (ret)
+               goto err;
+
+       if (!mv_u3d_phy->clk)
+               mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy");
+
+       platform_set_drvdata(pdev, mv_u3d_phy);
+
+       dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n");
+err:
+       return ret;
+}
+
+static int __exit mv_u3d_phy_remove(struct platform_device *pdev)
+{
+       struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev);
+
+       usb_remove_phy(&mv_u3d_phy->phy);
+
+       if (mv_u3d_phy->clk) {
+               clk_put(mv_u3d_phy->clk);
+               mv_u3d_phy->clk = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver mv_u3d_phy_driver = {
+       .probe          = mv_u3d_phy_probe,
+       .remove         = __devexit_p(mv_u3d_phy_remove),
+       .driver         = {
+               .name   = "mv-u3d-phy",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(mv_u3d_phy_driver);
+MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller");
+MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mv-u3d-phy");
diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/mv_u3d_phy.h
new file mode 100644 (file)
index 0000000..2a658cb
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#ifndef __MV_U3D_PHY_H
+#define __MV_U3D_PHY_H
+
+#define USB3_POWER_PLL_CONTROL         0x1
+#define USB3_KVCO_CALI_CONTROL         0x2
+#define USB3_IMPEDANCE_CALI_CTRL       0x3
+#define USB3_IMPEDANCE_TX_SSC          0x4
+#define USB3_SQUELCH_FFE               0x6
+#define USB3_GEN1_SET0                 0xD
+#define USB3_GEN2_SET0                 0xF
+#define USB3_GEN2_SET1                 0x10
+#define USB3_DIGITAL_LOOPBACK_EN       0x23
+#define USB3_PHY_ISOLATION_MODE                0x26
+#define USB3_TXDETRX                   0x48
+#define USB3_TX_EMPPH                  0x5E
+#define USB3_RESET_CONTROL             0x90
+#define USB3_PIPE_SM_CTRL              0x91
+
+#define USB3_RESET_CONTROL_RESET_PIPE                  0x1
+#define USB3_RESET_CONTROL_RESET_PHY                   0x2
+
+#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK       (0x1F << 0)
+#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT      0
+#define USB3_PLL_25MHZ                                 0x2
+#define USB3_PLL_26MHZ                                 0x5
+#define USB3_POWER_PLL_CONTROL_PHY_MODE_MASK           (0x7 << 5)
+#define USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT          5
+#define USB3_POWER_PLL_CONTROL_PU_MASK                 (0xF << 12)
+#define USB3_POWER_PLL_CONTROL_PU_SHIFT                        12
+#define USB3_POWER_PLL_CONTROL_PU                      (0xF << 12)
+
+#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK   (0x1 << 12)
+#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_SHIFT  12
+#define USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT          14
+#define USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT         15
+
+#define USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK              0xF
+#define USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT             0
+#define USB3_SQUELCH_FFE_FFE_RES_SEL_MASK              (0x7 << 4)
+#define USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT             4
+#define USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK             (0x1F << 8)
+#define USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT            8
+
+#define USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK         (0x1 << 15)
+#define USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT             11
+
+#define USB3_GEN2_SET0_G2_TX_AMP_MASK                  (0x1F << 1)
+#define USB3_GEN2_SET0_G2_TX_AMP_SHIFT                 1
+#define USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT             6
+#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK             (0xF << 7)
+#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT            7
+#define USB3_GEN2_SET0_G2_TX_EMPH_EN_MASK              (0x1 << 11)
+#define USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT             11
+#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK         (0x1 << 15)
+#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_SHIFT                15
+
+#define USB3_GEN2_SET1_G2_RX_SELMUPI_MASK              (0x7 << 0)
+#define USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT             0
+#define USB3_GEN2_SET1_G2_RX_SELMUPF_MASK              (0x7 << 3)
+#define USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT             3
+#define USB3_GEN2_SET1_G2_RX_SELMUFI_MASK              (0x3 << 6)
+#define USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT             6
+#define USB3_GEN2_SET1_G2_RX_SELMUFF_MASK              (0x3 << 8)
+#define USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT             8
+
+#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK         (0x3 << 10)
+#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT                10
+
+#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK      (0x7 << 12)
+#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT     12
+
+#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK             (0x3F << 0)
+#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT            0
+
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK                0xF
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT       0
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK                (0xF << 4)
+#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT       4
+#define USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK       (0x1 << 8)
+
+#define USB3_TXDETRX_VTHSEL_MASK                       (0x3 << 4)
+#define USB3_TXDETRX_VTHSEL_SHIFT                      4
+
+#define USB3_TX_EMPPH_AMP_MASK                         (0xF << 0)
+#define USB3_TX_EMPPH_AMP_SHIFT                                0
+#define USB3_TX_EMPPH_EN_MASK                          (0x1 << 6)
+#define USB3_TX_EMPPH_EN_SHIFT                         6
+#define USB3_TX_EMPPH_AMP_FORCE_MASK                   (0x1 << 7)
+#define USB3_TX_EMPPH_AMP_FORCE_SHIFT                  7
+#define USB3_TX_EMPPH_PAR1_MASK                                (0x1F << 8)
+#define USB3_TX_EMPPH_PAR1_SHIFT                       8
+#define USB3_TX_EMPPH_PAR2_MASK                                (0x1 << 13)
+#define USB3_TX_EMPPH_PAR2_SHIFT                       13
+
+#define USB3_PIPE_SM_CTRL_PHY_INIT_DONE                        15
+
+#endif /* __MV_U3D_PHY_H */
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c
new file mode 100644 (file)
index 0000000..15ab3d6
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * omap-usb2.c - USB PHY, talking to musb controller in OMAP.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/usb/omap_usb.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+
+/**
+ * omap_usb2_set_comparator - links the comparator present in the sytem with
+ *     this phy
+ * @comparator - the companion phy(comparator) for this phy
+ *
+ * The phy companion driver should call this API passing the phy_companion
+ * filled with set_vbus and start_srp to be used by usb phy.
+ *
+ * For use by phy companion driver
+ */
+int omap_usb2_set_comparator(struct phy_companion *comparator)
+{
+       struct omap_usb *phy;
+       struct usb_phy  *x = usb_get_phy(USB_PHY_TYPE_USB2);
+
+       if (IS_ERR(x))
+               return -ENODEV;
+
+       phy = phy_to_omapusb(x);
+       phy->comparator = comparator;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
+
+/**
+ * omap_usb_phy_power - power on/off the phy using control module reg
+ * @phy: struct omap_usb *
+ * @on: 0 or 1, based on powering on or off the PHY
+ *
+ * XXX: Remove this function once control module driver gets merged
+ */
+static void omap_usb_phy_power(struct omap_usb *phy, int on)
+{
+       u32 val;
+
+       if (on) {
+               val = readl(phy->control_dev);
+               if (val & PHY_PD) {
+                       writel(~PHY_PD, phy->control_dev);
+                       /* XXX: add proper documentation for this delay */
+                       mdelay(200);
+               }
+       } else {
+               writel(PHY_PD, phy->control_dev);
+       }
+}
+
+static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
+{
+       struct omap_usb *phy = phy_to_omapusb(otg->phy);
+
+       if (!phy->comparator)
+               return -ENODEV;
+
+       return phy->comparator->set_vbus(phy->comparator, enabled);
+}
+
+static int omap_usb_start_srp(struct usb_otg *otg)
+{
+       struct omap_usb *phy = phy_to_omapusb(otg->phy);
+
+       if (!phy->comparator)
+               return -ENODEV;
+
+       return phy->comparator->start_srp(phy->comparator);
+}
+
+static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct usb_phy  *phy = otg->phy;
+
+       otg->host = host;
+       if (!host)
+               phy->state = OTG_STATE_UNDEFINED;
+
+       return 0;
+}
+
+static int omap_usb_set_peripheral(struct usb_otg *otg,
+               struct usb_gadget *gadget)
+{
+       struct usb_phy  *phy = otg->phy;
+
+       otg->gadget = gadget;
+       if (!gadget)
+               phy->state = OTG_STATE_UNDEFINED;
+
+       return 0;
+}
+
+static int omap_usb2_suspend(struct usb_phy *x, int suspend)
+{
+       u32 ret;
+       struct omap_usb *phy = phy_to_omapusb(x);
+
+       if (suspend && !phy->is_suspended) {
+               omap_usb_phy_power(phy, 0);
+               pm_runtime_put_sync(phy->dev);
+               phy->is_suspended = 1;
+       } else if (!suspend && phy->is_suspended) {
+               ret = pm_runtime_get_sync(phy->dev);
+               if (ret < 0) {
+                       dev_err(phy->dev, "get_sync failed with err %d\n",
+                                                                       ret);
+                       return ret;
+               }
+               omap_usb_phy_power(phy, 1);
+               phy->is_suspended = 0;
+       }
+
+       return 0;
+}
+
+static int __devinit omap_usb2_probe(struct platform_device *pdev)
+{
+       struct omap_usb                 *phy;
+       struct usb_otg                  *otg;
+       struct resource                 *res;
+
+       phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+       if (!phy) {
+               dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
+               return -ENOMEM;
+       }
+
+       otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+       if (!otg) {
+               dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n");
+               return -ENOMEM;
+       }
+
+       phy->dev                = &pdev->dev;
+
+       phy->phy.dev            = phy->dev;
+       phy->phy.label          = "omap-usb2";
+       phy->phy.set_suspend    = omap_usb2_suspend;
+       phy->phy.otg            = otg;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+       phy->control_dev = devm_request_and_ioremap(&pdev->dev, res);
+       if (phy->control_dev == NULL) {
+               dev_err(&pdev->dev, "Failed to obtain io memory\n");
+               return -ENXIO;
+       }
+
+       phy->is_suspended       = 1;
+       omap_usb_phy_power(phy, 0);
+
+       otg->set_host           = omap_usb_set_host;
+       otg->set_peripheral     = omap_usb_set_peripheral;
+       otg->set_vbus           = omap_usb_set_vbus;
+       otg->start_srp          = omap_usb_start_srp;
+       otg->phy                = &phy->phy;
+
+       phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
+       if (IS_ERR(phy->wkupclk)) {
+               dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
+               return PTR_ERR(phy->wkupclk);
+       }
+       clk_prepare(phy->wkupclk);
+
+       usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2);
+
+       platform_set_drvdata(pdev, phy);
+
+       pm_runtime_enable(phy->dev);
+
+       return 0;
+}
+
+static int __devexit omap_usb2_remove(struct platform_device *pdev)
+{
+       struct omap_usb *phy = platform_get_drvdata(pdev);
+
+       clk_unprepare(phy->wkupclk);
+       usb_remove_phy(&phy->phy);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int omap_usb2_runtime_suspend(struct device *dev)
+{
+       struct platform_device  *pdev = to_platform_device(dev);
+       struct omap_usb *phy = platform_get_drvdata(pdev);
+
+       clk_disable(phy->wkupclk);
+
+       return 0;
+}
+
+static int omap_usb2_runtime_resume(struct device *dev)
+{
+       u32 ret = 0;
+       struct platform_device  *pdev = to_platform_device(dev);
+       struct omap_usb *phy = platform_get_drvdata(pdev);
+
+       ret = clk_enable(phy->wkupclk);
+       if (ret < 0)
+               dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
+
+       return ret;
+}
+
+static const struct dev_pm_ops omap_usb2_pm_ops = {
+       SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume,
+               NULL)
+};
+
+#define DEV_PM_OPS     (&omap_usb2_pm_ops)
+#else
+#define DEV_PM_OPS     NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id omap_usb2_id_table[] = {
+       { .compatible = "ti,omap-usb2" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
+static struct platform_driver omap_usb2_driver = {
+       .probe          = omap_usb2_probe,
+       .remove         = __devexit_p(omap_usb2_remove),
+       .driver         = {
+               .name   = "omap-usb2",
+               .owner  = THIS_MODULE,
+               .pm     = DEV_PM_OPS,
+               .of_match_table = of_match_ptr(omap_usb2_id_table),
+       },
+};
+
+module_platform_driver(omap_usb2_driver);
+
+MODULE_ALIAS("platform: omap_usb2");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("OMAP USB2 phy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c
new file mode 100644 (file)
index 0000000..4739903
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *     Erik Gilling <konkers@google.com>
+ *     Benoit Goby <benoit@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/resource.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <asm/mach-types.h>
+#include <mach/gpio-tegra.h>
+#include <linux/usb/tegra_usb_phy.h>
+#include <mach/iomap.h>
+
+#define ULPI_VIEWPORT          0x170
+
+#define USB_PORTSC1            0x184
+#define   USB_PORTSC1_PTS(x)   (((x) & 0x3) << 30)
+#define   USB_PORTSC1_PSPD(x)  (((x) & 0x3) << 26)
+#define   USB_PORTSC1_PHCD     (1 << 23)
+#define   USB_PORTSC1_WKOC     (1 << 22)
+#define   USB_PORTSC1_WKDS     (1 << 21)
+#define   USB_PORTSC1_WKCN     (1 << 20)
+#define   USB_PORTSC1_PTC(x)   (((x) & 0xf) << 16)
+#define   USB_PORTSC1_PP       (1 << 12)
+#define   USB_PORTSC1_SUSP     (1 << 7)
+#define   USB_PORTSC1_PE       (1 << 2)
+#define   USB_PORTSC1_CCS      (1 << 0)
+
+#define USB_SUSP_CTRL          0x400
+#define   USB_WAKE_ON_CNNT_EN_DEV      (1 << 3)
+#define   USB_WAKE_ON_DISCON_EN_DEV    (1 << 4)
+#define   USB_SUSP_CLR         (1 << 5)
+#define   USB_PHY_CLK_VALID    (1 << 7)
+#define   UTMIP_RESET                  (1 << 11)
+#define   UHSIC_RESET                  (1 << 11)
+#define   UTMIP_PHY_ENABLE             (1 << 12)
+#define   ULPI_PHY_ENABLE      (1 << 13)
+#define   USB_SUSP_SET         (1 << 14)
+#define   USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+
+#define USB1_LEGACY_CTRL       0x410
+#define   USB1_NO_LEGACY_MODE                  (1 << 0)
+#define   USB1_VBUS_SENSE_CTL_MASK             (3 << 1)
+#define   USB1_VBUS_SENSE_CTL_VBUS_WAKEUP      (0 << 1)
+#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
+                                               (1 << 1)
+#define   USB1_VBUS_SENSE_CTL_AB_SESS_VLD      (2 << 1)
+#define   USB1_VBUS_SENSE_CTL_A_SESS_VLD       (3 << 1)
+
+#define ULPI_TIMING_CTRL_0     0x424
+#define   ULPI_OUTPUT_PINMUX_BYP       (1 << 10)
+#define   ULPI_CLKOUT_PINMUX_BYP       (1 << 11)
+
+#define ULPI_TIMING_CTRL_1     0x428
+#define   ULPI_DATA_TRIMMER_LOAD       (1 << 0)
+#define   ULPI_DATA_TRIMMER_SEL(x)     (((x) & 0x7) << 1)
+#define   ULPI_STPDIRNXT_TRIMMER_LOAD  (1 << 16)
+#define   ULPI_STPDIRNXT_TRIMMER_SEL(x)        (((x) & 0x7) << 17)
+#define   ULPI_DIR_TRIMMER_LOAD                (1 << 24)
+#define   ULPI_DIR_TRIMMER_SEL(x)      (((x) & 0x7) << 25)
+
+#define UTMIP_PLL_CFG1         0x804
+#define   UTMIP_XTAL_FREQ_COUNT(x)             (((x) & 0xfff) << 0)
+#define   UTMIP_PLLU_ENABLE_DLY_COUNT(x)       (((x) & 0x1f) << 27)
+
+#define UTMIP_XCVR_CFG0                0x808
+#define   UTMIP_XCVR_SETUP(x)                  (((x) & 0xf) << 0)
+#define   UTMIP_XCVR_LSRSLEW(x)                        (((x) & 0x3) << 8)
+#define   UTMIP_XCVR_LSFSLEW(x)                        (((x) & 0x3) << 10)
+#define   UTMIP_FORCE_PD_POWERDOWN             (1 << 14)
+#define   UTMIP_FORCE_PD2_POWERDOWN            (1 << 16)
+#define   UTMIP_FORCE_PDZI_POWERDOWN           (1 << 18)
+#define   UTMIP_XCVR_HSSLEW_MSB(x)             (((x) & 0x7f) << 25)
+
+#define UTMIP_BIAS_CFG0                0x80c
+#define   UTMIP_OTGPD                  (1 << 11)
+#define   UTMIP_BIASPD                 (1 << 10)
+
+#define UTMIP_HSRX_CFG0                0x810
+#define   UTMIP_ELASTIC_LIMIT(x)       (((x) & 0x1f) << 10)
+#define   UTMIP_IDLE_WAIT(x)           (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1                0x814
+#define   UTMIP_HS_SYNC_START_DLY(x)   (((x) & 0x1f) << 1)
+
+#define UTMIP_TX_CFG0          0x820
+#define   UTMIP_FS_PREABMLE_J          (1 << 19)
+#define   UTMIP_HS_DISCON_DISABLE      (1 << 8)
+
+#define UTMIP_MISC_CFG0                0x824
+#define   UTMIP_DPDM_OBSERVE           (1 << 26)
+#define   UTMIP_DPDM_OBSERVE_SEL(x)    (((x) & 0xf) << 27)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_J  UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_K  UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define   UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define   UTMIP_SUSPEND_EXIT_ON_EDGE   (1 << 22)
+
+#define UTMIP_MISC_CFG1                0x828
+#define   UTMIP_PLL_ACTIVE_DLY_COUNT(x)        (((x) & 0x1f) << 18)
+#define   UTMIP_PLLU_STABLE_COUNT(x)   (((x) & 0xfff) << 6)
+
+#define UTMIP_DEBOUNCE_CFG0    0x82c
+#define   UTMIP_BIAS_DEBOUNCE_A(x)     (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0    0x830
+#define   UTMIP_PD_CHRG                        (1 << 0)
+
+#define UTMIP_SPARE_CFG0       0x834
+#define   FUSE_SETUP_SEL               (1 << 3)
+
+#define UTMIP_XCVR_CFG1                0x838
+#define   UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define   UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define   UTMIP_FORCE_PDDR_POWERDOWN   (1 << 4)
+#define   UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1                0x83c
+#define   UTMIP_BIAS_PDTRK_COUNT(x)    (((x) & 0x1f) << 3)
+
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+
+struct tegra_xtal_freq {
+       int freq;
+       u8 enable_delay;
+       u8 stable_count;
+       u8 active_delay;
+       u8 xtal_freq_count;
+       u16 debounce;
+};
+
+static const struct tegra_xtal_freq tegra_freq_table[] = {
+       {
+               .freq = 12000000,
+               .enable_delay = 0x02,
+               .stable_count = 0x2F,
+               .active_delay = 0x04,
+               .xtal_freq_count = 0x76,
+               .debounce = 0x7530,
+       },
+       {
+               .freq = 13000000,
+               .enable_delay = 0x02,
+               .stable_count = 0x33,
+               .active_delay = 0x05,
+               .xtal_freq_count = 0x7F,
+               .debounce = 0x7EF4,
+       },
+       {
+               .freq = 19200000,
+               .enable_delay = 0x03,
+               .stable_count = 0x4B,
+               .active_delay = 0x06,
+               .xtal_freq_count = 0xBB,
+               .debounce = 0xBB80,
+       },
+       {
+               .freq = 26000000,
+               .enable_delay = 0x04,
+               .stable_count = 0x66,
+               .active_delay = 0x09,
+               .xtal_freq_count = 0xFE,
+               .debounce = 0xFDE8,
+       },
+};
+
+static struct tegra_utmip_config utmip_default[] = {
+       [0] = {
+               .hssync_start_delay = 9,
+               .idle_wait_delay = 17,
+               .elastic_limit = 16,
+               .term_range_adj = 6,
+               .xcvr_setup = 9,
+               .xcvr_lsfslew = 1,
+               .xcvr_lsrslew = 1,
+       },
+       [2] = {
+               .hssync_start_delay = 9,
+               .idle_wait_delay = 17,
+               .elastic_limit = 16,
+               .term_range_adj = 6,
+               .xcvr_setup = 9,
+               .xcvr_lsfslew = 2,
+               .xcvr_lsrslew = 2,
+       },
+};
+
+static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
+{
+       return (phy->instance == 1);
+}
+
+static int utmip_pad_open(struct tegra_usb_phy *phy)
+{
+       phy->pad_clk = clk_get_sys("utmip-pad", NULL);
+       if (IS_ERR(phy->pad_clk)) {
+               pr_err("%s: can't get utmip pad clock\n", __func__);
+               return PTR_ERR(phy->pad_clk);
+       }
+
+       if (phy->instance == 0) {
+               phy->pad_regs = phy->regs;
+       } else {
+               phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
+               if (!phy->pad_regs) {
+                       pr_err("%s: can't remap usb registers\n", __func__);
+                       clk_put(phy->pad_clk);
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+static void utmip_pad_close(struct tegra_usb_phy *phy)
+{
+       if (phy->instance != 0)
+               iounmap(phy->pad_regs);
+       clk_put(phy->pad_clk);
+}
+
+static void utmip_pad_power_on(struct tegra_usb_phy *phy)
+{
+       unsigned long val, flags;
+       void __iomem *base = phy->pad_regs;
+
+       clk_prepare_enable(phy->pad_clk);
+
+       spin_lock_irqsave(&utmip_pad_lock, flags);
+
+       if (utmip_pad_count++ == 0) {
+               val = readl(base + UTMIP_BIAS_CFG0);
+               val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+               writel(val, base + UTMIP_BIAS_CFG0);
+       }
+
+       spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+       clk_disable_unprepare(phy->pad_clk);
+}
+
+static int utmip_pad_power_off(struct tegra_usb_phy *phy)
+{
+       unsigned long val, flags;
+       void __iomem *base = phy->pad_regs;
+
+       if (!utmip_pad_count) {
+               pr_err("%s: utmip pad already powered off\n", __func__);
+               return -EINVAL;
+       }
+
+       clk_prepare_enable(phy->pad_clk);
+
+       spin_lock_irqsave(&utmip_pad_lock, flags);
+
+       if (--utmip_pad_count == 0) {
+               val = readl(base + UTMIP_BIAS_CFG0);
+               val |= UTMIP_OTGPD | UTMIP_BIASPD;
+               writel(val, base + UTMIP_BIAS_CFG0);
+       }
+
+       spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+       clk_disable_unprepare(phy->pad_clk);
+
+       return 0;
+}
+
+static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+{
+       unsigned long timeout = 2000;
+       do {
+               if ((readl(reg) & mask) == result)
+                       return 0;
+               udelay(1);
+               timeout--;
+       } while (timeout);
+       return -1;
+}
+
+static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       if (phy->instance == 0) {
+               val = readl(base + USB_SUSP_CTRL);
+               val |= USB_SUSP_SET;
+               writel(val, base + USB_SUSP_CTRL);
+
+               udelay(10);
+
+               val = readl(base + USB_SUSP_CTRL);
+               val &= ~USB_SUSP_SET;
+               writel(val, base + USB_SUSP_CTRL);
+       }
+
+       if (phy->instance == 2) {
+               val = readl(base + USB_PORTSC1);
+               val |= USB_PORTSC1_PHCD;
+               writel(val, base + USB_PORTSC1);
+       }
+
+       if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
+               pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+}
+
+static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       if (phy->instance == 0) {
+               val = readl(base + USB_SUSP_CTRL);
+               val |= USB_SUSP_CLR;
+               writel(val, base + USB_SUSP_CTRL);
+
+               udelay(10);
+
+               val = readl(base + USB_SUSP_CTRL);
+               val &= ~USB_SUSP_CLR;
+               writel(val, base + USB_SUSP_CTRL);
+       }
+
+       if (phy->instance == 2) {
+               val = readl(base + USB_PORTSC1);
+               val &= ~USB_PORTSC1_PHCD;
+               writel(val, base + USB_PORTSC1);
+       }
+
+       if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+                                                    USB_PHY_CLK_VALID))
+               pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+}
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+       struct tegra_utmip_config *config = phy->config;
+
+       val = readl(base + USB_SUSP_CTRL);
+       val |= UTMIP_RESET;
+       writel(val, base + USB_SUSP_CTRL);
+
+       if (phy->instance == 0) {
+               val = readl(base + USB1_LEGACY_CTRL);
+               val |= USB1_NO_LEGACY_MODE;
+               writel(val, base + USB1_LEGACY_CTRL);
+       }
+
+       val = readl(base + UTMIP_TX_CFG0);
+       val &= ~UTMIP_FS_PREABMLE_J;
+       writel(val, base + UTMIP_TX_CFG0);
+
+       val = readl(base + UTMIP_HSRX_CFG0);
+       val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+       val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+       val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+       writel(val, base + UTMIP_HSRX_CFG0);
+
+       val = readl(base + UTMIP_HSRX_CFG1);
+       val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+       val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+       writel(val, base + UTMIP_HSRX_CFG1);
+
+       val = readl(base + UTMIP_DEBOUNCE_CFG0);
+       val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+       val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+       writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+       val = readl(base + UTMIP_MISC_CFG0);
+       val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+       writel(val, base + UTMIP_MISC_CFG0);
+
+       val = readl(base + UTMIP_MISC_CFG1);
+       val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
+       val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+               UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+       writel(val, base + UTMIP_MISC_CFG1);
+
+       val = readl(base + UTMIP_PLL_CFG1);
+       val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+       val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+               UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+       writel(val, base + UTMIP_PLL_CFG1);
+
+       if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+               val = readl(base + USB_SUSP_CTRL);
+               val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+               writel(val, base + USB_SUSP_CTRL);
+       }
+
+       utmip_pad_power_on(phy);
+
+       val = readl(base + UTMIP_XCVR_CFG0);
+       val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+                UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
+                UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
+                UTMIP_XCVR_HSSLEW_MSB(~0));
+       val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+       val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+       val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+       writel(val, base + UTMIP_XCVR_CFG0);
+
+       val = readl(base + UTMIP_XCVR_CFG1);
+       val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+                UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+       val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+       writel(val, base + UTMIP_XCVR_CFG1);
+
+       val = readl(base + UTMIP_BAT_CHRG_CFG0);
+       val &= ~UTMIP_PD_CHRG;
+       writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+       val = readl(base + UTMIP_BIAS_CFG1);
+       val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+       val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+       writel(val, base + UTMIP_BIAS_CFG1);
+
+       if (phy->instance == 0) {
+               val = readl(base + UTMIP_SPARE_CFG0);
+               if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
+                       val &= ~FUSE_SETUP_SEL;
+               else
+                       val |= FUSE_SETUP_SEL;
+               writel(val, base + UTMIP_SPARE_CFG0);
+       }
+
+       if (phy->instance == 2) {
+               val = readl(base + USB_SUSP_CTRL);
+               val |= UTMIP_PHY_ENABLE;
+               writel(val, base + USB_SUSP_CTRL);
+       }
+
+       val = readl(base + USB_SUSP_CTRL);
+       val &= ~UTMIP_RESET;
+       writel(val, base + USB_SUSP_CTRL);
+
+       if (phy->instance == 0) {
+               val = readl(base + USB1_LEGACY_CTRL);
+               val &= ~USB1_VBUS_SENSE_CTL_MASK;
+               val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
+               writel(val, base + USB1_LEGACY_CTRL);
+
+               val = readl(base + USB_SUSP_CTRL);
+               val &= ~USB_SUSP_SET;
+               writel(val, base + USB_SUSP_CTRL);
+       }
+
+       utmi_phy_clk_enable(phy);
+
+       if (phy->instance == 2) {
+               val = readl(base + USB_PORTSC1);
+               val &= ~USB_PORTSC1_PTS(~0);
+               writel(val, base + USB_PORTSC1);
+       }
+
+       return 0;
+}
+
+static int utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       utmi_phy_clk_disable(phy);
+
+       if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+               val = readl(base + USB_SUSP_CTRL);
+               val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+               val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+               writel(val, base + USB_SUSP_CTRL);
+       }
+
+       val = readl(base + USB_SUSP_CTRL);
+       val |= UTMIP_RESET;
+       writel(val, base + USB_SUSP_CTRL);
+
+       val = readl(base + UTMIP_BAT_CHRG_CFG0);
+       val |= UTMIP_PD_CHRG;
+       writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+       val = readl(base + UTMIP_XCVR_CFG0);
+       val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+              UTMIP_FORCE_PDZI_POWERDOWN;
+       writel(val, base + UTMIP_XCVR_CFG0);
+
+       val = readl(base + UTMIP_XCVR_CFG1);
+       val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+              UTMIP_FORCE_PDDR_POWERDOWN;
+       writel(val, base + UTMIP_XCVR_CFG1);
+
+       return utmip_pad_power_off(phy);
+}
+
+static void utmi_phy_preresume(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       val = readl(base + UTMIP_TX_CFG0);
+       val |= UTMIP_HS_DISCON_DISABLE;
+       writel(val, base + UTMIP_TX_CFG0);
+}
+
+static void utmi_phy_postresume(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       val = readl(base + UTMIP_TX_CFG0);
+       val &= ~UTMIP_HS_DISCON_DISABLE;
+       writel(val, base + UTMIP_TX_CFG0);
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
+                                  enum tegra_usb_phy_port_speed port_speed)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       val = readl(base + UTMIP_MISC_CFG0);
+       val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+       if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
+               val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+       else
+               val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+       writel(val, base + UTMIP_MISC_CFG0);
+       udelay(1);
+
+       val = readl(base + UTMIP_MISC_CFG0);
+       val |= UTMIP_DPDM_OBSERVE;
+       writel(val, base + UTMIP_MISC_CFG0);
+       udelay(10);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+
+       val = readl(base + UTMIP_MISC_CFG0);
+       val &= ~UTMIP_DPDM_OBSERVE;
+       writel(val, base + UTMIP_MISC_CFG0);
+       udelay(10);
+}
+
+static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
+{
+       int ret;
+       unsigned long val;
+       void __iomem *base = phy->regs;
+       struct tegra_ulpi_config *config = phy->config;
+
+       gpio_direction_output(config->reset_gpio, 0);
+       msleep(5);
+       gpio_direction_output(config->reset_gpio, 1);
+
+       clk_prepare_enable(phy->clk);
+       msleep(1);
+
+       val = readl(base + USB_SUSP_CTRL);
+       val |= UHSIC_RESET;
+       writel(val, base + USB_SUSP_CTRL);
+
+       val = readl(base + ULPI_TIMING_CTRL_0);
+       val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+       writel(val, base + ULPI_TIMING_CTRL_0);
+
+       val = readl(base + USB_SUSP_CTRL);
+       val |= ULPI_PHY_ENABLE;
+       writel(val, base + USB_SUSP_CTRL);
+
+       val = 0;
+       writel(val, base + ULPI_TIMING_CTRL_1);
+
+       val |= ULPI_DATA_TRIMMER_SEL(4);
+       val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
+       val |= ULPI_DIR_TRIMMER_SEL(4);
+       writel(val, base + ULPI_TIMING_CTRL_1);
+       udelay(10);
+
+       val |= ULPI_DATA_TRIMMER_LOAD;
+       val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+       val |= ULPI_DIR_TRIMMER_LOAD;
+       writel(val, base + ULPI_TIMING_CTRL_1);
+
+       /* Fix VbusInvalid due to floating VBUS */
+       ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
+       if (ret) {
+               pr_err("%s: ulpi write failed\n", __func__);
+               return ret;
+       }
+
+       ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
+       if (ret) {
+               pr_err("%s: ulpi write failed\n", __func__);
+               return ret;
+       }
+
+       val = readl(base + USB_PORTSC1);
+       val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
+       writel(val, base + USB_PORTSC1);
+
+       val = readl(base + USB_SUSP_CTRL);
+       val |= USB_SUSP_CLR;
+       writel(val, base + USB_SUSP_CTRL);
+       udelay(100);
+
+       val = readl(base + USB_SUSP_CTRL);
+       val &= ~USB_SUSP_CLR;
+       writel(val, base + USB_SUSP_CTRL);
+
+       return 0;
+}
+
+static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
+{
+       unsigned long val;
+       void __iomem *base = phy->regs;
+       struct tegra_ulpi_config *config = phy->config;
+
+       /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
+        * Controller to immediately bring the ULPI PHY out of low power
+        */
+       val = readl(base + USB_PORTSC1);
+       val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
+       writel(val, base + USB_PORTSC1);
+
+       clk_disable(phy->clk);
+       return gpio_direction_output(config->reset_gpio, 0);
+}
+
+static int     tegra_phy_init(struct usb_phy *x)
+{
+       struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+       struct tegra_ulpi_config *ulpi_config;
+       int err;
+
+       if (phy_is_ulpi(phy)) {
+               ulpi_config = phy->config;
+               phy->clk = clk_get_sys(NULL, ulpi_config->clk);
+               if (IS_ERR(phy->clk)) {
+                       pr_err("%s: can't get ulpi clock\n", __func__);
+                       err = -ENXIO;
+                       goto err1;
+               }
+               if (!gpio_is_valid(ulpi_config->reset_gpio))
+                       ulpi_config->reset_gpio =
+                               of_get_named_gpio(phy->dev->of_node,
+                                                 "nvidia,phy-reset-gpio", 0);
+               if (!gpio_is_valid(ulpi_config->reset_gpio)) {
+                       pr_err("%s: invalid reset gpio: %d\n", __func__,
+                              ulpi_config->reset_gpio);
+                       err = -EINVAL;
+                       goto err1;
+               }
+               gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
+               gpio_direction_output(ulpi_config->reset_gpio, 0);
+               phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+               phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
+       } else {
+               err = utmip_pad_open(phy);
+               if (err < 0)
+                       goto err1;
+       }
+       return 0;
+err1:
+       clk_disable_unprepare(phy->pll_u);
+       clk_put(phy->pll_u);
+       return err;
+}
+
+static void tegra_usb_phy_close(struct usb_phy *x)
+{
+       struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+
+       if (phy_is_ulpi(phy))
+               clk_put(phy->clk);
+       else
+               utmip_pad_close(phy);
+       clk_disable_unprepare(phy->pll_u);
+       clk_put(phy->pll_u);
+       kfree(phy);
+}
+
+static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
+{
+       if (phy_is_ulpi(phy))
+               return ulpi_phy_power_on(phy);
+       else
+               return utmi_phy_power_on(phy);
+}
+
+static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
+{
+       if (phy_is_ulpi(phy))
+               return ulpi_phy_power_off(phy);
+       else
+               return utmi_phy_power_off(phy);
+}
+
+static int     tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
+{
+       struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
+       if (suspend)
+               return tegra_usb_phy_power_off(phy);
+       else
+               return tegra_usb_phy_power_on(phy);
+}
+
+struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
+       void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode)
+{
+       struct tegra_usb_phy *phy;
+       unsigned long parent_rate;
+       int i;
+       int err;
+
+       phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
+       if (!phy)
+               return ERR_PTR(-ENOMEM);
+
+       phy->instance = instance;
+       phy->regs = regs;
+       phy->config = config;
+       phy->mode = phy_mode;
+       phy->dev = dev;
+
+       if (!phy->config) {
+               if (phy_is_ulpi(phy)) {
+                       pr_err("%s: ulpi phy configuration missing", __func__);
+                       err = -EINVAL;
+                       goto err0;
+               } else {
+                       phy->config = &utmip_default[instance];
+               }
+       }
+
+       phy->pll_u = clk_get_sys(NULL, "pll_u");
+       if (IS_ERR(phy->pll_u)) {
+               pr_err("Can't get pll_u clock\n");
+               err = PTR_ERR(phy->pll_u);
+               goto err0;
+       }
+       clk_prepare_enable(phy->pll_u);
+
+       parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
+       for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
+               if (tegra_freq_table[i].freq == parent_rate) {
+                       phy->freq = &tegra_freq_table[i];
+                       break;
+               }
+       }
+       if (!phy->freq) {
+               pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+               err = -EINVAL;
+               goto err1;
+       }
+
+       phy->u_phy.init = tegra_phy_init;
+       phy->u_phy.shutdown = tegra_usb_phy_close;
+       phy->u_phy.set_suspend = tegra_usb_phy_suspend;
+
+       return phy;
+
+err1:
+       clk_disable_unprepare(phy->pll_u);
+       clk_put(phy->pll_u);
+err0:
+       kfree(phy);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
+
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
+{
+       if (!phy_is_ulpi(phy))
+               utmi_phy_preresume(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
+
+void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
+{
+       if (!phy_is_ulpi(phy))
+               utmi_phy_postresume(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
+
+void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
+                                enum tegra_usb_phy_port_speed port_speed)
+{
+       if (!phy_is_ulpi(phy))
+               utmi_phy_restore_start(phy, port_speed);
+}
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
+
+void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
+{
+       if (!phy_is_ulpi(phy))
+               utmi_phy_restore_end(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
+
+void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
+{
+       if (!phy_is_ulpi(phy))
+               utmi_phy_clk_disable(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
+
+void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
+{
+       if (!phy_is_ulpi(phy))
+               utmi_phy_clk_enable(phy);
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
index 8c9bb1ad30698b58f8949d7cdc0ca048492f5d62..681da06170c29273045b9602f9b63a873cacf8c0 100644 (file)
@@ -603,12 +603,12 @@ static int usbhsc_resume(struct device *dev)
        struct usbhs_priv *priv = dev_get_drvdata(dev);
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       usbhs_platform_call(priv, phy_reset, pdev);
-
        if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
                usbhsc_power_ctrl(priv, 1);
 
-       usbhsc_hotplug(priv);
+       usbhs_platform_call(priv, phy_reset, pdev);
+
+       usbhsc_drvcllbck_notify_hotplug(pdev);
 
        return 0;
 }
index ecd173032fd480cc5954c48f03aa61e7b5c439e8..143c4e9e1be45cc24c0a612d38e590a5ad136be9 100644 (file)
@@ -818,7 +818,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
            usbhs_pipe_is_dcp(pipe))
                goto usbhsf_pio_prepare_push;
 
-       if (len % 4) /* 32bit alignment */
+       if (len & 0x7) /* 8byte alignment */
                goto usbhsf_pio_prepare_push;
 
        if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
@@ -905,7 +905,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
        /* use PIO if packet is less than pio_dma_border */
        len = usbhsf_fifo_rcv_len(priv, fifo);
        len = min(pkt->length - pkt->actual, len);
-       if (len % 4) /* 32bit alignment */
+       if (len & 0x7) /* 8byte alignment */
                goto usbhsf_pio_prepare_pop_unselect;
 
        if (len < usbhs_get_dparam(priv, pio_dma_border))
index 82a628f96c03d4ac54e43daebe3a74d2abd31797..35c5208f32494d7c55f4fd98fa79cf517425ca46 100644 (file)
@@ -209,14 +209,18 @@ int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state)
        return (int)irq_state->intsts0 & CTSQ_MASK;
 }
 
-static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
-                                     struct usbhs_irq_state *state)
+static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
+                                    struct usbhs_irq_state *state)
 {
        struct usbhs_mod *mod = usbhs_mod_get_current(priv);
+       u16 intenb0, intenb1;
 
        state->intsts0 = usbhs_read(priv, INTSTS0);
        state->intsts1 = usbhs_read(priv, INTSTS1);
 
+       intenb0 = usbhs_read(priv, INTENB0);
+       intenb1 = usbhs_read(priv, INTENB1);
+
        /* mask */
        if (mod) {
                state->brdysts = usbhs_read(priv, BRDYSTS);
@@ -226,6 +230,20 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv,
                state->bempsts &= mod->irq_bempsts;
                state->brdysts &= mod->irq_brdysts;
        }
+
+       /*
+        * Check whether the irq enable registers and the irq status are set
+        * when IRQF_SHARED is set.
+        */
+       if (priv->irqflags & IRQF_SHARED) {
+               if (!(intenb0 & state->intsts0) &&
+                   !(intenb1 & state->intsts1) &&
+                   !(state->bempsts) &&
+                   !(state->brdysts))
+                       return -EIO;
+       }
+
+       return 0;
 }
 
 /*
@@ -238,7 +256,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data)
        struct usbhs_priv *priv = data;
        struct usbhs_irq_state irq_state;
 
-       usbhs_status_get_each_irq(priv, &irq_state);
+       if (usbhs_status_get_each_irq(priv, &irq_state) < 0)
+               return IRQ_NONE;
 
        /*
         * clear interrupt
index 1834cf50888cbc8a6832e5250a8ccd8dbdddaee5..9b69a132329474052486e0483649b6c64a746a4f 100644 (file)
@@ -1266,6 +1266,12 @@ static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        return ret;
 }
 
+static int usbhsh_bus_nop(struct usb_hcd *hcd)
+{
+       /* nothing to do */
+       return 0;
+}
+
 static struct hc_driver usbhsh_driver = {
        .description =          usbhsh_hcd_name,
        .hcd_priv_size =        sizeof(struct usbhsh_hpriv),
@@ -1290,6 +1296,8 @@ static struct hc_driver usbhsh_driver = {
         */
        .hub_status_data =      usbhsh_hub_status_data,
        .hub_control =          usbhsh_hub_control,
+       .bus_suspend =          usbhsh_bus_nop,
+       .bus_resume =           usbhsh_bus_nop,
 };
 
 /*
index f398d1e34474c34084b43dac6702a6378f71a970..c15f2e7cefc77e4782dfb39fcedc54e5b0bc6329 100644 (file)
@@ -61,18 +61,23 @@ static int usb_serial_device_probe(struct device *dev)
                goto exit;
        }
 
+       /* make sure suspend/resume doesn't race against port_probe */
+       retval = usb_autopm_get_interface(port->serial->interface);
+       if (retval)
+               goto exit;
+
        driver = port->serial->type;
        if (driver->port_probe) {
                retval = driver->port_probe(port);
                if (retval)
-                       goto exit;
+                       goto exit_with_autopm;
        }
 
        retval = device_create_file(dev, &dev_attr_port_number);
        if (retval) {
                if (driver->port_remove)
                        retval = driver->port_remove(port);
-               goto exit;
+               goto exit_with_autopm;
        }
 
        minor = port->number;
@@ -81,6 +86,8 @@ static int usb_serial_device_probe(struct device *dev)
                 "%s converter now attached to ttyUSB%d\n",
                 driver->description, minor);
 
+exit_with_autopm:
+       usb_autopm_put_interface(port->serial->interface);
 exit:
        return retval;
 }
@@ -96,6 +103,9 @@ static int usb_serial_device_remove(struct device *dev)
        if (!port)
                return -ENODEV;
 
+       /* make sure suspend/resume doesn't race against port_remove */
+       usb_autopm_get_interface(port->serial->interface);
+
        device_remove_file(&port->dev, &dev_attr_port_number);
 
        driver = port->serial->type;
@@ -107,6 +117,7 @@ static int usb_serial_device_remove(struct device *dev)
        dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
                 driver->description, minor);
 
+       usb_autopm_put_interface(port->serial->interface);
        return retval;
 }
 
index 1e71079ce33b7128c116f602d865428297804da7..3f86cf3735a71e0670b58d0f094cf02d5e9e5b28 100644 (file)
@@ -865,7 +865,6 @@ static int cp210x_startup(struct usb_serial *serial)
                if (!port_priv)
                        return -ENOMEM;
 
-               memset(port_priv, 0x00, sizeof(*port_priv));
                port_priv->bInterfaceNumber =
                    serial->interface->cur_altsetting->desc.bInterfaceNumber;
 
index bc912e5a3bebddf3073fe17e015b6195be3708be..29b81ad421fe218ad7203a33c1b2439745c48ec4 100644 (file)
@@ -811,6 +811,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
        { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
        { USB_DEVICE(PI_VID, PI_E861_PID) },
+       { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
        { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
        { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -2106,7 +2107,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
 
        cflag = termios->c_cflag;
 
-       if (old_termios == 0)
+       if (!old_termios)
                goto no_skip;
 
        if (old_termios->c_cflag == termios->c_cflag
index 5661c7e2d4151cbb8f2335c4572f83fc3deccff8..5dd96ca6c380a0971921d198e12399e1902663db 100644 (file)
 #define PI_VID              0x1a72  /* Vendor ID */
 #define PI_E861_PID         0x1008  /* E-861 piezo controller USB connection */
 
+/*
+ * Kondo Kagaku Co.Ltd.
+ * http://www.kondo-robot.com/EN
+ */
+#define KONDO_VID              0x165c
+#define KONDO_USB_SERIAL_PID   0x0002
+
 /*
  * Bayer Ascensia Contour blood glucose meter USB-converter cable.
  * http://winglucofacts.com/cables/
index 5811d34b6c6bc514fb8474cc9662ad9521471a72..2cb30c535839db429c0165a76be26afdf84063cb 100644 (file)
@@ -227,7 +227,6 @@ static void ipw_release(struct usb_serial *serial)
 {
        struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
 
-       usb_wwan_release(serial);
        usb_set_serial_data(serial, NULL);
        kfree(data);
 }
@@ -309,12 +308,12 @@ static struct usb_serial_driver ipw_device = {
        .description =          "IPWireless converter",
        .id_table =             id_table,
        .num_ports =            1,
-       .disconnect =           usb_wwan_disconnect,
        .open =                 ipw_open,
        .close =                ipw_close,
        .probe =                ipw_probe,
        .attach =               usb_wwan_startup,
        .release =              ipw_release,
+       .port_remove =          usb_wwan_port_remove,
        .dtr_rts =              ipw_dtr_rts,
        .write =                usb_wwan_write,
 };
index a07dd3c8cfef3e408fbaa4bba593267621ccec71..9817d9d654c1f6a0d1d14a2007595acba48aa383 100644 (file)
@@ -281,7 +281,7 @@ static void send_deferred_urbs(unsigned long _mos_parport)
        int ret_val;
        unsigned long flags;
        struct mos7715_parport *mos_parport = (void *)_mos_parport;
-       struct urbtracker *urbtrack;
+       struct urbtracker *urbtrack, *tmp;
        struct list_head *cursor, *next;
 
        /* if release function ran, game over */
@@ -312,7 +312,7 @@ static void send_deferred_urbs(unsigned long _mos_parport)
        /* move contents of deferred_urbs list to active_urbs list and submit */
        list_for_each_safe(cursor, next, &mos_parport->deferred_urbs)
                list_move_tail(cursor, &mos_parport->active_urbs);
-       list_for_each_entry(urbtrack, &mos_parport->active_urbs,
+       list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs,
                            urblist_entry) {
                ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC);
                dbg("%s: urb submitted", __func__);
index 57eca244842431fa100f742424c9dbc6310c4156..2f6da1e89bfa5606772103ce70f70087a9bfab42 100644 (file)
@@ -82,8 +82,7 @@
  * Defines used for sending commands to port
  */
 
-#define WAIT_FOR_EVER   (HZ * 0)       /* timeout urb is wait for ever */
-#define MOS_WDR_TIMEOUT (HZ * 5)       /* default urb timeout */
+#define MOS_WDR_TIMEOUT                5000    /* default urb timeout */
 
 #define MOS_PORT1       0x0200
 #define MOS_PORT2       0x0300
@@ -1232,9 +1231,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
                return 0;
 
        spin_lock_irqsave(&mos7840_port->pool_lock, flags);
-       for (i = 0; i < NUM_URBS; ++i)
-               if (mos7840_port->busy[i])
-                       chars += URB_TRANSFER_BUFFER_SIZE;
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (mos7840_port->busy[i]) {
+                       struct urb *urb = mos7840_port->write_urb_pool[i];
+                       chars += urb->transfer_buffer_length;
+               }
+       }
        spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
        dbg("%s - returns %d", __func__, chars);
        return chars;
@@ -1344,7 +1346,7 @@ static void mos7840_close(struct usb_serial_port *port)
 static void mos7840_block_until_chase_response(struct tty_struct *tty,
                                        struct moschip_port *mos7840_port)
 {
-       int timeout = 1 * HZ;
+       int timeout = msecs_to_jiffies(1000);
        int wait = 10;
        int count;
 
@@ -2672,7 +2674,7 @@ static int mos7840_startup(struct usb_serial *serial)
 
        /* setting configuration feature to one */
        usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                       (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
+                       (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, MOS_WDR_TIMEOUT);
        return 0;
 error:
        for (/* nothing */; i >= 0; i--) {
index 08ff9b862049197566454d1052d6c46160efbab6..cc40f47ecea13ff2041389d5aa7d5526159e58d8 100644 (file)
@@ -80,85 +80,9 @@ static void option_instat_callback(struct urb *urb);
 #define OPTION_PRODUCT_GTM380_MODEM            0x7201
 
 #define HUAWEI_VENDOR_ID                       0x12D1
-#define HUAWEI_PRODUCT_E600                    0x1001
-#define HUAWEI_PRODUCT_E220                    0x1003
-#define HUAWEI_PRODUCT_E220BIS                 0x1004
-#define HUAWEI_PRODUCT_E1401                   0x1401
-#define HUAWEI_PRODUCT_E1402                   0x1402
-#define HUAWEI_PRODUCT_E1403                   0x1403
-#define HUAWEI_PRODUCT_E1404                   0x1404
-#define HUAWEI_PRODUCT_E1405                   0x1405
-#define HUAWEI_PRODUCT_E1406                   0x1406
-#define HUAWEI_PRODUCT_E1407                   0x1407
-#define HUAWEI_PRODUCT_E1408                   0x1408
-#define HUAWEI_PRODUCT_E1409                   0x1409
-#define HUAWEI_PRODUCT_E140A                   0x140A
-#define HUAWEI_PRODUCT_E140B                   0x140B
-#define HUAWEI_PRODUCT_E140C                   0x140C
-#define HUAWEI_PRODUCT_E140D                   0x140D
-#define HUAWEI_PRODUCT_E140E                   0x140E
-#define HUAWEI_PRODUCT_E140F                   0x140F
-#define HUAWEI_PRODUCT_E1410                   0x1410
-#define HUAWEI_PRODUCT_E1411                   0x1411
-#define HUAWEI_PRODUCT_E1412                   0x1412
-#define HUAWEI_PRODUCT_E1413                   0x1413
-#define HUAWEI_PRODUCT_E1414                   0x1414
-#define HUAWEI_PRODUCT_E1415                   0x1415
-#define HUAWEI_PRODUCT_E1416                   0x1416
-#define HUAWEI_PRODUCT_E1417                   0x1417
-#define HUAWEI_PRODUCT_E1418                   0x1418
-#define HUAWEI_PRODUCT_E1419                   0x1419
-#define HUAWEI_PRODUCT_E141A                   0x141A
-#define HUAWEI_PRODUCT_E141B                   0x141B
-#define HUAWEI_PRODUCT_E141C                   0x141C
-#define HUAWEI_PRODUCT_E141D                   0x141D
-#define HUAWEI_PRODUCT_E141E                   0x141E
-#define HUAWEI_PRODUCT_E141F                   0x141F
-#define HUAWEI_PRODUCT_E1420                   0x1420
-#define HUAWEI_PRODUCT_E1421                   0x1421
-#define HUAWEI_PRODUCT_E1422                   0x1422
-#define HUAWEI_PRODUCT_E1423                   0x1423
-#define HUAWEI_PRODUCT_E1424                   0x1424
-#define HUAWEI_PRODUCT_E1425                   0x1425
-#define HUAWEI_PRODUCT_E1426                   0x1426
-#define HUAWEI_PRODUCT_E1427                   0x1427
-#define HUAWEI_PRODUCT_E1428                   0x1428
-#define HUAWEI_PRODUCT_E1429                   0x1429
-#define HUAWEI_PRODUCT_E142A                   0x142A
-#define HUAWEI_PRODUCT_E142B                   0x142B
-#define HUAWEI_PRODUCT_E142C                   0x142C
-#define HUAWEI_PRODUCT_E142D                   0x142D
-#define HUAWEI_PRODUCT_E142E                   0x142E
-#define HUAWEI_PRODUCT_E142F                   0x142F
-#define HUAWEI_PRODUCT_E1430                   0x1430
-#define HUAWEI_PRODUCT_E1431                   0x1431
-#define HUAWEI_PRODUCT_E1432                   0x1432
-#define HUAWEI_PRODUCT_E1433                   0x1433
-#define HUAWEI_PRODUCT_E1434                   0x1434
-#define HUAWEI_PRODUCT_E1435                   0x1435
-#define HUAWEI_PRODUCT_E1436                   0x1436
-#define HUAWEI_PRODUCT_E1437                   0x1437
-#define HUAWEI_PRODUCT_E1438                   0x1438
-#define HUAWEI_PRODUCT_E1439                   0x1439
-#define HUAWEI_PRODUCT_E143A                   0x143A
-#define HUAWEI_PRODUCT_E143B                   0x143B
-#define HUAWEI_PRODUCT_E143C                   0x143C
-#define HUAWEI_PRODUCT_E143D                   0x143D
-#define HUAWEI_PRODUCT_E143E                   0x143E
-#define HUAWEI_PRODUCT_E143F                   0x143F
 #define HUAWEI_PRODUCT_K4505                   0x1464
 #define HUAWEI_PRODUCT_K3765                   0x1465
-#define HUAWEI_PRODUCT_E14AC                   0x14AC
-#define HUAWEI_PRODUCT_K3806                   0x14AE
 #define HUAWEI_PRODUCT_K4605                   0x14C6
-#define HUAWEI_PRODUCT_K5005                   0x14C8
-#define HUAWEI_PRODUCT_K3770                   0x14C9
-#define HUAWEI_PRODUCT_K3771                   0x14CA
-#define HUAWEI_PRODUCT_K4510                   0x14CB
-#define HUAWEI_PRODUCT_K4511                   0x14CC
-#define HUAWEI_PRODUCT_ETS1220                 0x1803
-#define HUAWEI_PRODUCT_E353                    0x1506
-#define HUAWEI_PRODUCT_E173S                   0x1C05
 
 #define QUANTA_VENDOR_ID                       0x0408
 #define QUANTA_PRODUCT_Q101                    0xEA02
@@ -615,104 +539,123 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) },
        { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) },
        { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) },  /* E398 3G Modem */
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) },  /* E398 3G PC UI Interface */
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) },  /* E398 3G Application Interface */
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) },
+
+
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
@@ -943,6 +886,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff),
+         .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) },
@@ -1297,8 +1242,8 @@ static struct usb_serial_driver option_1port_device = {
        .tiocmset          = usb_wwan_tiocmset,
        .ioctl             = usb_wwan_ioctl,
        .attach            = usb_wwan_startup,
-       .disconnect        = usb_wwan_disconnect,
        .release           = option_release,
+       .port_remove       = usb_wwan_port_remove,
        .read_int_callback = option_instat_callback,
 #ifdef CONFIG_PM
        .suspend           = usb_wwan_suspend,
@@ -1414,8 +1359,6 @@ static void option_release(struct usb_serial *serial)
        struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
        struct option_private *priv = intfdata->private;
 
-       usb_wwan_release(serial);
-
        kfree(priv);
        kfree(intfdata);
 }
index 8d103019d6aa529511a82070a3864ef87af44c22..bfd50779f0c9f9bf93d2f795322912caa3978f7b 100644 (file)
@@ -199,43 +199,49 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 
        /* default to enabling interface */
        altsetting = 0;
-       switch (ifnum) {
-               /* Composite mode; don't bind to the QMI/net interface as that
-                * gets handled by other drivers.
-                */
 
+       /* Composite mode; don't bind to the QMI/net interface as that
+        * gets handled by other drivers.
+        */
+
+       if (is_gobi1k) {
                /* Gobi 1K USB layout:
                 * 0: serial port (doesn't respond)
                 * 1: serial port (doesn't respond)
                 * 2: AT-capable modem port
                 * 3: QMI/net
-                *
-                * Gobi 2K+ USB layout:
+                */
+               if (ifnum == 2)
+                       dev_dbg(dev, "Modem port found\n");
+               else
+                       altsetting = -1;
+       } else {
+               /* Gobi 2K+ USB layout:
                 * 0: QMI/net
                 * 1: DM/DIAG (use libqcdm from ModemManager for communication)
                 * 2: AT-capable modem port
                 * 3: NMEA
                 */
-
-       case 1:
-               if (is_gobi1k)
+               switch (ifnum) {
+               case 0:
+                       /* Don't claim the QMI/net interface */
                        altsetting = -1;
-               else
+                       break;
+               case 1:
                        dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n");
-               break;
-       case 2:
-               dev_dbg(dev, "Modem port found\n");
-               break;
-       case 3:
-               if (is_gobi1k)
-                       altsetting = -1;
-               else
+                       break;
+               case 2:
+                       dev_dbg(dev, "Modem port found\n");
+                       break;
+               case 3:
                        /*
                         * NMEA (serial line 9600 8N1)
                         * # echo "\$GPS_START" > /dev/ttyUSBx
                         * # echo "\$GPS_STOP"  > /dev/ttyUSBx
                         */
                        dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
+                       break;
+               }
        }
 
 done:
@@ -262,8 +268,7 @@ static void qc_release(struct usb_serial *serial)
 {
        struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
 
-       /* Call usb_wwan release & free the private data allocated in qcprobe */
-       usb_wwan_release(serial);
+       /* Free the private data allocated in qcprobe */
        usb_set_serial_data(serial, NULL);
        kfree(priv);
 }
@@ -283,8 +288,8 @@ static struct usb_serial_driver qcdevice = {
        .write_room          = usb_wwan_write_room,
        .chars_in_buffer     = usb_wwan_chars_in_buffer,
        .attach              = usb_wwan_startup,
-       .disconnect          = usb_wwan_disconnect,
        .release             = qc_release,
+       .port_remove         = usb_wwan_port_remove,
 #ifdef CONFIG_PM
        .suspend             = usb_wwan_suspend,
        .resume              = usb_wwan_resume,
index c47b6ec030634f9af420987e06c33727042b4f05..1f034d2397c6c6ea3888e79aa6cd2ddb6d73202b 100644 (file)
@@ -9,8 +9,7 @@ extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on);
 extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
 extern void usb_wwan_close(struct usb_serial_port *port);
 extern int usb_wwan_startup(struct usb_serial *serial);
-extern void usb_wwan_disconnect(struct usb_serial *serial);
-extern void usb_wwan_release(struct usb_serial *serial);
+extern int usb_wwan_port_remove(struct usb_serial_port *port);
 extern int usb_wwan_write_room(struct tty_struct *tty);
 extern void usb_wwan_set_termios(struct tty_struct *tty,
                                 struct usb_serial_port *port,
index f35971dff4a5782d6c0cca563f53558043359674..6855d5ed033115473cf02e3a6f3ee73d1d5bace8 100644 (file)
@@ -565,62 +565,52 @@ bail_out_error:
 }
 EXPORT_SYMBOL(usb_wwan_startup);
 
-static void stop_read_write_urbs(struct usb_serial *serial)
+int usb_wwan_port_remove(struct usb_serial_port *port)
 {
-       int i, j;
-       struct usb_serial_port *port;
+       int i;
        struct usb_wwan_port_private *portdata;
 
-       /* Stop reading/writing urbs */
-       for (i = 0; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               portdata = usb_get_serial_port_data(port);
-               for (j = 0; j < N_IN_URB; j++)
-                       usb_kill_urb(portdata->in_urbs[j]);
-               for (j = 0; j < N_OUT_URB; j++)
-                       usb_kill_urb(portdata->out_urbs[j]);
+       portdata = usb_get_serial_port_data(port);
+       usb_set_serial_port_data(port, NULL);
+
+       /* Stop reading/writing urbs and free them */
+       for (i = 0; i < N_IN_URB; i++) {
+               usb_kill_urb(portdata->in_urbs[i]);
+               usb_free_urb(portdata->in_urbs[i]);
+               free_page((unsigned long)portdata->in_buffer[i]);
+       }
+       for (i = 0; i < N_OUT_URB; i++) {
+               usb_kill_urb(portdata->out_urbs[i]);
+               usb_free_urb(portdata->out_urbs[i]);
+               kfree(portdata->out_buffer[i]);
        }
-}
 
-void usb_wwan_disconnect(struct usb_serial *serial)
-{
-       stop_read_write_urbs(serial);
+       /* Now free port private data */
+       kfree(portdata);
+       return 0;
 }
-EXPORT_SYMBOL(usb_wwan_disconnect);
+EXPORT_SYMBOL(usb_wwan_port_remove);
 
-void usb_wwan_release(struct usb_serial *serial)
+#ifdef CONFIG_PM
+static void stop_read_write_urbs(struct usb_serial *serial)
 {
        int i, j;
        struct usb_serial_port *port;
        struct usb_wwan_port_private *portdata;
 
-       /* Now free them */
+       /* Stop reading/writing urbs */
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                portdata = usb_get_serial_port_data(port);
-
-               for (j = 0; j < N_IN_URB; j++) {
-                       usb_free_urb(portdata->in_urbs[j]);
-                       free_page((unsigned long)
-                                 portdata->in_buffer[j]);
-                       portdata->in_urbs[j] = NULL;
-               }
-               for (j = 0; j < N_OUT_URB; j++) {
-                       usb_free_urb(portdata->out_urbs[j]);
-                       kfree(portdata->out_buffer[j]);
-                       portdata->out_urbs[j] = NULL;
-               }
-       }
-
-       /* Now free per port private data */
-       for (i = 0; i < serial->num_ports; i++) {
-               port = serial->port[i];
-               kfree(usb_get_serial_port_data(port));
+               if (!portdata)
+                       continue;
+               for (j = 0; j < N_IN_URB; j++)
+                       usb_kill_urb(portdata->in_urbs[j]);
+               for (j = 0; j < N_OUT_URB; j++)
+                       usb_kill_urb(portdata->out_urbs[j]);
        }
 }
-EXPORT_SYMBOL(usb_wwan_release);
 
-#ifdef CONFIG_PM
 int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
 {
        struct usb_wwan_intf_private *intfdata = serial->private;
@@ -712,7 +702,7 @@ int usb_wwan_resume(struct usb_serial *serial)
 
                /* skip closed ports */
                spin_lock_irq(&intfdata->susp_lock);
-               if (!portdata->opened) {
+               if (!portdata || !portdata->opened) {
                        spin_unlock_irq(&intfdata->susp_lock);
                        continue;
                }
index 7691c866637be6be835442396b1f545da5a7f09c..0ae7bb64b5eacb9915ba713848a3c862989715e7 100644 (file)
@@ -213,17 +213,3 @@ config USB_UAS
          say 'Y' or 'M' here and the kernel will use the right driver.
 
          If you compile this driver as a module, it will be named uas.
-
-config USB_LIBUSUAL
-       bool "The shared table of common (or usual) storage devices"
-       depends on USB
-       help
-         This module contains a table of common (or usual) devices
-         for usb-storage and ub drivers, and allows to switch binding
-         of these devices without rebuilding modules.
-
-         Typical syntax of /etc/modprobe.d/*conf is:
-
-               options libusual bias="ub"
-
-         If unsure, say N.
index 82e6416a2d47a4686126d79d9add9b146e170e66..4cd55481b309197f73b8aa34dae0d60e6bd35382 100644 (file)
@@ -12,16 +12,9 @@ obj-$(CONFIG_USB_STORAGE)    += usb-storage.o
 
 usb-storage-y := scsiglue.o protocol.o transport.o usb.o
 usb-storage-y += initializers.o sierra_ms.o option_ms.o
-
+usb-storage-y += usual-tables.o
 usb-storage-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
 
-ifeq ($(CONFIG_USB_LIBUSUAL),)
-       usb-storage-y           += usual-tables.o
-else
-       obj-$(CONFIG_USB)       += usb-libusual.o
-       usb-libusual-y          := libusual.o usual-tables.o
-endif
-
 obj-$(CONFIG_USB_STORAGE_ALAUDA)       += ums-alauda.o
 obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o
 obj-$(CONFIG_USB_STORAGE_DATAFAB)      += ums-datafab.o
index bab8c8fe8290cfd298e6e4361b9925a1169737e4..be5564cc8e0160c466c79558ec3a57f0994418f0 100644 (file)
@@ -137,7 +137,7 @@ static int init_alauda(struct us_data *us);
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id alauda_usb_ids[] = {
 #      include "unusual_alauda.h"
index 5fe451d16e6870968ec4dbfc084d37e1e055a361..070b5c0ebbf98d0d822723c4fe04b9ee984c5bf5 100644 (file)
@@ -41,7 +41,7 @@ MODULE_LICENSE("GPL");
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id cypress_usb_ids[] = {
 #      include "unusual_cypress.h"
index 35e9c51e66962af08162b5e07022735f7470a4a4..494fee5af41d516c0a1e1e8a2b9b63e1faa6ecaf 100644 (file)
@@ -86,7 +86,7 @@ static int datafab_determine_lun(struct us_data *us,
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id datafab_usb_ids[] = {
 #      include "unusual_datafab.h"
index b28f2ad127d493aef0cdd6891d638ff8eba2f694..118b134a1dad38c970f3a459f9b8868c4002ee43 100644 (file)
 #include "protocol.h"
 #include "debug.h"
 
+#define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
+#define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
+#define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
+#define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
+#define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
+#define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
+
 MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
 MODULE_LICENSE("GPL");
-
+MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
+MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
+MODULE_FIRMWARE(SD_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_INIT_FIRMWARE);
+MODULE_FIRMWARE(MSP_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_RW_FIRMWARE);
 
 /*
  * The table of devices
@@ -40,7 +52,7 @@ MODULE_LICENSE("GPL");
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-       .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+       .driver_info = (flags)}
 
 static struct usb_device_id ene_ub6250_usb_ids[] = {
 #      include "unusual_ene_ub6250.h"
@@ -1883,28 +1895,28 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
        /* For SD */
        case SD_INIT1_PATTERN:
                US_DEBUGP("SD_INIT1_PATTERN\n");
-               fw_name = "ene-ub6250/sd_init1.bin";
+               fw_name = SD_INIT1_FIRMWARE;
                break;
        case SD_INIT2_PATTERN:
                US_DEBUGP("SD_INIT2_PATTERN\n");
-               fw_name = "ene-ub6250/sd_init2.bin";
+               fw_name = SD_INIT2_FIRMWARE;
                break;
        case SD_RW_PATTERN:
-               US_DEBUGP("SD_RDWR_PATTERN\n");
-               fw_name = "ene-ub6250/sd_rdwr.bin";
+               US_DEBUGP("SD_RW_PATTERN\n");
+               fw_name = SD_RW_FIRMWARE;
                break;
        /* For MS */
        case MS_INIT_PATTERN:
                US_DEBUGP("MS_INIT_PATTERN\n");
-               fw_name = "ene-ub6250/ms_init.bin";
+               fw_name = MS_INIT_FIRMWARE;
                break;
        case MSP_RW_PATTERN:
                US_DEBUGP("MSP_RW_PATTERN\n");
-               fw_name = "ene-ub6250/msp_rdwr.bin";
+               fw_name = MSP_RW_FIRMWARE;
                break;
        case MS_RW_PATTERN:
                US_DEBUGP("MS_RW_PATTERN\n");
-               fw_name = "ene-ub6250/ms_rdwr.bin";
+               fw_name = MS_RW_FIRMWARE;
                break;
        default:
                US_DEBUGP("----------- Unknown PATTERN ----------\n");
index 042cf9ef3153e194c7474747b8a9aa74986ab0d9..e6df087dca9d39e0910962df2eb40b2573f94115 100644 (file)
@@ -117,7 +117,7 @@ static int init_freecom(struct us_data *us);
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id freecom_usb_ids[] = {
 #      include "unusual_freecom.h"
index 31fa24e7e68ab5a4a78336fc3be7c4d140e02cb7..ecea4787736463ccda4d1a498749eed74c2c9136 100644 (file)
@@ -74,7 +74,7 @@ static int isd200_Initialization(struct us_data *us);
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id isd200_usb_ids[] = {
 #      include "unusual_isd200.h"
@@ -83,7 +83,6 @@ static struct usb_device_id isd200_usb_ids[] = {
 MODULE_DEVICE_TABLE(usb, isd200_usb_ids);
 
 #undef UNUSUAL_DEV
-#undef USUAL_DEV
 
 /*
  * The flags table
@@ -105,8 +104,6 @@ static struct us_unusual_dev isd200_unusual_dev_list[] = {
 };
 
 #undef UNUSUAL_DEV
-#undef USUAL_DEV
-
 
 /* Timeout defines (in Seconds) */
 
index e3b97383186ab2f91aaa2df87aeac6304b647259..ddc78780b1ad2a687a198281a181a57f5e0417a4 100644 (file)
@@ -69,7 +69,7 @@ MODULE_LICENSE("GPL");
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id jumpshot_usb_ids[] = {
 #      include "unusual_jumpshot.h"
index a8708eae9788eb5cd3104a0b50369fb299d3f58a..f085ffb606c88e9c199dadb81448c2740c4f68a6 100644 (file)
@@ -57,7 +57,7 @@ static int rio_karma_init(struct us_data *us);
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id karma_usb_ids[] = {
 #      include "unusual_karma.h"
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
deleted file mode 100644 (file)
index fe3ffe1..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * libusual
- *
- * The libusual contains the table of devices common for ub and usb-storage.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb_usual.h>
-#include <linux/vmalloc.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-
-/*
- */
-#define USU_MOD_FL_THREAD   1  /* Thread is running */
-#define USU_MOD_FL_PRESENT  2  /* The module is loaded */
-
-struct mod_status {
-       unsigned long fls;
-};
-
-static struct mod_status stat[3];
-static DEFINE_SPINLOCK(usu_lock);
-
-/*
- */
-#define USB_US_DEFAULT_BIAS    USB_US_TYPE_STOR
-static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS);
-
-#define BIAS_NAME_SIZE  (sizeof("usb-storage"))
-static const char *bias_names[3] = { "none", "usb-storage", "ub" };
-
-static DEFINE_MUTEX(usu_probe_mutex);
-static DECLARE_COMPLETION(usu_end_notify);
-static atomic_t total_threads = ATOMIC_INIT(0);
-
-static int usu_probe_thread(void *arg);
-
-/*
- * @type: the module type as an integer
- */
-void usb_usual_set_present(int type)
-{
-       struct mod_status *st;
-       unsigned long flags;
-
-       if (type <= 0 || type >= 3)
-               return;
-       st = &stat[type];
-       spin_lock_irqsave(&usu_lock, flags);
-       st->fls |= USU_MOD_FL_PRESENT;
-       spin_unlock_irqrestore(&usu_lock, flags);
-}
-EXPORT_SYMBOL_GPL(usb_usual_set_present);
-
-void usb_usual_clear_present(int type)
-{
-       struct mod_status *st;
-       unsigned long flags;
-
-       if (type <= 0 || type >= 3)
-               return;
-       st = &stat[type];
-       spin_lock_irqsave(&usu_lock, flags);
-       st->fls &= ~USU_MOD_FL_PRESENT;
-       spin_unlock_irqrestore(&usu_lock, flags);
-}
-EXPORT_SYMBOL_GPL(usb_usual_clear_present);
-
-/*
- * Match the calling driver type against the table.
- * Returns: 0 if the device matches.
- */
-int usb_usual_check_type(const struct usb_device_id *id, int caller_type)
-{
-       int id_type = USB_US_TYPE(id->driver_info);
-
-       if (caller_type <= 0 || caller_type >= 3)
-               return -EINVAL;
-
-       /* Drivers grab fixed assignment devices */
-       if (id_type == caller_type)
-               return 0;
-       /* Drivers grab devices biased to them */
-       if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias))
-               return 0;
-       return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(usb_usual_check_type);
-
-/*
- */
-static int usu_probe(struct usb_interface *intf,
-                        const struct usb_device_id *id)
-{
-       int rc;
-       unsigned long type;
-       struct task_struct* task;
-       unsigned long flags;
-
-       type = USB_US_TYPE(id->driver_info);
-       if (type == 0)
-               type = atomic_read(&usu_bias);
-
-       spin_lock_irqsave(&usu_lock, flags);
-       if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) {
-               spin_unlock_irqrestore(&usu_lock, flags);
-               return -ENXIO;
-       }
-       stat[type].fls |= USU_MOD_FL_THREAD;
-       spin_unlock_irqrestore(&usu_lock, flags);
-
-       task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
-       if (IS_ERR(task)) {
-               rc = PTR_ERR(task);
-               printk(KERN_WARNING "libusual: "
-                   "Unable to start the thread for %s: %d\n",
-                   bias_names[type], rc);
-               spin_lock_irqsave(&usu_lock, flags);
-               stat[type].fls &= ~USU_MOD_FL_THREAD;
-               spin_unlock_irqrestore(&usu_lock, flags);
-               return rc;      /* Not being -ENXIO causes a message printed */
-       }
-       atomic_inc(&total_threads);
-
-       return -ENXIO;
-}
-
-static void usu_disconnect(struct usb_interface *intf)
-{
-       ;       /* We should not be here. */
-}
-
-static struct usb_driver usu_driver = {
-       .name =         "libusual",
-       .probe =        usu_probe,
-       .disconnect =   usu_disconnect,
-       .id_table =     usb_storage_usb_ids,
-};
-
-/*
- * A whole new thread for a purpose of request_module seems quite stupid.
- * The request_module forks once inside again. However, if we attempt
- * to load a storage module from our own modprobe thread, that module
- * references our symbols, which cannot be resolved until our module is
- * initialized. I wish there was a way to wait for the end of initialization.
- * The module notifier reports MODULE_STATE_COMING only.
- * So, we wait until module->init ends as the next best thing.
- */
-static int usu_probe_thread(void *arg)
-{
-       int type = (unsigned long) arg;
-       struct mod_status *st = &stat[type];
-       int rc;
-       unsigned long flags;
-
-       mutex_lock(&usu_probe_mutex);
-       rc = request_module(bias_names[type]);
-       spin_lock_irqsave(&usu_lock, flags);
-       if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) {
-               /*
-                * This should not happen, but let us keep tabs on it.
-                */
-               printk(KERN_NOTICE "libusual: "
-                   "modprobe for %s succeeded, but module is not present\n",
-                   bias_names[type]);
-       }
-       st->fls &= ~USU_MOD_FL_THREAD;
-       spin_unlock_irqrestore(&usu_lock, flags);
-       mutex_unlock(&usu_probe_mutex);
-
-       complete_and_exit(&usu_end_notify, 0);
-}
-
-/*
- */
-static int __init usb_usual_init(void)
-{
-       int rc;
-
-       mutex_lock(&usu_probe_mutex);
-       rc = usb_register(&usu_driver);
-       mutex_unlock(&usu_probe_mutex);
-       return rc;
-}
-
-static void __exit usb_usual_exit(void)
-{
-       /*
-        * We do not check for any drivers present, because
-        * they keep us pinned with symbol references.
-        */
-
-       usb_deregister(&usu_driver);
-
-       while (atomic_read(&total_threads) > 0) {
-               wait_for_completion(&usu_end_notify);
-               atomic_dec(&total_threads);
-       }
-}
-
-/*
- * Validate and accept the bias parameter.
- */
-static int usu_set_bias(const char *bias_s, struct kernel_param *kp)
-{
-       int i;
-       int len;
-       int bias_n = 0;
-
-       len = strlen(bias_s);
-       if (len == 0)
-               return -EDOM;
-       if (bias_s[len-1] == '\n')
-               --len;
-
-       for (i = 1; i < 3; i++) {
-               if (strncmp(bias_s, bias_names[i], len) == 0) {
-                       bias_n = i;
-                       break;
-               }
-       }
-       if (bias_n == 0)
-               return -EINVAL;
-
-       atomic_set(&usu_bias, bias_n);
-       return 0;
-}
-
-static int usu_get_bias(char *buffer, struct kernel_param *kp)
-{
-       return strlen(strcpy(buffer, bias_names[atomic_read(&usu_bias)]));
-}
-
-module_init(usb_usual_init);
-module_exit(usb_usual_exit);
-
-module_param_call(bias, usu_set_bias, usu_get_bias, NULL, S_IRUGO|S_IWUSR);
-__MODULE_PARM_TYPE(bias, "string");
-MODULE_PARM_DESC(bias, "Bias to usb-storage or ub");
-
-MODULE_LICENSE("GPL");
index 886567a3806ddd5d190dfb253dabc6afc44e1ea9..cb79de61f4c837e191e1e8de0616e9b06d33d5fe 100644 (file)
@@ -67,7 +67,7 @@ struct usb_onetouch {
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id onetouch_usb_ids[] = {
 #      include "unusual_onetouch.h"
index 63cf2822e299a6213164feb3a9d426e6ff40ee4a..d36446dd7ae867629258b9051b3c1173cde9641f 100644 (file)
@@ -172,7 +172,7 @@ static int init_realtek_cr(struct us_data *us);
                    initFunction, flags) \
 {\
        USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-       .driver_info = (flags)|(USB_US_TYPE_STOR<<24)\
+       .driver_info = (flags) \
 }
 
 static const struct usb_device_id realtek_cr_ids[] = {
index 3252a62b31bcaeb21824ec80323572fe10d0de28..7bd54e0d5120cdaf0dba96fff1928c4380ba4631 100644 (file)
@@ -69,7 +69,7 @@ static int usb_stor_sddr09_init(struct us_data *us);
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id sddr09_usb_ids[] = {
 #      include "unusual_sddr09.h"
index c144078065a7f691ce3f1e1c57f2d0244510a724..d278c5a99b7a253a49ba6b2d09ba2abac88bd5e4 100644 (file)
@@ -46,7 +46,7 @@ MODULE_LICENSE("GPL");
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id sddr55_usb_ids[] = {
 #      include "unusual_sddr55.h"
index fa1ceebc465ce434a28167bb3c5f633a3e48645b..daf2fc58ae0203857b5b198327d7f9a917214c98 100644 (file)
@@ -168,7 +168,7 @@ static int init_usbat_flash(struct us_data *us);
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+  .driver_info = (flags) }
 
 static struct usb_device_id usbat_usb_ids[] = {
 #      include "unusual_usbat.h"
index c70109e5d60bb0f409df74187e3dabc5a53f4979..c0543c83923e30fab82b82698471d200ec1be47d 100644 (file)
@@ -1331,7 +1331,7 @@ int usb_stor_port_reset(struct us_data *us)
        int result;
 
        /*for these devices we must use the class specific method */
-       if (us->pusb_dev->quirks & USB_QUIRK_RESET_MORPHS)
+       if (us->pusb_dev->quirks & USB_QUIRK_RESET)
                return -EPERM;
 
        result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
index 62a31bea06346b0900fafec5e2d832188e66b860..779cd954abcbd26d1fc935650d102dc524b8ca5a 100644 (file)
@@ -2038,25 +2038,25 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
 
 /* Control/Bulk transport for all SubClass values */
-USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_QIC, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_UFI, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8070, USB_PR_CB, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_SCSI, USB_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(USB_SC_RBC, USB_PR_CB),
+USUAL_DEV(USB_SC_8020, USB_PR_CB),
+USUAL_DEV(USB_SC_QIC, USB_PR_CB),
+USUAL_DEV(USB_SC_UFI, USB_PR_CB),
+USUAL_DEV(USB_SC_8070, USB_PR_CB),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CB),
 
 /* Control/Bulk/Interrupt transport for all SubClass values */
-USUAL_DEV(USB_SC_RBC, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8020, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_QIC, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_UFI, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8070, USB_PR_CBI, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_SCSI, USB_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(USB_SC_RBC, USB_PR_CBI),
+USUAL_DEV(USB_SC_8020, USB_PR_CBI),
+USUAL_DEV(USB_SC_QIC, USB_PR_CBI),
+USUAL_DEV(USB_SC_UFI, USB_PR_CBI),
+USUAL_DEV(USB_SC_8070, USB_PR_CBI),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CBI),
 
 /* Bulk-only transport for all SubClass values */
-USUAL_DEV(USB_SC_RBC, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8020, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_QIC, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_UFI, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_8070, USB_PR_BULK, USB_US_TYPE_STOR),
-USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0),
+USUAL_DEV(USB_SC_RBC, USB_PR_BULK),
+USUAL_DEV(USB_SC_8020, USB_PR_BULK),
+USUAL_DEV(USB_SC_QIC, USB_PR_BULK),
+USUAL_DEV(USB_SC_UFI, USB_PR_BULK),
+USUAL_DEV(USB_SC_8070, USB_PR_BULK),
+USUAL_DEV(USB_SC_SCSI, USB_PR_BULK),
index d012fe4329e7a36660d23f46195bdb86f511f21e..12aa72630aedbb7f88e4cb40b5eb233fae828f72 100644 (file)
@@ -114,7 +114,7 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
 
 #define COMPLIANT_DEV  UNUSUAL_DEV
 
-#define USUAL_DEV(use_protocol, use_transport, use_type) \
+#define USUAL_DEV(use_protocol, use_transport) \
 { \
        .useProtocol = use_protocol,    \
        .useTransport = use_transport,  \
@@ -126,7 +126,7 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
 };
 
 static struct us_unusual_dev for_dynamic_ids =
-               USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
+               USUAL_DEV(USB_SC_SCSI, USB_PR_BULK);
 
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
@@ -564,7 +564,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id,
        us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ?
                        idesc->bInterfaceProtocol :
                        unusual_dev->useTransport;
-       us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
+       us->fflags = id->driver_info;
        adjust_quirks(us);
 
        if (us->fflags & US_FL_IGNORE_DEVICE) {
@@ -1041,13 +1041,10 @@ static int storage_probe(struct usb_interface *intf,
        int size;
 
        /*
-        * If libusual is configured, let it decide whether a standard
-        * device should be handled by usb-storage or by ub.
         * If the device isn't standard (is handled by a subdriver
         * module) then don't accept it.
         */
-       if (usb_usual_check_type(id, USB_US_TYPE_STOR) ||
-                       usb_usual_ignore_device(intf))
+       if (usb_usual_ignore_device(intf))
                return -ENXIO;
 
        /*
@@ -1105,10 +1102,8 @@ static int __init usb_stor_init(void)
 
        /* register the driver, return usb_register return code if error */
        retval = usb_register(&usb_storage_driver);
-       if (retval == 0) {
+       if (retval == 0)
                pr_info("USB Mass Storage support registered.\n");
-               usb_usual_set_present(USB_US_TYPE_STOR);
-       }
        return retval;
 }
 
@@ -1122,8 +1117,6 @@ static void __exit usb_stor_exit(void)
         */
        US_DEBUGP("-- calling usb_deregister()\n");
        usb_deregister(&usb_storage_driver) ;
-
-       usb_usual_clear_present(USB_US_TYPE_STOR);
 }
 
 module_init(usb_stor_init);
index b96927914f89098bc00119d1338fb381368ea687..b78a526910fb31ac257a13800c593236c0e21a27 100644 (file)
 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
                    vendorName, productName, useProtocol, useTransport, \
                    initFunction, flags) \
-{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
-
-#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
-                   vendorName, productName, useProtocol, useTransport, \
-                   initFunction, flags) \
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags) }
 
-#define USUAL_DEV(useProto, useTrans, useType) \
-{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
-  .driver_info = ((useType)<<24) }
+#define COMPLIANT_DEV  UNUSUAL_DEV
+
+#define USUAL_DEV(useProto, useTrans) \
+{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) }
 
 struct usb_device_id usb_storage_usb_ids[] = {
 #      include "unusual_devs.h"
        { }             /* Terminating entry */
 };
-EXPORT_SYMBOL_GPL(usb_storage_usb_ids);
-
 MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);
 
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
 #undef USUAL_DEV
 
-
 /*
  * The table of devices to ignore
  */
@@ -95,7 +87,6 @@ static struct ignore_entry ignore_ids[] = {
 
 #undef UNUSUAL_DEV
 
-
 /* Return an error if a device is in the ignore_ids list */
 int usb_usual_ignore_device(struct usb_interface *intf)
 {
@@ -115,4 +106,3 @@ int usb_usual_ignore_device(struct usb_interface *intf)
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(usb_usual_ignore_device);
index fa810a83e8300957c72de584ab3f3fcd1e31a29a..dd88441c8f7891e0d242e1107d6ff585a30999e4 100644 (file)
@@ -202,7 +202,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
 {
        int result, bytes, secd_size;
        struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor *secd;
+       struct usb_security_descriptor *secd, *new_secd;
        const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
        const void *itr, *top;
        char buf[64];
@@ -221,11 +221,12 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
                goto out;
        }
        secd_size = le16_to_cpu(secd->wTotalLength);
-       secd = krealloc(secd, secd_size, GFP_KERNEL);
-       if (secd == NULL) {
+       new_secd = krealloc(secd, secd_size, GFP_KERNEL);
+       if (new_secd == NULL) {
                dev_err(dev, "Can't allocate space for security descriptors\n");
                goto out;
        }
+       secd = new_secd;
        result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
                                    0, secd, secd_size);
        if (result < secd_size) {
index 9e4a924616884d7152497bb465e67c1c2167b2bb..a09b65ebd9bb712d02060e760ff2c349bcdc2e77 100644 (file)
@@ -46,8 +46,10 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)
        wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
        wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd);
        wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL);
-       if (wa->xfer_result == NULL)
+       if (wa->xfer_result == NULL) {
+               result = -ENOMEM;
                goto error_xfer_result_alloc;
+       }
        result = wa_nep_create(wa, iface);
        if (result < 0) {
                dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
index 9591e2b509d794e93e596fe8f2c1da8c11691205..17830c9c7cc623b7b26cdac7568aca508f7251e7 100644 (file)
@@ -264,6 +264,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
        return group;
 }
 
+/* called with vfio.group_lock held */
 static void vfio_group_release(struct kref *kref)
 {
        struct vfio_group *group = container_of(kref, struct vfio_group, kref);
@@ -287,13 +288,7 @@ static void vfio_group_release(struct kref *kref)
 
 static void vfio_group_put(struct vfio_group *group)
 {
-       mutex_lock(&vfio.group_lock);
-       /*
-        * Release needs to unlock to unregister the notifier, so only
-        * unlock if not released.
-        */
-       if (!kref_put(&group->kref, vfio_group_release))
-               mutex_unlock(&vfio.group_lock);
+       kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock);
 }
 
 /* Assume group_lock or group reference is held */
@@ -401,7 +396,6 @@ static void vfio_device_release(struct kref *kref)
                                                  struct vfio_device, kref);
        struct vfio_group *group = device->group;
 
-       mutex_lock(&group->device_lock);
        list_del(&device->group_next);
        mutex_unlock(&group->device_lock);
 
@@ -416,8 +410,9 @@ static void vfio_device_release(struct kref *kref)
 /* Device reference always implies a group reference */
 static void vfio_device_put(struct vfio_device *device)
 {
-       kref_put(&device->kref, vfio_device_release);
-       vfio_group_put(device->group);
+       struct vfio_group *group = device->group;
+       kref_put_mutex(&device->kref, vfio_device_release, &group->device_lock);
+       vfio_group_put(group);
 }
 
 static void vfio_device_get(struct vfio_device *device)
@@ -1116,10 +1111,10 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
                 */
                filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
 
-               fd_install(ret, filep);
-
                vfio_device_get(device);
                atomic_inc(&group->container_users);
+
+               fd_install(ret, filep);
                break;
        }
        mutex_unlock(&group->device_lock);
index e4e2fd1b51076dfbc8ffc73920ac148d830c4d4f..202bba6c997cce61eb116fc74db8e842454ce1f4 100644 (file)
@@ -9,3 +9,6 @@ config VHOST_NET
          To compile this driver as a module, choose M here: the module will
          be called vhost_net.
 
+if STAGING
+source "drivers/vhost/Kconfig.tcm"
+endif
diff --git a/drivers/vhost/Kconfig.tcm b/drivers/vhost/Kconfig.tcm
new file mode 100644 (file)
index 0000000..a9c6f76
--- /dev/null
@@ -0,0 +1,6 @@
+config TCM_VHOST
+       tristate "TCM_VHOST fabric module (EXPERIMENTAL)"
+       depends on TARGET_CORE && EVENTFD && EXPERIMENTAL && m
+       default n
+       ---help---
+       Say M here to enable the TCM_VHOST fabric module for use with virtio-scsi guests
index 72dd02050bb986cf6d426828f64ea521aaff3284..a27b053bc9ab12d546c9f17bee106a916eb5e236 100644 (file)
@@ -1,2 +1,4 @@
 obj-$(CONFIG_VHOST_NET) += vhost_net.o
 vhost_net-y := vhost.o net.o
+
+obj-$(CONFIG_TCM_VHOST) += tcm_vhost.o
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
new file mode 100644 (file)
index 0000000..ed8e2e6
--- /dev/null
@@ -0,0 +1,1649 @@
+/*******************************************************************************
+ * Vhost kernel TCM fabric driver for virtio SCSI initiators
+ *
+ * (C) Copyright 2010-2012 RisingTide Systems LLC.
+ * (C) Copyright 2010-2012 IBM Corp.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Authors: Nicholas A. Bellinger <nab@risingtidesystems.com>
+ *          Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */
+#include <linux/virtio_scsi.h>
+
+#include "vhost.c"
+#include "vhost.h"
+#include "tcm_vhost.h"
+
+enum {
+       VHOST_SCSI_VQ_CTL = 0,
+       VHOST_SCSI_VQ_EVT = 1,
+       VHOST_SCSI_VQ_IO = 2,
+};
+
+struct vhost_scsi {
+       struct tcm_vhost_tpg *vs_tpg;   /* Protected by vhost_scsi->dev.mutex */
+       struct vhost_dev dev;
+       struct vhost_virtqueue vqs[3];
+
+       struct vhost_work vs_completion_work; /* cmd completion work item */
+       struct list_head vs_completion_list;  /* cmd completion queue */
+       spinlock_t vs_completion_lock;        /* protects s_completion_list */
+};
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *tcm_vhost_fabric_configfs;
+
+static struct workqueue_struct *tcm_vhost_workqueue;
+
+/* Global spinlock to protect tcm_vhost TPG list for vhost IOCTL access */
+static DEFINE_MUTEX(tcm_vhost_mutex);
+static LIST_HEAD(tcm_vhost_list);
+
+static int tcm_vhost_check_true(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int tcm_vhost_check_false(struct se_portal_group *se_tpg)
+{
+       return 0;
+}
+
+static char *tcm_vhost_get_fabric_name(void)
+{
+       return "vhost";
+}
+
+static u8 tcm_vhost_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_fabric_proto_ident(se_tpg);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_fabric_proto_ident(se_tpg);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_fabric_proto_ident(se_tpg);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_fabric_proto_ident(se_tpg);
+}
+
+static char *tcm_vhost_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       return &tport->tport_name[0];
+}
+
+static u16 tcm_vhost_get_tag(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       return tpg->tport_tpgt;
+}
+
+static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static u32 tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl,
+       struct t10_pr_registration *pr_reg,
+       int *format_code,
+       unsigned char *buf)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                       format_code, buf);
+}
+
+static u32 tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl,
+       struct t10_pr_registration *pr_reg,
+       int *format_code)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                       format_code);
+}
+
+static char *tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+       const char *buf,
+       u32 *out_tid_len,
+       char **port_nexus_ptr)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       case SCSI_PROTOCOL_FCP:
+               return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                       port_nexus_ptr);
+}
+
+static struct se_node_acl *tcm_vhost_alloc_fabric_acl(
+       struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_nacl *nacl;
+
+       nacl = kzalloc(sizeof(struct tcm_vhost_nacl), GFP_KERNEL);
+       if (!nacl) {
+               pr_err("Unable to alocate struct tcm_vhost_nacl\n");
+               return NULL;
+       }
+
+       return &nacl->se_node_acl;
+}
+
+static void tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl)
+{
+       struct tcm_vhost_nacl *nacl = container_of(se_nacl,
+                       struct tcm_vhost_nacl, se_node_acl);
+       kfree(nacl);
+}
+
+static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
+{
+       return;
+}
+
+static int tcm_vhost_shutdown_session(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static void tcm_vhost_close_session(struct se_session *se_sess)
+{
+       return;
+}
+
+static u32 tcm_vhost_sess_get_index(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static int tcm_vhost_write_pending(struct se_cmd *se_cmd)
+{
+       /* Go ahead and process the write immediately */
+       target_execute_cmd(se_cmd);
+       return 0;
+}
+
+static int tcm_vhost_write_pending_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void tcm_vhost_set_default_node_attrs(struct se_node_acl *nacl)
+{
+       return;
+}
+
+static u32 tcm_vhost_get_task_tag(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd)
+{
+       struct vhost_scsi *vs = tv_cmd->tvc_vhost;
+
+       spin_lock_bh(&vs->vs_completion_lock);
+       list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list);
+       spin_unlock_bh(&vs->vs_completion_lock);
+
+       vhost_work_queue(&vs->dev, &vs->vs_completion_work);
+}
+
+static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd)
+{
+       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+                               struct tcm_vhost_cmd, tvc_se_cmd);
+       vhost_scsi_complete_cmd(tv_cmd);
+       return 0;
+}
+
+static int tcm_vhost_queue_status(struct se_cmd *se_cmd)
+{
+       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+                               struct tcm_vhost_cmd, tvc_se_cmd);
+       vhost_scsi_complete_cmd(tv_cmd);
+       return 0;
+}
+
+static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static u16 tcm_vhost_set_fabric_sense_len(struct se_cmd *se_cmd,
+       u32 sense_length)
+{
+       return 0;
+}
+
+static u16 tcm_vhost_get_fabric_sense_len(void)
+{
+       return 0;
+}
+
+static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
+{
+       struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+
+       /* TODO locking against target/backend threads? */
+       transport_generic_free_cmd(se_cmd, 1);
+
+       if (tv_cmd->tvc_sgl_count) {
+               u32 i;
+               for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
+                       put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+
+               kfree(tv_cmd->tvc_sgl);
+       }
+
+       kfree(tv_cmd);
+}
+
+/* Dequeue a command from the completion list */
+static struct tcm_vhost_cmd *vhost_scsi_get_cmd_from_completion(
+       struct vhost_scsi *vs)
+{
+       struct tcm_vhost_cmd *tv_cmd = NULL;
+
+       spin_lock_bh(&vs->vs_completion_lock);
+       if (list_empty(&vs->vs_completion_list)) {
+               spin_unlock_bh(&vs->vs_completion_lock);
+               return NULL;
+       }
+
+       list_for_each_entry(tv_cmd, &vs->vs_completion_list,
+                           tvc_completion_list) {
+               list_del(&tv_cmd->tvc_completion_list);
+               break;
+       }
+       spin_unlock_bh(&vs->vs_completion_lock);
+       return tv_cmd;
+}
+
+/* Fill in status and signal that we are done processing this command
+ *
+ * This is scheduled in the vhost work queue so we are called with the owner
+ * process mm and can access the vring.
+ */
+static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
+{
+       struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
+                                       vs_completion_work);
+       struct tcm_vhost_cmd *tv_cmd;
+
+       while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs))) {
+               struct virtio_scsi_cmd_resp v_rsp;
+               struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+               int ret;
+
+               pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
+                       tv_cmd, se_cmd->residual_count, se_cmd->scsi_status);
+
+               memset(&v_rsp, 0, sizeof(v_rsp));
+               v_rsp.resid = se_cmd->residual_count;
+               /* TODO is status_qualifier field needed? */
+               v_rsp.status = se_cmd->scsi_status;
+               v_rsp.sense_len = se_cmd->scsi_sense_length;
+               memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf,
+                      v_rsp.sense_len);
+               ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
+               if (likely(ret == 0))
+                       vhost_add_used(&vs->vqs[2], tv_cmd->tvc_vq_desc, 0);
+               else
+                       pr_err("Faulted on virtio_scsi_cmd_resp\n");
+
+               vhost_scsi_free_cmd(tv_cmd);
+       }
+
+       vhost_signal(&vs->dev, &vs->vqs[2]);
+}
+
+static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
+       struct tcm_vhost_tpg *tv_tpg,
+       struct virtio_scsi_cmd_req *v_req,
+       u32 exp_data_len,
+       int data_direction)
+{
+       struct tcm_vhost_cmd *tv_cmd;
+       struct tcm_vhost_nexus *tv_nexus;
+       struct se_portal_group *se_tpg = &tv_tpg->se_tpg;
+       struct se_session *se_sess;
+       struct se_cmd *se_cmd;
+       int sam_task_attr;
+
+       tv_nexus = tv_tpg->tpg_nexus;
+       if (!tv_nexus) {
+               pr_err("Unable to locate active struct tcm_vhost_nexus\n");
+               return ERR_PTR(-EIO);
+       }
+       se_sess = tv_nexus->tvn_se_sess;
+
+       tv_cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
+       if (!tv_cmd) {
+               pr_err("Unable to allocate struct tcm_vhost_cmd\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_LIST_HEAD(&tv_cmd->tvc_completion_list);
+       tv_cmd->tvc_tag = v_req->tag;
+
+       se_cmd = &tv_cmd->tvc_se_cmd;
+       /*
+        * Locate the SAM Task Attr from virtio_scsi_cmd_req
+        */
+       sam_task_attr = v_req->task_attr;
+       /*
+        * Initialize struct se_cmd descriptor from TCM infrastructure
+        */
+       transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, exp_data_len,
+                               data_direction, sam_task_attr,
+                               &tv_cmd->tvc_sense_buf[0]);
+
+#if 0  /* FIXME: vhost_scsi_allocate_cmd() BIDI operation */
+       if (bidi)
+               se_cmd->se_cmd_flags |= SCF_BIDI;
+#endif
+       return tv_cmd;
+}
+
+/*
+ * Map a user memory range into a scatterlist
+ *
+ * Returns the number of scatterlist entries used or -errno on error.
+ */
+static int vhost_scsi_map_to_sgl(struct scatterlist *sgl,
+       unsigned int sgl_count, void __user *ptr, size_t len, int write)
+{
+       struct scatterlist *sg = sgl;
+       unsigned int npages = 0;
+       int ret;
+
+       while (len > 0) {
+               struct page *page;
+               unsigned int offset = (uintptr_t)ptr & ~PAGE_MASK;
+               unsigned int nbytes = min_t(unsigned int,
+                               PAGE_SIZE - offset, len);
+
+               if (npages == sgl_count) {
+                       ret = -ENOBUFS;
+                       goto err;
+               }
+
+               ret = get_user_pages_fast((unsigned long)ptr, 1, write, &page);
+               BUG_ON(ret == 0); /* we should either get our page or fail */
+               if (ret < 0)
+                       goto err;
+
+               sg_set_page(sg, page, nbytes, offset);
+               ptr += nbytes;
+               len -= nbytes;
+               sg++;
+               npages++;
+       }
+       return npages;
+
+err:
+       /* Put pages that we hold */
+       for (sg = sgl; sg != &sgl[npages]; sg++)
+               put_page(sg_page(sg));
+       return ret;
+}
+
+static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
+       struct iovec *iov, unsigned int niov, int write)
+{
+       int ret;
+       unsigned int i;
+       u32 sgl_count;
+       struct scatterlist *sg;
+
+       /*
+        * Find out how long sglist needs to be
+        */
+       sgl_count = 0;
+       for (i = 0; i < niov; i++) {
+               sgl_count += (((uintptr_t)iov[i].iov_base + iov[i].iov_len +
+                               PAGE_SIZE - 1) >> PAGE_SHIFT) -
+                               ((uintptr_t)iov[i].iov_base >> PAGE_SHIFT);
+       }
+       /* TODO overflow checking */
+
+       sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
+       if (!sg)
+               return -ENOMEM;
+       pr_debug("%s sg %p sgl_count %u is_err %d\n", __func__,
+              sg, sgl_count, !sg);
+       sg_init_table(sg, sgl_count);
+
+       tv_cmd->tvc_sgl = sg;
+       tv_cmd->tvc_sgl_count = sgl_count;
+
+       pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
+       for (i = 0; i < niov; i++) {
+               ret = vhost_scsi_map_to_sgl(sg, sgl_count, iov[i].iov_base,
+                                       iov[i].iov_len, write);
+               if (ret < 0) {
+                       for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
+                               put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+                       kfree(tv_cmd->tvc_sgl);
+                       tv_cmd->tvc_sgl = NULL;
+                       tv_cmd->tvc_sgl_count = 0;
+                       return ret;
+               }
+
+               sg += ret;
+               sgl_count -= ret;
+       }
+       return 0;
+}
+
+static void tcm_vhost_submission_work(struct work_struct *work)
+{
+       struct tcm_vhost_cmd *tv_cmd =
+               container_of(work, struct tcm_vhost_cmd, work);
+       struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+       struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
+       int rc, sg_no_bidi = 0;
+       /*
+        * Locate the struct se_lun pointer based on v_req->lun, and
+        * attach it to struct se_cmd
+        */
+       rc = transport_lookup_cmd_lun(&tv_cmd->tvc_se_cmd, tv_cmd->tvc_lun);
+       if (rc < 0) {
+               pr_err("Failed to look up lun: %d\n", tv_cmd->tvc_lun);
+               transport_send_check_condition_and_sense(&tv_cmd->tvc_se_cmd,
+                       tv_cmd->tvc_se_cmd.scsi_sense_reason, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       }
+
+       rc = target_setup_cmd_from_cdb(se_cmd, tv_cmd->tvc_cdb);
+       if (rc == -ENOMEM) {
+               transport_send_check_condition_and_sense(se_cmd,
+                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       } else if (rc < 0) {
+               if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
+                       tcm_vhost_queue_status(se_cmd);
+               else
+                       transport_send_check_condition_and_sense(se_cmd,
+                                       se_cmd->scsi_sense_reason, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       }
+
+       if (tv_cmd->tvc_sgl_count) {
+               sg_ptr = tv_cmd->tvc_sgl;
+               /*
+                * For BIDI commands, pass in the extra READ buffer
+                * to transport_generic_map_mem_to_cmd() below..
+                */
+/* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */
+#if 0
+               if (se_cmd->se_cmd_flags & SCF_BIDI) {
+                       sg_bidi_ptr = NULL;
+                       sg_no_bidi = 0;
+               }
+#endif
+       } else {
+               sg_ptr = NULL;
+       }
+
+       rc = transport_generic_map_mem_to_cmd(se_cmd, sg_ptr,
+                               tv_cmd->tvc_sgl_count, sg_bidi_ptr,
+                               sg_no_bidi);
+       if (rc < 0) {
+               transport_send_check_condition_and_sense(se_cmd,
+                               se_cmd->scsi_sense_reason, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       }
+       transport_handle_cdb_direct(se_cmd);
+}
+
+static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
+{
+       struct vhost_virtqueue *vq = &vs->vqs[2];
+       struct virtio_scsi_cmd_req v_req;
+       struct tcm_vhost_tpg *tv_tpg;
+       struct tcm_vhost_cmd *tv_cmd;
+       u32 exp_data_len, data_first, data_num, data_direction;
+       unsigned out, in, i;
+       int head, ret;
+
+       /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */
+       tv_tpg = vs->vs_tpg;
+       if (unlikely(!tv_tpg)) {
+               pr_err("%s endpoint not set\n", __func__);
+               return;
+       }
+
+       mutex_lock(&vq->mutex);
+       vhost_disable_notify(&vs->dev, vq);
+
+       for (;;) {
+               head = vhost_get_vq_desc(&vs->dev, vq, vq->iov,
+                                       ARRAY_SIZE(vq->iov), &out, &in,
+                                       NULL, NULL);
+               pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
+                                       head, out, in);
+               /* On error, stop handling until the next kick. */
+               if (unlikely(head < 0))
+                       break;
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (head == vq->num) {
+                       if (unlikely(vhost_enable_notify(&vs->dev, vq))) {
+                               vhost_disable_notify(&vs->dev, vq);
+                               continue;
+                       }
+                       break;
+               }
+
+/* FIXME: BIDI operation */
+               if (out == 1 && in == 1) {
+                       data_direction = DMA_NONE;
+                       data_first = 0;
+                       data_num = 0;
+               } else if (out == 1 && in > 1) {
+                       data_direction = DMA_FROM_DEVICE;
+                       data_first = out + 1;
+                       data_num = in - 1;
+               } else if (out > 1 && in == 1) {
+                       data_direction = DMA_TO_DEVICE;
+                       data_first = 1;
+                       data_num = out - 1;
+               } else {
+                       vq_err(vq, "Invalid buffer layout out: %u in: %u\n",
+                                       out, in);
+                       break;
+               }
+
+               /*
+                * Check for a sane resp buffer so we can report errors to
+                * the guest.
+                */
+               if (unlikely(vq->iov[out].iov_len !=
+                                       sizeof(struct virtio_scsi_cmd_resp))) {
+                       vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
+                               " bytes\n", vq->iov[out].iov_len);
+                       break;
+               }
+
+               if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) {
+                       vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu"
+                               " bytes\n", vq->iov[0].iov_len);
+                       break;
+               }
+               pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p,"
+                       " len: %zu\n", vq->iov[0].iov_base, sizeof(v_req));
+               ret = __copy_from_user(&v_req, vq->iov[0].iov_base,
+                               sizeof(v_req));
+               if (unlikely(ret)) {
+                       vq_err(vq, "Faulted on virtio_scsi_cmd_req\n");
+                       break;
+               }
+
+               exp_data_len = 0;
+               for (i = 0; i < data_num; i++)
+                       exp_data_len += vq->iov[data_first + i].iov_len;
+
+               tv_cmd = vhost_scsi_allocate_cmd(tv_tpg, &v_req,
+                                       exp_data_len, data_direction);
+               if (IS_ERR(tv_cmd)) {
+                       vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n",
+                                       PTR_ERR(tv_cmd));
+                       break;
+               }
+               pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
+                       ": %d\n", tv_cmd, exp_data_len, data_direction);
+
+               tv_cmd->tvc_vhost = vs;
+
+               if (unlikely(vq->iov[out].iov_len !=
+                               sizeof(struct virtio_scsi_cmd_resp))) {
+                       vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
+                               " bytes, out: %d, in: %d\n",
+                               vq->iov[out].iov_len, out, in);
+                       break;
+               }
+
+               tv_cmd->tvc_resp = vq->iov[out].iov_base;
+
+               /*
+                * Copy in the recieved CDB descriptor into tv_cmd->tvc_cdb
+                * that will be used by tcm_vhost_new_cmd_map() and down into
+                * target_setup_cmd_from_cdb()
+                */
+               memcpy(tv_cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
+               /*
+                * Check that the recieved CDB size does not exceeded our
+                * hardcoded max for tcm_vhost
+                */
+               /* TODO what if cdb was too small for varlen cdb header? */
+               if (unlikely(scsi_command_size(tv_cmd->tvc_cdb) >
+                                       TCM_VHOST_MAX_CDB_SIZE)) {
+                       vq_err(vq, "Received SCSI CDB with command_size: %d that"
+                               " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
+                               scsi_command_size(tv_cmd->tvc_cdb),
+                               TCM_VHOST_MAX_CDB_SIZE);
+                       break; /* TODO */
+               }
+               tv_cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
+
+               pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
+                       tv_cmd->tvc_cdb[0], tv_cmd->tvc_lun);
+
+               if (data_direction != DMA_NONE) {
+                       ret = vhost_scsi_map_iov_to_sgl(tv_cmd,
+                                       &vq->iov[data_first], data_num,
+                                       data_direction == DMA_TO_DEVICE);
+                       if (unlikely(ret)) {
+                               vq_err(vq, "Failed to map iov to sgl\n");
+                               break; /* TODO */
+                       }
+               }
+
+               /*
+                * Save the descriptor from vhost_get_vq_desc() to be used to
+                * complete the virtio-scsi request in TCM callback context via
+                * tcm_vhost_queue_data_in() and tcm_vhost_queue_status()
+                */
+               tv_cmd->tvc_vq_desc = head;
+               /*
+                * Dispatch tv_cmd descriptor for cmwq execution in process
+                * context provided by tcm_vhost_workqueue.  This also ensures
+                * tv_cmd is executed on the same kworker CPU as this vhost
+                * thread to gain positive L2 cache locality effects..
+                */
+               INIT_WORK(&tv_cmd->work, tcm_vhost_submission_work);
+               queue_work(tcm_vhost_workqueue, &tv_cmd->work);
+       }
+
+       mutex_unlock(&vq->mutex);
+}
+
+static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
+{
+       pr_debug("%s: The handling func for control queue.\n", __func__);
+}
+
+static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
+{
+       pr_debug("%s: The handling func for event queue.\n", __func__);
+}
+
+static void vhost_scsi_handle_kick(struct vhost_work *work)
+{
+       struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+                                               poll.work);
+       struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
+
+       vhost_scsi_handle_vq(vs);
+}
+
+/*
+ * Called from vhost_scsi_ioctl() context to walk the list of available
+ * tcm_vhost_tpg with an active struct tcm_vhost_nexus
+ */
+static int vhost_scsi_set_endpoint(
+       struct vhost_scsi *vs,
+       struct vhost_scsi_target *t)
+{
+       struct tcm_vhost_tport *tv_tport;
+       struct tcm_vhost_tpg *tv_tpg;
+       int index;
+
+       mutex_lock(&vs->dev.mutex);
+       /* Verify that ring has been setup correctly. */
+       for (index = 0; index < vs->dev.nvqs; ++index) {
+               /* Verify that ring has been setup correctly. */
+               if (!vhost_vq_access_ok(&vs->vqs[index])) {
+                       mutex_unlock(&vs->dev.mutex);
+                       return -EFAULT;
+               }
+       }
+       mutex_unlock(&vs->dev.mutex);
+
+       mutex_lock(&tcm_vhost_mutex);
+       list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) {
+               mutex_lock(&tv_tpg->tv_tpg_mutex);
+               if (!tv_tpg->tpg_nexus) {
+                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                       continue;
+               }
+               if (tv_tpg->tv_tpg_vhost_count != 0) {
+                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                       continue;
+               }
+               tv_tport = tv_tpg->tport;
+
+               if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) &&
+                   (tv_tpg->tport_tpgt == t->vhost_tpgt)) {
+                       tv_tpg->tv_tpg_vhost_count++;
+                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                       mutex_unlock(&tcm_vhost_mutex);
+
+                       mutex_lock(&vs->dev.mutex);
+                       if (vs->vs_tpg) {
+                               mutex_unlock(&vs->dev.mutex);
+                               mutex_lock(&tv_tpg->tv_tpg_mutex);
+                               tv_tpg->tv_tpg_vhost_count--;
+                               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                               return -EEXIST;
+                       }
+
+                       vs->vs_tpg = tv_tpg;
+                       smp_mb__after_atomic_inc();
+                       mutex_unlock(&vs->dev.mutex);
+                       return 0;
+               }
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       }
+       mutex_unlock(&tcm_vhost_mutex);
+       return -EINVAL;
+}
+
+static int vhost_scsi_clear_endpoint(
+       struct vhost_scsi *vs,
+       struct vhost_scsi_target *t)
+{
+       struct tcm_vhost_tport *tv_tport;
+       struct tcm_vhost_tpg *tv_tpg;
+       int index, ret;
+
+       mutex_lock(&vs->dev.mutex);
+       /* Verify that ring has been setup correctly. */
+       for (index = 0; index < vs->dev.nvqs; ++index) {
+               if (!vhost_vq_access_ok(&vs->vqs[index])) {
+                       ret = -EFAULT;
+                       goto err;
+               }
+       }
+
+       if (!vs->vs_tpg) {
+               ret = -ENODEV;
+               goto err;
+       }
+       tv_tpg = vs->vs_tpg;
+       tv_tport = tv_tpg->tport;
+
+       if (strcmp(tv_tport->tport_name, t->vhost_wwpn) ||
+           (tv_tpg->tport_tpgt != t->vhost_tpgt)) {
+               pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu"
+                       " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n",
+                       tv_tport->tport_name, tv_tpg->tport_tpgt,
+                       t->vhost_wwpn, t->vhost_tpgt);
+               ret = -EINVAL;
+               goto err;
+       }
+       tv_tpg->tv_tpg_vhost_count--;
+       vs->vs_tpg = NULL;
+       mutex_unlock(&vs->dev.mutex);
+
+       return 0;
+
+err:
+       mutex_unlock(&vs->dev.mutex);
+       return ret;
+}
+
+static int vhost_scsi_open(struct inode *inode, struct file *f)
+{
+       struct vhost_scsi *s;
+       int r;
+
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work);
+       INIT_LIST_HEAD(&s->vs_completion_list);
+       spin_lock_init(&s->vs_completion_lock);
+
+       s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick;
+       s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick;
+       s->vqs[VHOST_SCSI_VQ_IO].handle_kick = vhost_scsi_handle_kick;
+       r = vhost_dev_init(&s->dev, s->vqs, 3);
+       if (r < 0) {
+               kfree(s);
+               return r;
+       }
+
+       f->private_data = s;
+       return 0;
+}
+
+static int vhost_scsi_release(struct inode *inode, struct file *f)
+{
+       struct vhost_scsi *s = f->private_data;
+
+       if (s->vs_tpg && s->vs_tpg->tport) {
+               struct vhost_scsi_target backend;
+
+               memcpy(backend.vhost_wwpn, s->vs_tpg->tport->tport_name,
+                               sizeof(backend.vhost_wwpn));
+               backend.vhost_tpgt = s->vs_tpg->tport_tpgt;
+               vhost_scsi_clear_endpoint(s, &backend);
+       }
+
+       vhost_dev_cleanup(&s->dev, false);
+       kfree(s);
+       return 0;
+}
+
+static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index)
+{
+       vhost_poll_flush(&vs->dev.vqs[index].poll);
+}
+
+static void vhost_scsi_flush(struct vhost_scsi *vs)
+{
+       vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_CTL);
+       vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_EVT);
+       vhost_scsi_flush_vq(vs, VHOST_SCSI_VQ_IO);
+}
+
+static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+{
+       if (features & ~VHOST_FEATURES)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&vs->dev.mutex);
+       if ((features & (1 << VHOST_F_LOG_ALL)) &&
+           !vhost_log_access_ok(&vs->dev)) {
+               mutex_unlock(&vs->dev.mutex);
+               return -EFAULT;
+       }
+       vs->dev.acked_features = features;
+       smp_wmb();
+       vhost_scsi_flush(vs);
+       mutex_unlock(&vs->dev.mutex);
+       return 0;
+}
+
+static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
+                               unsigned long arg)
+{
+       struct vhost_scsi *vs = f->private_data;
+       struct vhost_scsi_target backend;
+       void __user *argp = (void __user *)arg;
+       u64 __user *featurep = argp;
+       u64 features;
+       int r, abi_version = VHOST_SCSI_ABI_VERSION;
+
+       switch (ioctl) {
+       case VHOST_SCSI_SET_ENDPOINT:
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
+               if (backend.reserved != 0)
+                       return -EOPNOTSUPP;
+
+               return vhost_scsi_set_endpoint(vs, &backend);
+       case VHOST_SCSI_CLEAR_ENDPOINT:
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
+               if (backend.reserved != 0)
+                       return -EOPNOTSUPP;
+
+               return vhost_scsi_clear_endpoint(vs, &backend);
+       case VHOST_SCSI_GET_ABI_VERSION:
+               if (copy_to_user(argp, &abi_version, sizeof abi_version))
+                       return -EFAULT;
+               return 0;
+       case VHOST_GET_FEATURES:
+               features = VHOST_FEATURES;
+               if (copy_to_user(featurep, &features, sizeof features))
+                       return -EFAULT;
+               return 0;
+       case VHOST_SET_FEATURES:
+               if (copy_from_user(&features, featurep, sizeof features))
+                       return -EFAULT;
+               return vhost_scsi_set_features(vs, features);
+       default:
+               mutex_lock(&vs->dev.mutex);
+               r = vhost_dev_ioctl(&vs->dev, ioctl, arg);
+               mutex_unlock(&vs->dev.mutex);
+               return r;
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_scsi_compat_ioctl(struct file *f, unsigned int ioctl,
+                               unsigned long arg)
+{
+       return vhost_scsi_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations vhost_scsi_fops = {
+       .owner          = THIS_MODULE,
+       .release        = vhost_scsi_release,
+       .unlocked_ioctl = vhost_scsi_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = vhost_scsi_compat_ioctl,
+#endif
+       .open           = vhost_scsi_open,
+       .llseek         = noop_llseek,
+};
+
+static struct miscdevice vhost_scsi_misc = {
+       MISC_DYNAMIC_MINOR,
+       "vhost-scsi",
+       &vhost_scsi_fops,
+};
+
+static int __init vhost_scsi_register(void)
+{
+       return misc_register(&vhost_scsi_misc);
+}
+
+static int vhost_scsi_deregister(void)
+{
+       return misc_deregister(&vhost_scsi_misc);
+}
+
+static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
+{
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return "SAS";
+       case SCSI_PROTOCOL_FCP:
+               return "FCP";
+       case SCSI_PROTOCOL_ISCSI:
+               return "iSCSI";
+       default:
+               break;
+       }
+
+       return "Unknown";
+}
+
+static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
+       struct se_lun *lun)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+
+       mutex_lock(&tv_tpg->tv_tpg_mutex);
+       tv_tpg->tv_tpg_port_count++;
+       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+
+       return 0;
+}
+
+static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,
+       struct se_lun *se_lun)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+
+       mutex_lock(&tv_tpg->tv_tpg_mutex);
+       tv_tpg->tv_tpg_port_count--;
+       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+}
+
+static struct se_node_acl *tcm_vhost_make_nodeacl(
+       struct se_portal_group *se_tpg,
+       struct config_group *group,
+       const char *name)
+{
+       struct se_node_acl *se_nacl, *se_nacl_new;
+       struct tcm_vhost_nacl *nacl;
+       u64 wwpn = 0;
+       u32 nexus_depth;
+
+       /* tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+               return ERR_PTR(-EINVAL); */
+       se_nacl_new = tcm_vhost_alloc_fabric_acl(se_tpg);
+       if (!se_nacl_new)
+               return ERR_PTR(-ENOMEM);
+
+       nexus_depth = 1;
+       /*
+        * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+        * when converting a NodeACL from demo mode -> explict
+        */
+       se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+                               name, nexus_depth);
+       if (IS_ERR(se_nacl)) {
+               tcm_vhost_release_fabric_acl(se_tpg, se_nacl_new);
+               return se_nacl;
+       }
+       /*
+        * Locate our struct tcm_vhost_nacl and set the FC Nport WWPN
+        */
+       nacl = container_of(se_nacl, struct tcm_vhost_nacl, se_node_acl);
+       nacl->iport_wwpn = wwpn;
+
+       return se_nacl;
+}
+
+static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
+{
+       struct tcm_vhost_nacl *nacl = container_of(se_acl,
+                               struct tcm_vhost_nacl, se_node_acl);
+       core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+       kfree(nacl);
+}
+
+static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tv_tpg,
+       const char *name)
+{
+       struct se_portal_group *se_tpg;
+       struct tcm_vhost_nexus *tv_nexus;
+
+       mutex_lock(&tv_tpg->tv_tpg_mutex);
+       if (tv_tpg->tpg_nexus) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               pr_debug("tv_tpg->tpg_nexus already exists\n");
+               return -EEXIST;
+       }
+       se_tpg = &tv_tpg->se_tpg;
+
+       tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL);
+       if (!tv_nexus) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+               return -ENOMEM;
+       }
+       /*
+        *  Initialize the struct se_session pointer
+        */
+       tv_nexus->tvn_se_sess = transport_init_session();
+       if (IS_ERR(tv_nexus->tvn_se_sess)) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               kfree(tv_nexus);
+               return -ENOMEM;
+       }
+       /*
+        * Since we are running in 'demo mode' this call with generate a
+        * struct se_node_acl for the tcm_vhost struct se_portal_group with
+        * the SCSI Initiator port name of the passed configfs group 'name'.
+        */
+       tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+                               se_tpg, (unsigned char *)name);
+       if (!tv_nexus->tvn_se_sess->se_node_acl) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               pr_debug("core_tpg_check_initiator_node_acl() failed"
+                               " for %s\n", name);
+               transport_free_session(tv_nexus->tvn_se_sess);
+               kfree(tv_nexus);
+               return -ENOMEM;
+       }
+       /*
+        * Now register the TCM vhost virtual I_T Nexus as active with the
+        * call to __transport_register_session()
+        */
+       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+                       tv_nexus->tvn_se_sess, tv_nexus);
+       tv_tpg->tpg_nexus = tv_nexus;
+
+       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       return 0;
+}
+
+static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
+{
+       struct se_session *se_sess;
+       struct tcm_vhost_nexus *tv_nexus;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+
+       se_sess = tv_nexus->tvn_se_sess;
+       if (!se_sess) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+
+       if (tpg->tv_tpg_port_count != 0) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_err("Unable to remove TCM_vhost I_T Nexus with"
+                       " active TPG port count: %d\n",
+                       tpg->tv_tpg_port_count);
+               return -EBUSY;
+       }
+
+       if (tpg->tv_tpg_vhost_count != 0) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_err("Unable to remove TCM_vhost I_T Nexus with"
+                       " active TPG vhost count: %d\n",
+                       tpg->tv_tpg_vhost_count);
+               return -EBUSY;
+       }
+
+       pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
+               " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport),
+               tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+       /*
+        * Release the SCSI I_T Nexus to the emulated vhost Target Port
+        */
+       transport_deregister_session(tv_nexus->tvn_se_sess);
+       tpg->tpg_nexus = NULL;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       kfree(tv_nexus);
+       return 0;
+}
+
+static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_nexus *tv_nexus;
+       ssize_t ret;
+
+       mutex_lock(&tv_tpg->tv_tpg_mutex);
+       tv_nexus = tv_tpg->tpg_nexus;
+       if (!tv_nexus) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+       ret = snprintf(page, PAGE_SIZE, "%s\n",
+                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+
+       return ret;
+}
+
+static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport_wwn = tv_tpg->tport;
+       unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr;
+       int ret;
+       /*
+        * Shutdown the active I_T nexus if 'NULL' is passed..
+        */
+       if (!strncmp(page, "NULL", 4)) {
+               ret = tcm_vhost_drop_nexus(tv_tpg);
+               return (!ret) ? count : ret;
+       }
+       /*
+        * Otherwise make sure the passed virtual Initiator port WWN matches
+        * the fabric protocol_id set in tcm_vhost_make_tport(), and call
+        * tcm_vhost_make_nexus().
+        */
+       if (strlen(page) >= TCM_VHOST_NAMELEN) {
+               pr_err("Emulated NAA Sas Address: %s, exceeds"
+                               " max: %d\n", page, TCM_VHOST_NAMELEN);
+               return -EINVAL;
+       }
+       snprintf(&i_port[0], TCM_VHOST_NAMELEN, "%s", page);
+
+       ptr = strstr(i_port, "naa.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
+                       pr_err("Passed SAS Initiator Port %s does not"
+                               " match target port protoid: %s\n", i_port,
+                               tcm_vhost_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[0];
+               goto check_newline;
+       }
+       ptr = strstr(i_port, "fc.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
+                       pr_err("Passed FCP Initiator Port %s does not"
+                               " match target port protoid: %s\n", i_port,
+                               tcm_vhost_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[3]; /* Skip over "fc." */
+               goto check_newline;
+       }
+       ptr = strstr(i_port, "iqn.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
+                       pr_err("Passed iSCSI Initiator Port %s does not"
+                               " match target port protoid: %s\n", i_port,
+                               tcm_vhost_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[0];
+               goto check_newline;
+       }
+       pr_err("Unable to locate prefix for emulated Initiator Port:"
+                       " %s\n", i_port);
+       return -EINVAL;
+       /*
+        * Clear any trailing newline for the NAA WWN
+        */
+check_newline:
+       if (i_port[strlen(i_port)-1] == '\n')
+               i_port[strlen(i_port)-1] = '\0';
+
+       ret = tcm_vhost_make_nexus(tv_tpg, port_ptr);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_vhost, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_vhost_tpg_attrs[] = {
+       &tcm_vhost_tpg_nexus.attr,
+       NULL,
+};
+
+static struct se_portal_group *tcm_vhost_make_tpg(struct se_wwn *wwn,
+       struct config_group *group,
+       const char *name)
+{
+       struct tcm_vhost_tport *tport = container_of(wwn,
+                       struct tcm_vhost_tport, tport_wwn);
+
+       struct tcm_vhost_tpg *tpg;
+       unsigned long tpgt;
+       int ret;
+
+       if (strstr(name, "tpgt_") != name)
+               return ERR_PTR(-EINVAL);
+       if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+               return ERR_PTR(-EINVAL);
+
+       tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL);
+       if (!tpg) {
+               pr_err("Unable to allocate struct tcm_vhost_tpg");
+               return ERR_PTR(-ENOMEM);
+       }
+       mutex_init(&tpg->tv_tpg_mutex);
+       INIT_LIST_HEAD(&tpg->tv_tpg_list);
+       tpg->tport = tport;
+       tpg->tport_tpgt = tpgt;
+
+       ret = core_tpg_register(&tcm_vhost_fabric_configfs->tf_ops, wwn,
+                               &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
+       if (ret < 0) {
+               kfree(tpg);
+               return NULL;
+       }
+       mutex_lock(&tcm_vhost_mutex);
+       list_add_tail(&tpg->tv_tpg_list, &tcm_vhost_list);
+       mutex_unlock(&tcm_vhost_mutex);
+
+       return &tpg->se_tpg;
+}
+
+static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+
+       mutex_lock(&tcm_vhost_mutex);
+       list_del(&tpg->tv_tpg_list);
+       mutex_unlock(&tcm_vhost_mutex);
+       /*
+        * Release the virtual I_T Nexus for this vhost TPG
+        */
+       tcm_vhost_drop_nexus(tpg);
+       /*
+        * Deregister the se_tpg from TCM..
+        */
+       core_tpg_deregister(se_tpg);
+       kfree(tpg);
+}
+
+static struct se_wwn *tcm_vhost_make_tport(struct target_fabric_configfs *tf,
+       struct config_group *group,
+       const char *name)
+{
+       struct tcm_vhost_tport *tport;
+       char *ptr;
+       u64 wwpn = 0;
+       int off = 0;
+
+       /* if (tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+               return ERR_PTR(-EINVAL); */
+
+       tport = kzalloc(sizeof(struct tcm_vhost_tport), GFP_KERNEL);
+       if (!tport) {
+               pr_err("Unable to allocate struct tcm_vhost_tport");
+               return ERR_PTR(-ENOMEM);
+       }
+       tport->tport_wwpn = wwpn;
+       /*
+        * Determine the emulated Protocol Identifier and Target Port Name
+        * based on the incoming configfs directory name.
+        */
+       ptr = strstr(name, "naa.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_SAS;
+               goto check_len;
+       }
+       ptr = strstr(name, "fc.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_FCP;
+               off = 3; /* Skip over "fc." */
+               goto check_len;
+       }
+       ptr = strstr(name, "iqn.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_ISCSI;
+               goto check_len;
+       }
+
+       pr_err("Unable to locate prefix for emulated Target Port:"
+                       " %s\n", name);
+       kfree(tport);
+       return ERR_PTR(-EINVAL);
+
+check_len:
+       if (strlen(name) >= TCM_VHOST_NAMELEN) {
+               pr_err("Emulated %s Address: %s, exceeds"
+                       " max: %d\n", name, tcm_vhost_dump_proto_id(tport),
+                       TCM_VHOST_NAMELEN);
+               kfree(tport);
+               return ERR_PTR(-EINVAL);
+       }
+       snprintf(&tport->tport_name[0], TCM_VHOST_NAMELEN, "%s", &name[off]);
+
+       pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target"
+               " %s Address: %s\n", tcm_vhost_dump_proto_id(tport), name);
+
+       return &tport->tport_wwn;
+}
+
+static void tcm_vhost_drop_tport(struct se_wwn *wwn)
+{
+       struct tcm_vhost_tport *tport = container_of(wwn,
+                               struct tcm_vhost_tport, tport_wwn);
+
+       pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target"
+               " %s Address: %s\n", tcm_vhost_dump_proto_id(tport),
+               tport->tport_name);
+
+       kfree(tport);
+}
+
+static ssize_t tcm_vhost_wwn_show_attr_version(
+       struct target_fabric_configfs *tf,
+       char *page)
+{
+       return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
+               "on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+               utsname()->machine);
+}
+
+TF_WWN_ATTR_RO(tcm_vhost, version);
+
+static struct configfs_attribute *tcm_vhost_wwn_attrs[] = {
+       &tcm_vhost_wwn_version.attr,
+       NULL,
+};
+
+static struct target_core_fabric_ops tcm_vhost_ops = {
+       .get_fabric_name                = tcm_vhost_get_fabric_name,
+       .get_fabric_proto_ident         = tcm_vhost_get_fabric_proto_ident,
+       .tpg_get_wwn                    = tcm_vhost_get_fabric_wwn,
+       .tpg_get_tag                    = tcm_vhost_get_tag,
+       .tpg_get_default_depth          = tcm_vhost_get_default_depth,
+       .tpg_get_pr_transport_id        = tcm_vhost_get_pr_transport_id,
+       .tpg_get_pr_transport_id_len    = tcm_vhost_get_pr_transport_id_len,
+       .tpg_parse_pr_out_transport_id  = tcm_vhost_parse_pr_out_transport_id,
+       .tpg_check_demo_mode            = tcm_vhost_check_true,
+       .tpg_check_demo_mode_cache      = tcm_vhost_check_true,
+       .tpg_check_demo_mode_write_protect = tcm_vhost_check_false,
+       .tpg_check_prod_mode_write_protect = tcm_vhost_check_false,
+       .tpg_alloc_fabric_acl           = tcm_vhost_alloc_fabric_acl,
+       .tpg_release_fabric_acl         = tcm_vhost_release_fabric_acl,
+       .tpg_get_inst_index             = tcm_vhost_tpg_get_inst_index,
+       .release_cmd                    = tcm_vhost_release_cmd,
+       .shutdown_session               = tcm_vhost_shutdown_session,
+       .close_session                  = tcm_vhost_close_session,
+       .sess_get_index                 = tcm_vhost_sess_get_index,
+       .sess_get_initiator_sid         = NULL,
+       .write_pending                  = tcm_vhost_write_pending,
+       .write_pending_status           = tcm_vhost_write_pending_status,
+       .set_default_node_attributes    = tcm_vhost_set_default_node_attrs,
+       .get_task_tag                   = tcm_vhost_get_task_tag,
+       .get_cmd_state                  = tcm_vhost_get_cmd_state,
+       .queue_data_in                  = tcm_vhost_queue_data_in,
+       .queue_status                   = tcm_vhost_queue_status,
+       .queue_tm_rsp                   = tcm_vhost_queue_tm_rsp,
+       .get_fabric_sense_len           = tcm_vhost_get_fabric_sense_len,
+       .set_fabric_sense_len           = tcm_vhost_set_fabric_sense_len,
+       /*
+        * Setup callers for generic logic in target_core_fabric_configfs.c
+        */
+       .fabric_make_wwn                = tcm_vhost_make_tport,
+       .fabric_drop_wwn                = tcm_vhost_drop_tport,
+       .fabric_make_tpg                = tcm_vhost_make_tpg,
+       .fabric_drop_tpg                = tcm_vhost_drop_tpg,
+       .fabric_post_link               = tcm_vhost_port_link,
+       .fabric_pre_unlink              = tcm_vhost_port_unlink,
+       .fabric_make_np                 = NULL,
+       .fabric_drop_np                 = NULL,
+       .fabric_make_nodeacl            = tcm_vhost_make_nodeacl,
+       .fabric_drop_nodeacl            = tcm_vhost_drop_nodeacl,
+};
+
+static int tcm_vhost_register_configfs(void)
+{
+       struct target_fabric_configfs *fabric;
+       int ret;
+
+       pr_debug("TCM_VHOST fabric module %s on %s/%s"
+               " on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+               utsname()->machine);
+       /*
+        * Register the top level struct config_item_type with TCM core
+        */
+       fabric = target_fabric_configfs_init(THIS_MODULE, "vhost");
+       if (IS_ERR(fabric)) {
+               pr_err("target_fabric_configfs_init() failed\n");
+               return PTR_ERR(fabric);
+       }
+       /*
+        * Setup fabric->tf_ops from our local tcm_vhost_ops
+        */
+       fabric->tf_ops = tcm_vhost_ops;
+       /*
+        * Setup default attribute lists for various fabric->tf_cit_tmpl
+        */
+       TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_vhost_wwn_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_vhost_tpg_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+       /*
+        * Register the fabric for use within TCM
+        */
+       ret = target_fabric_configfs_register(fabric);
+       if (ret < 0) {
+               pr_err("target_fabric_configfs_register() failed"
+                               " for TCM_VHOST\n");
+               return ret;
+       }
+       /*
+        * Setup our local pointer to *fabric
+        */
+       tcm_vhost_fabric_configfs = fabric;
+       pr_debug("TCM_VHOST[0] - Set fabric -> tcm_vhost_fabric_configfs\n");
+       return 0;
+};
+
+static void tcm_vhost_deregister_configfs(void)
+{
+       if (!tcm_vhost_fabric_configfs)
+               return;
+
+       target_fabric_configfs_deregister(tcm_vhost_fabric_configfs);
+       tcm_vhost_fabric_configfs = NULL;
+       pr_debug("TCM_VHOST[0] - Cleared tcm_vhost_fabric_configfs\n");
+};
+
+static int __init tcm_vhost_init(void)
+{
+       int ret = -ENOMEM;
+       /*
+        * Use our own dedicated workqueue for submitting I/O into
+        * target core to avoid contention within system_wq.
+        */
+       tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0);
+       if (!tcm_vhost_workqueue)
+               goto out;
+
+       ret = vhost_scsi_register();
+       if (ret < 0)
+               goto out_destroy_workqueue;
+
+       ret = tcm_vhost_register_configfs();
+       if (ret < 0)
+               goto out_vhost_scsi_deregister;
+
+       return 0;
+
+out_vhost_scsi_deregister:
+       vhost_scsi_deregister();
+out_destroy_workqueue:
+       destroy_workqueue(tcm_vhost_workqueue);
+out:
+       return ret;
+};
+
+static void tcm_vhost_exit(void)
+{
+       tcm_vhost_deregister_configfs();
+       vhost_scsi_deregister();
+       destroy_workqueue(tcm_vhost_workqueue);
+};
+
+MODULE_DESCRIPTION("TCM_VHOST series fabric driver");
+MODULE_LICENSE("GPL");
+module_init(tcm_vhost_init);
+module_exit(tcm_vhost_exit);
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h
new file mode 100644 (file)
index 0000000..d9e9355
--- /dev/null
@@ -0,0 +1,103 @@
+#define TCM_VHOST_VERSION  "v0.1"
+#define TCM_VHOST_NAMELEN 256
+#define TCM_VHOST_MAX_CDB_SIZE 32
+
+struct tcm_vhost_cmd {
+       /* Descriptor from vhost_get_vq_desc() for virt_queue segment */
+       int tvc_vq_desc;
+       /* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
+       u64 tvc_tag;
+       /* The number of scatterlists associated with this cmd */
+       u32 tvc_sgl_count;
+       /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */
+       u32 tvc_lun;
+       /* Pointer to the SGL formatted memory from virtio-scsi */
+       struct scatterlist *tvc_sgl;
+       /* Pointer to response */
+       struct virtio_scsi_cmd_resp __user *tvc_resp;
+       /* Pointer to vhost_scsi for our device */
+       struct vhost_scsi *tvc_vhost;
+       /* The TCM I/O descriptor that is accessed via container_of() */
+       struct se_cmd tvc_se_cmd;
+       /* work item used for cmwq dispatch to tcm_vhost_submission_work() */
+       struct work_struct work;
+       /* Copy of the incoming SCSI command descriptor block (CDB) */
+       unsigned char tvc_cdb[TCM_VHOST_MAX_CDB_SIZE];
+       /* Sense buffer that will be mapped into outgoing status */
+       unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
+       /* Completed commands list, serviced from vhost worker thread */
+       struct list_head tvc_completion_list;
+};
+
+struct tcm_vhost_nexus {
+       /* Pointer to TCM session for I_T Nexus */
+       struct se_session *tvn_se_sess;
+};
+
+struct tcm_vhost_nacl {
+       /* Binary World Wide unique Port Name for Vhost Initiator port */
+       u64 iport_wwpn;
+       /* ASCII formatted WWPN for Sas Initiator port */
+       char iport_name[TCM_VHOST_NAMELEN];
+       /* Returned by tcm_vhost_make_nodeacl() */
+       struct se_node_acl se_node_acl;
+};
+
+struct tcm_vhost_tpg {
+       /* Vhost port target portal group tag for TCM */
+       u16 tport_tpgt;
+       /* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
+       int tv_tpg_port_count;
+       /* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
+       int tv_tpg_vhost_count;
+       /* list for tcm_vhost_list */
+       struct list_head tv_tpg_list;
+       /* Used to protect access for tpg_nexus */
+       struct mutex tv_tpg_mutex;
+       /* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
+       struct tcm_vhost_nexus *tpg_nexus;
+       /* Pointer back to tcm_vhost_tport */
+       struct tcm_vhost_tport *tport;
+       /* Returned by tcm_vhost_make_tpg() */
+       struct se_portal_group se_tpg;
+};
+
+struct tcm_vhost_tport {
+       /* SCSI protocol the tport is providing */
+       u8 tport_proto_id;
+       /* Binary World Wide unique Port Name for Vhost Target port */
+       u64 tport_wwpn;
+       /* ASCII formatted WWPN for Vhost Target port */
+       char tport_name[TCM_VHOST_NAMELEN];
+       /* Returned by tcm_vhost_make_tport() */
+       struct se_wwn tport_wwn;
+};
+
+/*
+ * As per request from MST, keep TCM_VHOST related ioctl defines out of
+ * linux/vhost.h (user-space) for now..
+ */
+
+#include <linux/vhost.h>
+
+/*
+ * Used by QEMU userspace to ensure a consistent vhost-scsi ABI.
+ *
+ * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate +
+ *            RFC-v2 vhost-scsi userspace.  Add GET_ABI_VERSION ioctl usage
+ */
+
+#define VHOST_SCSI_ABI_VERSION 0
+
+struct vhost_scsi_target {
+       int abi_version;
+       char vhost_wwpn[TRANSPORT_IQN_LEN];
+       unsigned short vhost_tpgt;
+       unsigned short reserved;
+};
+
+/* VHOST_SCSI specific defines */
+#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target)
+#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target)
+/* Changing this breaks userspace. */
+#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int)
index 2e471c22abf5a5e835704e71767017923f747c0c..88e92041d8f02d6136458535c61c3090c304e576 100644 (file)
@@ -372,8 +372,15 @@ static void fb_flashcursor(struct work_struct *work)
        struct vc_data *vc = NULL;
        int c;
        int mode;
+       int ret;
+
+       /* FIXME: we should sort out the unbind locking instead */
+       /* instead we just fail to flash the cursor if we can't get
+        * the lock instead of blocking fbcon deinit */
+       ret = console_trylock();
+       if (ret == 0)
+               return;
 
-       console_lock();
        if (ops && ops->currcon != -1)
                vc = vc_cons[ops->currcon].d;
 
index d90062b211f8a107a142f439129a6f8d699aa1de..92d08e7fcba2377088bf4b45b12e18f773f6bb23 100644 (file)
@@ -91,6 +91,11 @@ static struct w1_family w1_therm_family_DS28EA00 = {
        .fops = &w1_therm_fops,
 };
 
+static struct w1_family w1_therm_family_DS1825 = {
+       .fid = W1_THERM_DS1825,
+       .fops = &w1_therm_fops,
+};
+
 struct w1_therm_family_converter
 {
        u8                      broken;
@@ -120,6 +125,10 @@ static struct w1_therm_family_converter w1_therm_families[] = {
                .f              = &w1_therm_family_DS28EA00,
                .convert        = w1_DS18B20_convert_temp
        },
+       {
+               .f              = &w1_therm_family_DS1825,
+               .convert        = w1_DS18B20_convert_temp
+       }
 };
 
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
index b00ada44a89be8989a46912fb85e976624d5e586..a1f0ce151d53d902813ef9f6521ee4973c9f053b 100644 (file)
@@ -39,6 +39,7 @@
 #define W1_EEPROM_DS2431       0x2D
 #define W1_FAMILY_DS2760       0x30
 #define W1_FAMILY_DS2780       0x32
+#define W1_THERM_DS1825                0x3B
 #define W1_FAMILY_DS2781       0x3D
 #define W1_THERM_DS28EA00      0x42
 
index 181fa8158a8b01d48393bb9d2b1d9d4e0bf9e79e..858c9714b2f390a26e1a1450f196d7abf6e14340 100644 (file)
@@ -37,7 +37,6 @@ struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO];
      */
 
 struct zorro_bus {
-       struct list_head devices;       /* list of devices on this bus */
        struct device dev;
 };
 
@@ -136,7 +135,6 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
        if (!bus)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&bus->devices);
        bus->dev.parent = &pdev->dev;
        dev_set_name(&bus->dev, "zorro");
        error = device_register(&bus->dev);
index 1feb68ecef9509dd88a4323f3193845af6a84e15..842d00048a652f8cb9ebda7eeea40d62e9cb6720 100644 (file)
@@ -94,25 +94,21 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
 {
        struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
        struct list_head *next;
-       struct dentry *p, *q;
+       struct dentry *q;
 
        spin_lock(&sbi->lookup_lock);
+       spin_lock(&root->d_lock);
 
-       if (prev == NULL) {
-               spin_lock(&root->d_lock);
+       if (prev)
+               next = prev->d_u.d_child.next;
+       else {
                prev = dget_dlock(root);
                next = prev->d_subdirs.next;
-               p = prev;
-               goto start;
        }
 
-       p = prev;
-       spin_lock(&p->d_lock);
-again:
-       next = p->d_u.d_child.next;
-start:
+cont:
        if (next == &root->d_subdirs) {
-               spin_unlock(&p->d_lock);
+               spin_unlock(&root->d_lock);
                spin_unlock(&sbi->lookup_lock);
                dput(prev);
                return NULL;
@@ -121,16 +117,15 @@ start:
        q = list_entry(next, struct dentry, d_u.d_child);
 
        spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
-       /* Negative dentry - try next */
-       if (!simple_positive(q)) {
-               spin_unlock(&p->d_lock);
-               lock_set_subclass(&q->d_lock.dep_map, 0, _RET_IP_);
-               p = q;
-               goto again;
+       /* Already gone or negative dentry (under construction) - try next */
+       if (q->d_count == 0 || !simple_positive(q)) {
+               spin_unlock(&q->d_lock);
+               next = q->d_u.d_child.next;
+               goto cont;
        }
        dget_dlock(q);
        spin_unlock(&q->d_lock);
-       spin_unlock(&p->d_lock);
+       spin_unlock(&root->d_lock);
        spin_unlock(&sbi->lookup_lock);
 
        dput(prev);
@@ -404,11 +399,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
                        DPRINTK("checking mountpoint %p %.*s",
                                dentry, (int)dentry->d_name.len, dentry->d_name.name);
 
-                       /* Path walk currently on this dentry? */
-                       ino_count = atomic_read(&ino->count) + 2;
-                       if (dentry->d_count > ino_count)
-                               goto next;
-
                        /* Can we umount this guy */
                        if (autofs4_mount_busy(mnt, dentry))
                                goto next;
index 73922abba832d0a41c1cb01bbf5bcc0fec1cb78b..5eaa70c9d96e6bb3900930d63beb224f38d15c8f 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1312,7 +1312,7 @@ EXPORT_SYMBOL(bio_copy_kern);
  * Note that this code is very hard to test under normal circumstances because
  * direct-io pins the pages with get_user_pages().  This makes
  * is_page_cache_freeable return false, and the VM will not clean the pages.
- * But other code (eg, pdflush) could clean the pages if they are mapped
+ * But other code (eg, flusher threads) could clean the pages if they are mapped
  * pagecache.
  *
  * Simply disabling the call to bio_set_pages_dirty() is a good way to test the
index 83baec24946d7449194e94893f92f918b14c79b5..6e8f416773d4b221713c30079eb1de1f732e5ded 100644 (file)
@@ -324,7 +324,8 @@ static noinline int add_async_extent(struct async_cow *cow,
  * If this code finds it can't get good compression, it puts an
  * entry onto the work queue to write the uncompressed bytes.  This
  * makes sure that both compressed inodes and uncompressed inodes
- * are written in the same order that pdflush sent them down.
+ * are written in the same order that the flusher thread sent them
+ * down.
  */
 static noinline int compress_file_range(struct inode *inode,
                                        struct page *locked_page,
index bc2f6ffff3cfb004099a5d4eb84f8a9aa688d7cd..7bb755677a220f71fd0540932c0c19565aec6a23 100644 (file)
@@ -664,10 +664,6 @@ static noinline int btrfs_mksubvol(struct path *parent,
        struct dentry *dentry;
        int error;
 
-       error = mnt_want_write(parent->mnt);
-       if (error)
-               return error;
-
        mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
 
        dentry = lookup_one_len(name, parent->dentry, namelen);
@@ -703,7 +699,6 @@ out_dput:
        dput(dentry);
 out_unlock:
        mutex_unlock(&dir->i_mutex);
-       mnt_drop_write(parent->mnt);
        return error;
 }
 
index 643335a4fe3c6699a894c19d01e79bed9ef631c7..051c7fe551dd38bb7e391e5abaeff992f32b90f7 100644 (file)
@@ -596,7 +596,7 @@ void btrfs_start_ordered_extent(struct inode *inode,
        /*
         * pages in the range can be dirty, clean or writeback.  We
         * start IO on any dirty ones so the wait doesn't stall waiting
-        * for pdflush to find them
+        * for the flusher thread to find them
         */
        if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags))
                filemap_fdatawrite_range(inode->i_mapping, start, end);
index 8c6e61d6eed5b754945930fbaaaaf21d6f98d028..f2eb24c477a3ca1c60ee95b51040354dd5a869ba 100644 (file)
@@ -100,10 +100,6 @@ static void __save_error_info(struct btrfs_fs_info *fs_info)
        fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR;
 }
 
-/* NOTE:
- *     We move write_super stuff at umount in order to avoid deadlock
- *     for umount hold all lock.
- */
 static void save_error_info(struct btrfs_fs_info *fs_info)
 {
        __save_error_info(fs_info);
index b8708f994e679a559af68b90b3135b2b8fa2a9ac..e86ae04abe6a78e72dd86b3a813bce3107a8802e 100644 (file)
@@ -1744,10 +1744,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        device->fs_devices = root->fs_info->fs_devices;
 
-       /*
-        * we don't want write_supers to jump in here with our device
-        * half setup
-        */
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices);
        list_add(&device->dev_alloc_list,
index fb962efdacee8cdbbdff2c3324516d0356d2e2e5..6d59006bfa27e688d37499b88f45e28a22df24db 100644 (file)
@@ -201,6 +201,7 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
        int err = -ENOMEM;
 
        dout("ceph_fs_debugfs_init\n");
+       BUG_ON(!fsc->client->debugfs_dir);
        fsc->debugfs_congestion_kb =
                debugfs_create_file("writeback_congestion_kb",
                                    0600,
index 9fff9f3b17e4a5206a9073cec2be714fba44bda0..4b5762ef7c2bf87ecb937a70a55ae20b100d77c9 100644 (file)
@@ -992,11 +992,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
        if (rinfo->head->is_dentry) {
                struct inode *dir = req->r_locked_dir;
 
-               err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
-                                session, req->r_request_started, -1,
-                                &req->r_caps_reservation);
-               if (err < 0)
-                       return err;
+               if (dir) {
+                       err = fill_inode(dir, &rinfo->diri, rinfo->dirfrag,
+                                        session, req->r_request_started, -1,
+                                        &req->r_caps_reservation);
+                       if (err < 0)
+                               return err;
+               } else {
+                       WARN_ON_ONCE(1);
+               }
        }
 
        /*
@@ -1004,6 +1008,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
         * will have trouble splicing in the virtual snapdir later
         */
        if (rinfo->head->is_dentry && !req->r_aborted &&
+           req->r_locked_dir &&
            (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name,
                                               fsc->mount_options->snapdir_name,
                                               req->r_dentry->d_name.len))) {
index 8e3fb69fbe62e60cd3698c07d9fa8e53d6d2b184..1396ceb46797400c124ac80880f31a90583d0e4b 100644 (file)
@@ -42,7 +42,8 @@ static long __validate_layout(struct ceph_mds_client *mdsc,
        /* validate striping parameters */
        if ((l->object_size & ~PAGE_MASK) ||
            (l->stripe_unit & ~PAGE_MASK) ||
-           ((unsigned)l->object_size % (unsigned)l->stripe_unit))
+           (l->stripe_unit != 0 &&
+            ((unsigned)l->object_size % (unsigned)l->stripe_unit)))
                return -EINVAL;
 
        /* make sure it's a valid data pool */
index 6161255fac45648efdfe437d9d880d390268d14f..1bdb350ea5d345fc2842c75ad7cc2e5065c81c16 100644 (file)
@@ -1155,11 +1155,14 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
        struct file *file;
        int fput_needed;
        ssize_t ret;
+       loff_t pos;
 
        file = fget_light(fd, &fput_needed);
        if (!file)
                return -EBADF;
-       ret = compat_readv(file, vec, vlen, &file->f_pos);
+       pos = file->f_pos;
+       ret = compat_readv(file, vec, vlen, &pos);
+       file->f_pos = pos;
        fput_light(file, fput_needed);
        return ret;
 }
@@ -1221,11 +1224,14 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
        struct file *file;
        int fput_needed;
        ssize_t ret;
+       loff_t pos;
 
        file = fget_light(fd, &fput_needed);
        if (!file)
                return -EBADF;
-       ret = compat_writev(file, vec, vlen, &file->f_pos);
+       pos = file->f_pos;
+       ret = compat_writev(file, vec, vlen, &pos);
+       file->f_pos = pos;
        fput_light(file, fput_needed);
        return ret;
 }
index 1c8b55670804c20e88a10a48668f574d54f58205..eedec84c1809173eb4c627815ad70122de66eeb3 100644 (file)
@@ -1654,8 +1654,8 @@ SYSCALL_DEFINE1(epoll_create1, int, flags)
                error = PTR_ERR(file);
                goto out_free_fd;
        }
-       fd_install(fd, file);
        ep->file = file;
+       fd_install(fd, file);
        return fd;
 
 out_free_fd:
index 5badb0c039de404b24208c8e6c2041b3331ae5bb..1562c27a2fab27f700825e0090e4d98492fa2fbd 100644 (file)
 
 #define EXOFS_DBGMSG2(M...) do {} while (0)
 
-enum {MAX_PAGES_KMALLOC = PAGE_SIZE / sizeof(struct page *), };
-
 unsigned exofs_max_io_pages(struct ore_layout *layout,
                            unsigned expected_pages)
 {
-       unsigned pages = min_t(unsigned, expected_pages, MAX_PAGES_KMALLOC);
+       unsigned pages = min_t(unsigned, expected_pages,
+                              layout->max_io_length / PAGE_SIZE);
 
-       /* TODO: easily support bio chaining */
-       pages =  min_t(unsigned, pages, layout->max_io_length / PAGE_SIZE);
        return pages;
 }
 
@@ -101,7 +98,8 @@ static void _pcol_reset(struct page_collect *pcol)
         * it might not end here. don't be left with nothing
         */
        if (!pcol->expected_pages)
-               pcol->expected_pages = MAX_PAGES_KMALLOC;
+               pcol->expected_pages =
+                               exofs_max_io_pages(&pcol->sbi->layout, ~0);
 }
 
 static int pcol_try_alloc(struct page_collect *pcol)
@@ -389,6 +387,8 @@ static int readpage_strip(void *data, struct page *page)
        size_t len;
        int ret;
 
+       BUG_ON(!PageLocked(page));
+
        /* FIXME: Just for debugging, will be removed */
        if (PageUptodate(page))
                EXOFS_ERR("PageUptodate(0x%lx, 0x%lx)\n", pcol->inode->i_ino,
@@ -572,8 +572,16 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
 
        if (!pcol->that_locked_page ||
            (pcol->that_locked_page->index != index)) {
-               struct page *page = find_get_page(pcol->inode->i_mapping, index);
+               struct page *page;
+               loff_t i_size = i_size_read(pcol->inode);
+
+               if (offset >= i_size) {
+                       *uptodate = true;
+                       EXOFS_DBGMSG("offset >= i_size index=0x%lx\n", index);
+                       return ZERO_PAGE(0);
+               }
 
+               page =  find_get_page(pcol->inode->i_mapping, index);
                if (!page) {
                        page = find_or_create_page(pcol->inode->i_mapping,
                                                   index, GFP_NOFS);
@@ -602,12 +610,13 @@ static void __r4w_put_page(void *priv, struct page *page)
 {
        struct page_collect *pcol = priv;
 
-       if (pcol->that_locked_page != page) {
+       if ((pcol->that_locked_page != page) && (ZERO_PAGE(0) != page)) {
                EXOFS_DBGMSG("index=0x%lx\n", page->index);
                page_cache_release(page);
                return;
        }
-       EXOFS_DBGMSG("that_locked_page index=0x%lx\n", page->index);
+       EXOFS_DBGMSG("that_locked_page index=0x%lx\n",
+                    ZERO_PAGE(0) == page ? -1 : page->index);
 }
 
 static const struct _ore_r4w_op _r4w_op = {
index 24a49d47e9354c00f0ebd2da6c92d3520e71332c..1585db1aa3651a3eb2fbe586156fd5bd270f5b82 100644 (file)
@@ -837,11 +837,11 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
                                bio->bi_rw |= REQ_WRITE;
                        }
 
-                       osd_req_write(or, _ios_obj(ios, dev), per_dev->offset,
-                                     bio, per_dev->length);
+                       osd_req_write(or, _ios_obj(ios, cur_comp),
+                                     per_dev->offset, bio, per_dev->length);
                        ORE_DBGMSG("write(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     _LLU(per_dev->offset),
                                     _LLU(per_dev->length), dev);
                } else if (ios->kern_buff) {
@@ -853,20 +853,20 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
                               (ios->si.unit_off + ios->length >
                                ios->layout->stripe_unit));
 
-                       ret = osd_req_write_kern(or, _ios_obj(ios, per_dev->dev),
+                       ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp),
                                                 per_dev->offset,
                                                 ios->kern_buff, ios->length);
                        if (unlikely(ret))
                                goto out;
                        ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     _LLU(per_dev->offset),
                                     _LLU(ios->length), per_dev->dev);
                } else {
-                       osd_req_set_attributes(or, _ios_obj(ios, dev));
+                       osd_req_set_attributes(or, _ios_obj(ios, cur_comp));
                        ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     ios->out_attr_len, dev);
                }
 
index 433783624d107d1d29fd16ffb1c4890ecd78c7cd..dde41a75c7c8dbd36597272a13f5c6f3487507d3 100644 (file)
@@ -400,8 +400,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait)
        ret = ore_write(ios);
        if (unlikely(ret))
                EXOFS_ERR("%s: ore_write failed.\n", __func__);
-       else
-               sb->s_dirt = 0;
 
 
        unlock_super(sb);
@@ -412,14 +410,6 @@ out:
        return ret;
 }
 
-static void exofs_write_super(struct super_block *sb)
-{
-       if (!(sb->s_flags & MS_RDONLY))
-               exofs_sync_fs(sb, 1);
-       else
-               sb->s_dirt = 0;
-}
-
 static void _exofs_print_device(const char *msg, const char *dev_path,
                                struct osd_dev *od, u64 pid)
 {
@@ -952,7 +942,6 @@ static const struct super_operations exofs_sops = {
        .write_inode    = exofs_write_inode,
        .evict_inode    = exofs_evict_inode,
        .put_super      = exofs_put_super,
-       .write_super    = exofs_write_super,
        .sync_fs        = exofs_sync_fs,
        .statfs         = exofs_statfs,
 };
index 9a4a5c48b1c99f6a60ff02d35cda4ef1ced9bd50..a07597307fd1cd221b20997d9e0268caa6bc9138 100644 (file)
@@ -3459,14 +3459,6 @@ ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
  * inode out, but prune_icache isn't a user-visible syncing function.
  * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
  * we start and wait on commits.
- *
- * Is this efficient/effective?  Well, we're being nice to the system
- * by cleaning up our inodes proactively so they can be reaped
- * without I/O.  But we are potentially leaving up to five seconds'
- * worth of inodes floating about which prune_icache wants us to
- * write out.  One way to fix that would be to get prune_icache()
- * to do a write_super() to free up some memory.  It has the desired
- * effect.
  */
 int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
 {
index ff9bcdc5b0d5a7b5f210723092716e9e0f32937c..8c892e93d8e7b6f2ff727709619eedde0e880812 100644 (file)
@@ -64,11 +64,6 @@ static int ext3_freeze(struct super_block *sb);
 
 /*
  * Wrappers for journal_start/end.
- *
- * The only special thing we need to do here is to make sure that all
- * journal_end calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
  */
 handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
 {
@@ -90,12 +85,6 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
        return journal_start(journal, nblocks);
 }
 
-/*
- * The only special thing we need to do here is to make sure that all
- * journal_stop calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
- */
 int __ext3_journal_stop(const char *where, handle_t *handle)
 {
        struct super_block *sb;
index d23b31ca9d7a713cfff0899889dd6eeb46f1b2c6..1b5089067d018d581c68242f39fcf522a8fee55d 100644 (file)
@@ -280,14 +280,18 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
        return desc;
 }
 
-static int ext4_valid_block_bitmap(struct super_block *sb,
-                                  struct ext4_group_desc *desc,
-                                  unsigned int block_group,
-                                  struct buffer_head *bh)
+/*
+ * Return the block number which was discovered to be invalid, or 0 if
+ * the block bitmap is valid.
+ */
+static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
+                                           struct ext4_group_desc *desc,
+                                           unsigned int block_group,
+                                           struct buffer_head *bh)
 {
        ext4_grpblk_t offset;
        ext4_grpblk_t next_zero_bit;
-       ext4_fsblk_t bitmap_blk;
+       ext4_fsblk_t blk;
        ext4_fsblk_t group_first_block;
 
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
@@ -297,37 +301,33 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
                 * or it has to also read the block group where the bitmaps
                 * are located to verify they are set.
                 */
-               return 1;
+               return 0;
        }
        group_first_block = ext4_group_first_block_no(sb, block_group);
 
        /* check whether block bitmap block number is set */
-       bitmap_blk = ext4_block_bitmap(sb, desc);
-       offset = bitmap_blk - group_first_block;
+       blk = ext4_block_bitmap(sb, desc);
+       offset = blk - group_first_block;
        if (!ext4_test_bit(offset, bh->b_data))
                /* bad block bitmap */
-               goto err_out;
+               return blk;
 
        /* check whether the inode bitmap block number is set */
-       bitmap_blk = ext4_inode_bitmap(sb, desc);
-       offset = bitmap_blk - group_first_block;
+       blk = ext4_inode_bitmap(sb, desc);
+       offset = blk - group_first_block;
        if (!ext4_test_bit(offset, bh->b_data))
                /* bad block bitmap */
-               goto err_out;
+               return blk;
 
        /* check whether the inode table block number is set */
-       bitmap_blk = ext4_inode_table(sb, desc);
-       offset = bitmap_blk - group_first_block;
+       blk = ext4_inode_table(sb, desc);
+       offset = blk - group_first_block;
        next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
                                offset + EXT4_SB(sb)->s_itb_per_group,
                                offset);
-       if (next_zero_bit >= offset + EXT4_SB(sb)->s_itb_per_group)
-               /* good bitmap for inode tables */
-               return 1;
-
-err_out:
-       ext4_error(sb, "Invalid block bitmap - block_group = %d, block = %llu",
-                       block_group, bitmap_blk);
+       if (next_zero_bit < offset + EXT4_SB(sb)->s_itb_per_group)
+               /* bad bitmap for inode tables */
+               return blk;
        return 0;
 }
 
@@ -336,14 +336,26 @@ void ext4_validate_block_bitmap(struct super_block *sb,
                               unsigned int block_group,
                               struct buffer_head *bh)
 {
+       ext4_fsblk_t    blk;
+
        if (buffer_verified(bh))
                return;
 
        ext4_lock_group(sb, block_group);
-       if (ext4_valid_block_bitmap(sb, desc, block_group, bh) &&
-           ext4_block_bitmap_csum_verify(sb, block_group, desc, bh,
-                                         EXT4_BLOCKS_PER_GROUP(sb) / 8))
-               set_buffer_verified(bh);
+       blk = ext4_valid_block_bitmap(sb, desc, block_group, bh);
+       if (unlikely(blk != 0)) {
+               ext4_unlock_group(sb, block_group);
+               ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
+                          block_group, blk);
+               return;
+       }
+       if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
+                       desc, bh, EXT4_BLOCKS_PER_GROUP(sb) / 8))) {
+               ext4_unlock_group(sb, block_group);
+               ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
+               return;
+       }
+       set_buffer_verified(bh);
        ext4_unlock_group(sb, block_group);
 }
 
index f8716eab99952401dc473deb6619295b4a830f3b..5c2d1813ebe919188d53dac74de8b512a7f02965 100644 (file)
@@ -79,7 +79,6 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
        if (provided == calculated)
                return 1;
 
-       ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group);
        return 0;
 }
 
index cd0c7ed0677200d09ce1445def04452a2f178978..aabbb3f53683f54081cd04c9a6d150e0121cc640 100644 (file)
@@ -2662,6 +2662,7 @@ cont:
                }
                path[0].p_depth = depth;
                path[0].p_hdr = ext_inode_hdr(inode);
+               i = 0;
 
                if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
                        err = -EIO;
index 6324f74e03424e9ac21ceb01f6fbee07caa546df..dff171c3a1234e2ea9f545d8c2fd65c1b9b4bc1d 100644 (file)
@@ -1970,7 +1970,7 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate);
  * This function can get called via...
  *   - ext4_da_writepages after taking page lock (have journal handle)
  *   - journal_submit_inode_data_buffers (no journal handle)
- *   - shrink_page_list via pdflush (no journal handle)
+ *   - shrink_page_list via the kswapd/direct reclaim (no journal handle)
  *   - grab_page_cache when doing write_begin (have journal handle)
  *
  * We don't do any block allocation in this function. If we have page with
@@ -4589,14 +4589,6 @@ static int ext4_expand_extra_isize(struct inode *inode,
  * inode out, but prune_icache isn't a user-visible syncing function.
  * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
  * we start and wait on commits.
- *
- * Is this efficient/effective?  Well, we're being nice to the system
- * by cleaning up our inodes proactively so they can be reaped
- * without I/O.  But we are potentially leaving up to five seconds'
- * worth of inodes floating about which prune_icache wants us to
- * write out.  One way to fix that would be to get prune_icache()
- * to do a write_super() to free up some memory.  It has the desired
- * effect.
  */
 int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
 {
index d76ec8277d3fca660e619d097711cc0057349823..c6e0cb3d1f4a9e3730aea4904037eb0e9d4dd6d8 100644 (file)
@@ -326,11 +326,6 @@ static void ext4_put_nojournal(handle_t *handle)
 
 /*
  * Wrappers for jbd2_journal_start/end.
- *
- * The only special thing we need to do here is to make sure that all
- * journal_end calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
  */
 handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
 {
@@ -356,12 +351,6 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
        return jbd2_journal_start(journal, nblocks);
 }
 
-/*
- * The only special thing we need to do here is to make sure that all
- * jbd2_journal_stop calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
- */
 int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
 {
        struct super_block *sb;
@@ -959,6 +948,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_reserved_meta_blocks = 0;
        ei->i_allocated_meta_blocks = 0;
        ei->i_da_metadata_calc_len = 0;
+       ei->i_da_metadata_calc_last_lblock = 0;
        spin_lock_init(&(ei->i_block_reservation_lock));
 #ifdef CONFIG_QUOTA
        ei->i_reserved_quota = 0;
@@ -3119,6 +3109,10 @@ static int count_overhead(struct super_block *sb, ext4_group_t grp,
        ext4_group_t            i, ngroups = ext4_get_groups_count(sb);
        int                     s, j, count = 0;
 
+       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+               return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) +
+                       sbi->s_itb_per_group + 2);
+
        first_block = le32_to_cpu(sbi->s_es->s_first_data_block) +
                (grp * EXT4_BLOCKS_PER_GROUP(sb));
        last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1;
@@ -4430,6 +4424,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
                ext4_commit_super(sb, 1);
 
                jbd2_journal_clear_err(journal);
+               jbd2_journal_update_sb_errno(journal);
        }
 }
 
index 8964cf3999b2bb561ec71d93914170529f72977a..324bc085053447665eccaacdc8fcf169cb418413 100644 (file)
@@ -383,6 +383,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
        struct fuse_entry_out outentry;
        struct fuse_file *ff;
 
+       /* Userspace expects S_IFREG in create mode */
+       BUG_ON((mode & S_IFMT) != S_IFREG);
+
        forget = fuse_alloc_forget();
        err = -ENOMEM;
        if (!forget)
index 93d8d6c9494dbd5737b0842a3ebb55ef972e0d87..aba15f1b7ad2974aa85e2c7272afc3d7836a40bc 100644 (file)
@@ -703,13 +703,16 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                                  unsigned long nr_segs, loff_t pos)
 {
        struct inode *inode = iocb->ki_filp->f_mapping->host;
+       struct fuse_conn *fc = get_fuse_conn(inode);
 
-       if (pos + iov_length(iov, nr_segs) > i_size_read(inode)) {
+       /*
+        * In auto invalidate mode, always update attributes on read.
+        * Otherwise, only update if we attempt to read past EOF (to ensure
+        * i_size is up to date).
+        */
+       if (fc->auto_inval_data ||
+           (pos + iov_length(iov, nr_segs) > i_size_read(inode))) {
                int err;
-               /*
-                * If trying to read past EOF, make sure the i_size
-                * attribute is up-to-date.
-                */
                err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
                if (err)
                        return err;
@@ -1700,7 +1703,7 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
        size_t n;
        u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
 
-       for (n = 0; n < count; n++) {
+       for (n = 0; n < count; n++, iov++) {
                if (iov->iov_len > (size_t) max)
                        return -ENOMEM;
                max -= iov->iov_len;
index 771fb6322c0750d223bb2ee7873f6d0cdbdef41b..e24dd74e3068d130545ee58f918519d4ca2ee620 100644 (file)
@@ -484,6 +484,9 @@ struct fuse_conn {
        /** Is fallocate not implemented by fs? */
        unsigned no_fallocate:1;
 
+       /** Use enhanced/automatic page cache invalidation. */
+       unsigned auto_inval_data:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
index 1cd61652018c7c8547a060344ef998ee6ae96879..ce0a2838ccd097a5392d469fc0650d2e7b0d7e8d 100644 (file)
@@ -197,6 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
        loff_t oldsize;
+       struct timespec old_mtime;
 
        spin_lock(&fc->lock);
        if (attr_version != 0 && fi->attr_version > attr_version) {
@@ -204,15 +205,35 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
                return;
        }
 
+       old_mtime = inode->i_mtime;
        fuse_change_attributes_common(inode, attr, attr_valid);
 
        oldsize = inode->i_size;
        i_size_write(inode, attr->size);
        spin_unlock(&fc->lock);
 
-       if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
-               truncate_pagecache(inode, oldsize, attr->size);
-               invalidate_inode_pages2(inode->i_mapping);
+       if (S_ISREG(inode->i_mode)) {
+               bool inval = false;
+
+               if (oldsize != attr->size) {
+                       truncate_pagecache(inode, oldsize, attr->size);
+                       inval = true;
+               } else if (fc->auto_inval_data) {
+                       struct timespec new_mtime = {
+                               .tv_sec = attr->mtime,
+                               .tv_nsec = attr->mtimensec,
+                       };
+
+                       /*
+                        * Auto inval mode also checks and invalidates if mtime
+                        * has changed.
+                        */
+                       if (!timespec_equal(&old_mtime, &new_mtime))
+                               inval = true;
+               }
+
+               if (inval)
+                       invalidate_inode_pages2(inode->i_mapping);
        }
 }
 
@@ -834,6 +855,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->big_writes = 1;
                        if (arg->flags & FUSE_DONT_MASK)
                                fc->dont_mask = 1;
+                       if (arg->flags & FUSE_AUTO_INVAL_DATA)
+                               fc->auto_inval_data = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -859,7 +882,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
-               FUSE_FLOCK_LOCKS;
+               FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
+               FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
index 3a56c8d94de0607249e6296a18ec28b5ea120e89..22255d96b27efbb9c3a93e6db8678a147d99548b 100644 (file)
@@ -52,7 +52,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
                /*
                 * If it's a fully non-blocking write attempt and we cannot
                 * lock the buffer then redirty the page.  Note that this can
-                * potentially cause a busy-wait loop from pdflush and kswapd
+                * potentially cause a busy-wait loop from flusher thread and kswapd
                 * activity, but those code paths have their own higher-level
                 * throttling.
                 */
index 5fd51a5833ffb91facba871b74589bf8b9a6c087..b7ec224910c5d7bda2f36432260fa6a6050d76d4 100644 (file)
@@ -236,10 +236,10 @@ out:
  * hfs_mdb_commit()
  *
  * Description:
- *   This updates the MDB on disk (look also at hfs_write_super()).
+ *   This updates the MDB on disk.
  *   It does not check, if the superblock has been modified, or
  *   if the filesystem has been mounted read-only. It is mainly
- *   called by hfs_write_super() and hfs_btree_extend().
+ *   called by hfs_sync_fs() and flush_mdb().
  * Input Variable(s):
  *   struct hfs_mdb *mdb: Pointer to the hfs MDB
  *   int backup;
index 425c2f2cf1700a3f5d9db8fc4e93dcde0450d998..09357508ec9ae5aebbac1e2ccbd44d42087bfd4a 100644 (file)
@@ -534,8 +534,8 @@ int journal_start_commit(journal_t *journal, tid_t *ptid)
                ret = 1;
        } else if (journal->j_committing_transaction) {
                /*
-                * If ext3_write_super() recently started a commit, then we
-                * have to wait for completion of that transaction
+                * If commit has been started, then we have to wait for
+                * completion of that transaction.
                 */
                if (ptid)
                        *ptid = journal->j_committing_transaction->t_tid;
index e9a3c4c85594e30aca1ed1f14d5667ba0595160a..e149b99a7ffb8e0c0db2a042aaac864f5fc65348 100644 (file)
@@ -612,8 +612,8 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
                ret = 1;
        } else if (journal->j_committing_transaction) {
                /*
-                * If ext3_write_super() recently started a commit, then we
-                * have to wait for completion of that transaction
+                * If commit has been started, then we have to wait for
+                * completion of that transaction.
                 */
                if (ptid)
                        *ptid = journal->j_committing_transaction->t_tid;
@@ -1377,7 +1377,7 @@ static void jbd2_mark_journal_empty(journal_t *journal)
  * Update a journal's errno.  Write updated superblock to disk waiting for IO
  * to complete.
  */
-static void jbd2_journal_update_sb_errno(journal_t *journal)
+void jbd2_journal_update_sb_errno(journal_t *journal)
 {
        journal_superblock_t *sb = journal->j_superblock;
 
@@ -1390,6 +1390,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal)
 
        jbd2_write_superblock(journal, WRITE_SYNC);
 }
+EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
 
 /*
  * Read the superblock for a given journal, performing initial
index 1b464390dde85ecd783eb45f64aee1f89f6c3ff1..dd1ed1b8e98efe048683e81bd1244c483160ad55 100644 (file)
@@ -352,6 +352,7 @@ int __inode_permission(struct inode *inode, int mask)
 /**
  * sb_permission - Check superblock-level permissions
  * @sb: Superblock of inode to check permission on
+ * @inode: Inode to check permission on
  * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
  *
  * Separate out file-system wide checks from inode-specific permission checks.
@@ -656,6 +657,7 @@ int sysctl_protected_hardlinks __read_mostly = 1;
 /**
  * may_follow_link - Check symlink following for unsafe situations
  * @link: The path of the symlink
+ * @nd: nameidata pathwalk data
  *
  * In the case of the sysctl_protected_symlinks sysctl being enabled,
  * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
@@ -2414,7 +2416,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                goto out;
        }
 
-       mode = op->mode & S_IALLUGO;
+       mode = op->mode;
        if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
                mode &= ~current_umask();
 
@@ -2452,7 +2454,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
        }
 
        if (open_flag & O_CREAT) {
-               error = may_o_create(&nd->path, dentry, op->mode);
+               error = may_o_create(&nd->path, dentry, mode);
                if (error) {
                        create_error = error;
                        if (open_flag & O_EXCL)
@@ -2489,6 +2491,10 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        dput(dentry);
                        dentry = file->f_path.dentry;
                }
+               if (create_error && dentry->d_inode == NULL) {
+                       error = create_error;
+                       goto out;
+               }
                goto looked_up;
        }
 
index 8bf3a3f6925ab7459d93416f171b05d8cbf13cb7..b7db60897f91d5e8be99f59400add178cd082b8e 100644 (file)
@@ -12,19 +12,19 @@ nfs-$(CONFIG_ROOT_NFS)      += nfsroot.o
 nfs-$(CONFIG_SYSCTL)   += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
 
-obj-$(CONFIG_NFS_V2) += nfs2.o
-nfs2-y := nfs2super.o proc.o nfs2xdr.o
+obj-$(CONFIG_NFS_V2) += nfsv2.o
+nfsv2-y := nfs2super.o proc.o nfs2xdr.o
 
-obj-$(CONFIG_NFS_V3) += nfs3.o
-nfs3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
-nfs3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
+obj-$(CONFIG_NFS_V3) += nfsv3.o
+nfsv3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
+nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
 
-obj-$(CONFIG_NFS_V4) += nfs4.o
-nfs4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
+obj-$(CONFIG_NFS_V4) += nfsv4.o
+nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
          delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \
          nfs4namespace.o nfs4getroot.o nfs4client.o
-nfs4-$(CONFIG_SYSCTL)  += nfs4sysctl.o
-nfs4-$(CONFIG_NFS_V4_1)        += pnfs.o pnfs_dev.o
+nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
+nfsv4-$(CONFIG_NFS_V4_1)       += pnfs.o pnfs_dev.o
 
 obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
index 9fc0d9dfc91b8a5e4226b0fcfb56bb55658f0869..99694442b93f6d64f5f433d8cf3cc8fdc08de52e 100644 (file)
@@ -105,7 +105,7 @@ struct nfs_subversion *get_nfs_version(unsigned int version)
 
        if (IS_ERR(nfs)) {
                mutex_lock(&nfs_version_mutex);
-               request_module("nfs%d", version);
+               request_module("nfsv%d", version);
                nfs = find_nfs_version(version);
                mutex_unlock(&nfs_version_mutex);
        }
index b701358c39c351d0613d1db29ebcf382ca8cb0a6..a850079467d85f149d997b9c96176c9a0829be0d 100644 (file)
@@ -61,6 +61,12 @@ struct idmap {
        struct mutex            idmap_mutex;
 };
 
+struct idmap_legacy_upcalldata {
+       struct rpc_pipe_msg pipe_msg;
+       struct idmap_msg idmap_msg;
+       struct idmap *idmap;
+};
+
 /**
  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
  * @fattr: fully initialised struct nfs_fattr
@@ -324,6 +330,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
                ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
                                            name, namelen, type, data,
                                            data_size, idmap);
+               idmap->idmap_key_cons = NULL;
                mutex_unlock(&idmap->idmap_mutex);
        }
        return ret;
@@ -380,11 +387,13 @@ static const match_table_t nfs_idmap_tokens = {
 static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
 static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
                                   size_t);
+static void idmap_release_pipe(struct inode *);
 static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 
 static const struct rpc_pipe_ops idmap_upcall_ops = {
        .upcall         = rpc_pipe_generic_upcall,
        .downcall       = idmap_pipe_downcall,
+       .release_pipe   = idmap_release_pipe,
        .destroy_msg    = idmap_pipe_destroy_msg,
 };
 
@@ -616,7 +625,8 @@ void nfs_idmap_quit(void)
        nfs_idmap_quit_keyring();
 }
 
-static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
+static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
+                                    struct idmap_msg *im,
                                     struct rpc_pipe_msg *msg)
 {
        substring_t substr;
@@ -659,6 +669,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
                                   const char *op,
                                   void *aux)
 {
+       struct idmap_legacy_upcalldata *data;
        struct rpc_pipe_msg *msg;
        struct idmap_msg *im;
        struct idmap *idmap = (struct idmap *)aux;
@@ -666,15 +677,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
        int ret = -ENOMEM;
 
        /* msg and im are freed in idmap_pipe_destroy_msg */
-       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
-       if (!msg)
-               goto out0;
-
-       im = kmalloc(sizeof(*im), GFP_KERNEL);
-       if (!im)
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
                goto out1;
 
-       ret = nfs_idmap_prepare_message(key->description, im, msg);
+       msg = &data->pipe_msg;
+       im = &data->idmap_msg;
+       data->idmap = idmap;
+
+       ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
        if (ret < 0)
                goto out2;
 
@@ -683,15 +694,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
 
        ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
        if (ret < 0)
-               goto out2;
+               goto out3;
 
        return ret;
 
+out3:
+       idmap->idmap_key_cons = NULL;
 out2:
-       kfree(im);
+       kfree(data);
 out1:
-       kfree(msg);
-out0:
        complete_request_key(cons, ret);
        return ret;
 }
@@ -749,9 +760,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        }
 
        if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
-               ret = mlen;
-               complete_request_key(cons, -ENOKEY);
-               goto out_incomplete;
+               ret = -ENOKEY;
+               goto out;
        }
 
        namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
@@ -768,16 +778,32 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 
 out:
        complete_request_key(cons, ret);
-out_incomplete:
        return ret;
 }
 
 static void
 idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
+       struct idmap_legacy_upcalldata *data = container_of(msg,
+                       struct idmap_legacy_upcalldata,
+                       pipe_msg);
+       struct idmap *idmap = data->idmap;
+       struct key_construction *cons;
+       if (msg->errno) {
+               cons = ACCESS_ONCE(idmap->idmap_key_cons);
+               idmap->idmap_key_cons = NULL;
+               complete_request_key(cons, msg->errno);
+       }
        /* Free memory allocated in nfs_idmap_legacy_upcall() */
-       kfree(msg->data);
-       kfree(msg);
+       kfree(data);
+}
+
+static void
+idmap_release_pipe(struct inode *inode)
+{
+       struct rpc_inode *rpci = RPC_I(inode);
+       struct idmap *idmap = (struct idmap *)rpci->private;
+       idmap->idmap_key_cons = NULL;
 }
 
 int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
index 0952c791df36eb4f1aa58beb20732c9af67a3098..d6b3b5f2d779acd1ce7e0324e8c52e388c7a273a 100644 (file)
@@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
        nfs_fattr_init(info->fattr);
        status = rpc_call_sync(client, &msg, 0);
        dprintk("%s: reply fsinfo: %d\n", __func__, status);
-       if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
+       if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) {
                msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
                msg.rpc_resp = info->fattr;
                status = rpc_call_sync(client, &msg, 0);
index 3b950dd81e81f82b4fd32c5b508fde181d07b875..da0618aeeadb88c04447a63b18e2d908b6d03955 100644 (file)
@@ -205,6 +205,9 @@ extern const struct dentry_operations nfs4_dentry_operations;
 int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
                    unsigned, umode_t, int *);
 
+/* super.c */
+extern struct file_system_type nfs4_fs_type;
+
 /* nfs4namespace.c */
 rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
 struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
index cbcdfaf325054e215159f2d1c1797994eff050ac..24eb663f8ed528426572471a629ab033726919d8 100644 (file)
@@ -74,7 +74,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
        return clp;
 
 error:
-       kfree(clp);
+       nfs_free_client(clp);
        return ERR_PTR(err);
 }
 
index a99a8d94872131610ab543d5a06d9f4f541cc2dc..635274140b180287668dbaa7540bd84852051181 100644 (file)
@@ -3737,9 +3737,10 @@ out:
 static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
 {
        struct nfs4_cached_acl *acl;
+       size_t buflen = sizeof(*acl) + acl_len;
 
-       if (pages && acl_len <= PAGE_SIZE) {
-               acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
+       if (pages && buflen <= PAGE_SIZE) {
+               acl = kmalloc(buflen, GFP_KERNEL);
                if (acl == NULL)
                        goto out;
                acl->cached = 1;
@@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
        if (ret)
                goto out_free;
 
-       acl_len = res.acl_len - res.acl_data_offset;
+       acl_len = res.acl_len;
        if (acl_len > args.acl_len)
                nfs4_write_cached_acl(inode, NULL, 0, acl_len);
        else
@@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        dprintk("<-- %s\n", __func__);
 }
 
+static size_t max_response_pages(struct nfs_server *server)
+{
+       u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+       return nfs_page_array_len(0, max_resp_sz);
+}
+
+static void nfs4_free_pages(struct page **pages, size_t size)
+{
+       int i;
+
+       if (!pages)
+               return;
+
+       for (i = 0; i < size; i++) {
+               if (!pages[i])
+                       break;
+               __free_page(pages[i]);
+       }
+       kfree(pages);
+}
+
+static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
+{
+       struct page **pages;
+       int i;
+
+       pages = kcalloc(size, sizeof(struct page *), gfp_flags);
+       if (!pages) {
+               dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
+               return NULL;
+       }
+
+       for (i = 0; i < size; i++) {
+               pages[i] = alloc_page(gfp_flags);
+               if (!pages[i]) {
+                       dprintk("%s: failed to allocate page\n", __func__);
+                       nfs4_free_pages(pages, size);
+                       return NULL;
+               }
+       }
+
+       return pages;
+}
+
 static void nfs4_layoutget_release(void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       size_t max_pages = max_response_pages(server);
 
        dprintk("--> %s\n", __func__);
+       nfs4_free_pages(lgp->args.layout.pages, max_pages);
        put_nfs_open_context(lgp->args.ctx);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
@@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
        .rpc_release = nfs4_layoutget_release,
 };
 
-int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
+void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
 {
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       size_t max_pages = max_response_pages(server);
        struct rpc_task *task;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
@@ -6259,12 +6308,19 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
 
        dprintk("--> %s\n", __func__);
 
+       lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
+       if (!lgp->args.layout.pages) {
+               nfs4_layoutget_release(lgp);
+               return;
+       }
+       lgp->args.layout.pglen = max_pages * PAGE_SIZE;
+
        lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
        nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
-               return PTR_ERR(task);
+               return;
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
@@ -6272,7 +6328,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
                status = pnfs_layout_process(lgp);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
-       return status;
+       return;
 }
 
 static void
@@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
                return;
        }
        spin_lock(&lo->plh_inode->i_lock);
-       if (task->tk_status == 0) {
-               if (lrp->res.lrs_present) {
-                       pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
-               } else
-                       BUG_ON(!list_empty(&lo->plh_segs));
-       }
+       if (task->tk_status == 0 && lrp->res.lrs_present)
+               pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
        lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
        dprintk("<-- %s\n", __func__);
index 12a31a9dbcddc562e7f55e65ae4952810dccb3f7..bd61221ad2c5542b08f42249d10285c159f66b1d 100644 (file)
@@ -23,14 +23,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *raw_data);
 
-static struct file_system_type nfs4_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs_fs_mount,
-       .kill_sb        = nfs_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
 static struct file_system_type nfs4_remote_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "nfs4",
@@ -344,14 +336,8 @@ static int __init init_nfs_v4(void)
        if (err)
                goto out1;
 
-       err = register_filesystem(&nfs4_fs_type);
-       if (err < 0)
-               goto out2;
-
        register_nfs_version(&nfs_v4);
        return 0;
-out2:
-       nfs4_unregister_sysctl();
 out1:
        nfs_idmap_quit();
 out:
@@ -361,7 +347,6 @@ out:
 static void __exit exit_nfs_v4(void)
 {
        unregister_nfs_version(&nfs_v4);
-       unregister_filesystem(&nfs4_fs_type);
        nfs4_unregister_sysctl();
        nfs_idmap_quit();
 }
index ca13483edd60aee67c8e1673b18250959187f8a4..1bfbd67c556d753a21f046c87edc3c9b07b0b8f0 100644 (file)
@@ -5045,22 +5045,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                         struct nfs_getaclres *res)
 {
        unsigned int savep;
-       __be32 *bm_p;
        uint32_t attrlen,
                 bitmap[3] = {0};
        int status;
-       size_t page_len = xdr->buf->page_len;
+       unsigned int pg_offset;
 
        res->acl_len = 0;
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
                goto out;
 
-       bm_p = xdr->p;
-       res->acl_data_offset = be32_to_cpup(bm_p) + 2;
-       res->acl_data_offset <<= 2;
-       /* Check if the acl data starts beyond the allocated buffer */
-       if (res->acl_data_offset > page_len)
-               return -ERANGE;
+       xdr_enter_page(xdr, xdr->buf->page_len);
+
+       /* Calculate the offset of the page data */
+       pg_offset = xdr->buf->head[0].iov_len;
 
        if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
                goto out;
@@ -5074,23 +5071,20 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                /* The bitmap (xdr len + bitmaps) and the attr xdr len words
                 * are stored with the acl data to handle the problem of
                 * variable length bitmaps.*/
-               xdr->p = bm_p;
+               res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset;
 
                /* We ignore &savep and don't do consistency checks on
                 * the attr length.  Let userspace figure it out.... */
-               attrlen += res->acl_data_offset;
-               if (attrlen > page_len) {
+               res->acl_len = attrlen;
+               if (attrlen > (xdr->nwords << 2)) {
                        if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
                                /* getxattr interface called with a NULL buf */
-                               res->acl_len = attrlen;
                                goto out;
                        }
-                       dprintk("NFS: acl reply: attrlen %u > page_len %zu\n",
-                                       attrlen, page_len);
+                       dprintk("NFS: acl reply: attrlen %u > page_len %u\n",
+                                       attrlen, xdr->nwords << 2);
                        return -EINVAL;
                }
-               xdr_read_pages(xdr, attrlen);
-               res->acl_len = attrlen;
        } else
                status = -EOPNOTSUPP;
 
index f50d3e8d6f2230a42cdc656b61004dcf62182dd2..ea6d111b03e9484c23d5ca3f7997f10d893a57ad 100644 (file)
@@ -570,17 +570,66 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,
                return false;
 
        return pgio->pg_count + req->wb_bytes <=
-                       OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+                       (unsigned long)pgio->pg_layout_private;
+}
+
+void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       pnfs_generic_pg_init_read(pgio, req);
+       if (unlikely(pgio->pg_lseg == NULL))
+               return; /* Not pNFS */
+
+       pgio->pg_layout_private = (void *)
+                               OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+}
+
+static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,
+                                  unsigned long *stripe_end)
+{
+       u32 stripe_off;
+       unsigned stripe_size;
+
+       if (layout->raid_algorithm == PNFS_OSD_RAID_0)
+               return true;
+
+       stripe_size = layout->stripe_unit *
+                               (layout->group_width - layout->parity);
+
+       div_u64_rem(offset, stripe_size, &stripe_off);
+       if (!stripe_off)
+               return true;
+
+       *stripe_end = stripe_size - stripe_off;
+       return false;
+}
+
+void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       unsigned long stripe_end = 0;
+
+       pnfs_generic_pg_init_write(pgio, req);
+       if (unlikely(pgio->pg_lseg == NULL))
+               return; /* Not pNFS */
+
+       if (req->wb_offset ||
+           !aligned_on_raid_stripe(req->wb_index * PAGE_SIZE,
+                              &OBJIO_LSEG(pgio->pg_lseg)->layout,
+                              &stripe_end)) {
+               pgio->pg_layout_private = (void *)stripe_end;
+       } else {
+               pgio->pg_layout_private = (void *)
+                               OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+       }
 }
 
 static const struct nfs_pageio_ops objio_pg_read_ops = {
-       .pg_init = pnfs_generic_pg_init_read,
+       .pg_init = objio_init_read,
        .pg_test = objio_pg_test,
        .pg_doio = pnfs_generic_pg_readpages,
 };
 
 static const struct nfs_pageio_ops objio_pg_write_ops = {
-       .pg_init = pnfs_generic_pg_init_write,
+       .pg_init = objio_init_write,
        .pg_test = objio_pg_test,
        .pg_doio = pnfs_generic_pg_writepages,
 };
index 1a6732ed04a447aa14147468e15f4b7956557376..311a79681e2b16311724e25921d922768c999026 100644 (file)
@@ -49,6 +49,7 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
        hdr->io_start = req_offset(hdr->req);
        hdr->good_bytes = desc->pg_count;
        hdr->dreq = desc->pg_dreq;
+       hdr->layout_private = desc->pg_layout_private;
        hdr->release = release;
        hdr->completion_ops = desc->pg_completion_ops;
        if (hdr->completion_ops->init_hdr)
@@ -268,6 +269,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
        desc->pg_error = 0;
        desc->pg_lseg = NULL;
        desc->pg_dreq = NULL;
+       desc->pg_layout_private = NULL;
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_init);
 
index 76875bfcf19ceda4a54cb0dde14466a304191cf9..2e00feacd4bee642c59c965612068653f120756c 100644 (file)
@@ -583,9 +583,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        struct nfs_server *server = NFS_SERVER(ino);
        struct nfs4_layoutget *lgp;
        struct pnfs_layout_segment *lseg = NULL;
-       struct page **pages = NULL;
-       int i;
-       u32 max_resp_sz, max_pages;
 
        dprintk("--> %s\n", __func__);
 
@@ -594,20 +591,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        if (lgp == NULL)
                return NULL;
 
-       /* allocate pages for xdr post processing */
-       max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
-       max_pages = nfs_page_array_len(0, max_resp_sz);
-
-       pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
-       if (!pages)
-               goto out_err_free;
-
-       for (i = 0; i < max_pages; i++) {
-               pages[i] = alloc_page(gfp_flags);
-               if (!pages[i])
-                       goto out_err_free;
-       }
-
        lgp->args.minlength = PAGE_CACHE_SIZE;
        if (lgp->args.minlength > range->length)
                lgp->args.minlength = range->length;
@@ -616,39 +599,19 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp->args.type = server->pnfs_curr_ld->id;
        lgp->args.inode = ino;
        lgp->args.ctx = get_nfs_open_context(ctx);
-       lgp->args.layout.pages = pages;
-       lgp->args.layout.pglen = max_pages * PAGE_SIZE;
        lgp->lsegpp = &lseg;
        lgp->gfp_flags = gfp_flags;
 
        /* Synchronously retrieve layout information from server and
         * store in lseg.
         */
-       nfs4_proc_layoutget(lgp);
+       nfs4_proc_layoutget(lgp, gfp_flags);
        if (!lseg) {
                /* remember that LAYOUTGET failed and suspend trying */
                set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
        }
 
-       /* free xdr pages */
-       for (i = 0; i < max_pages; i++)
-               __free_page(pages[i]);
-       kfree(pages);
-
        return lseg;
-
-out_err_free:
-       /* free any allocated xdr pages, lgp as it's not used */
-       if (pages) {
-               for (i = 0; i < max_pages; i++) {
-                       if (!pages[i])
-                               break;
-                       __free_page(pages[i]);
-               }
-               kfree(pages);
-       }
-       kfree(lgp);
-       return NULL;
 }
 
 /*
index 2c6c80503ba4851ed1e69c253293684c540b2c32..745aa1b39e7c3d1e543a1c0beae0113c99a23cac 100644 (file)
@@ -172,7 +172,7 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server,
                                   struct pnfs_devicelist *devlist);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev);
-extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
+extern void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
 extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
 
 /* pnfs.c */
index ac6a3c55dce408afbd5348a2f9af42a7f78e660e..239aff7338eb89ee8c0d4080694178317d84929e 100644 (file)
@@ -319,6 +319,34 @@ EXPORT_SYMBOL_GPL(nfs_sops);
 static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *);
 static int nfs4_validate_mount_data(void *options,
        struct nfs_parsed_mount_data *args, const char *dev_name);
+
+struct file_system_type nfs4_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs_fs_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+EXPORT_SYMBOL_GPL(nfs4_fs_type);
+
+static int __init register_nfs4_fs(void)
+{
+       return register_filesystem(&nfs4_fs_type);
+}
+
+static void unregister_nfs4_fs(void)
+{
+       unregister_filesystem(&nfs4_fs_type);
+}
+#else
+static int __init register_nfs4_fs(void)
+{
+       return 0;
+}
+
+static void unregister_nfs4_fs(void)
+{
+}
 #endif
 
 static struct shrinker acl_shrinker = {
@@ -337,12 +365,18 @@ int __init register_nfs_fs(void)
        if (ret < 0)
                goto error_0;
 
-       ret = nfs_register_sysctl();
+       ret = register_nfs4_fs();
        if (ret < 0)
                goto error_1;
+
+       ret = nfs_register_sysctl();
+       if (ret < 0)
+               goto error_2;
        register_shrinker(&acl_shrinker);
        return 0;
 
+error_2:
+       unregister_nfs4_fs();
 error_1:
        unregister_filesystem(&nfs_fs_type);
 error_0:
@@ -356,6 +390,7 @@ void __exit unregister_nfs_fs(void)
 {
        unregister_shrinker(&acl_shrinker);
        nfs_unregister_sysctl();
+       unregister_nfs4_fs();
        unregister_filesystem(&nfs_fs_type);
 }
 
@@ -2645,4 +2680,6 @@ MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
 module_param(send_implementation_id, ushort, 0644);
 MODULE_PARM_DESC(send_implementation_id,
                "Send implementation ID with NFSv4.1 exchange_id");
+MODULE_ALIAS("nfs4");
+
 #endif /* CONFIG_NFS_V4 */
index 5829d0ce7cfb574f28451380b153df72d3dcd18f..e3b55372726cb0d2a082c62ed86a35e8605c66b5 100644 (file)
@@ -1814,19 +1814,19 @@ int __init nfs_init_writepagecache(void)
        nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
                                                     nfs_wdata_cachep);
        if (nfs_wdata_mempool == NULL)
-               return -ENOMEM;
+               goto out_destroy_write_cache;
 
        nfs_cdata_cachep = kmem_cache_create("nfs_commit_data",
                                             sizeof(struct nfs_commit_data),
                                             0, SLAB_HWCACHE_ALIGN,
                                             NULL);
        if (nfs_cdata_cachep == NULL)
-               return -ENOMEM;
+               goto out_destroy_write_mempool;
 
        nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
                                                      nfs_wdata_cachep);
        if (nfs_commit_mempool == NULL)
-               return -ENOMEM;
+               goto out_destroy_commit_cache;
 
        /*
         * NFS congestion size, scale with available memory.
@@ -1849,11 +1849,20 @@ int __init nfs_init_writepagecache(void)
                nfs_congestion_kb = 256*1024;
 
        return 0;
+
+out_destroy_commit_cache:
+       kmem_cache_destroy(nfs_cdata_cachep);
+out_destroy_write_mempool:
+       mempool_destroy(nfs_wdata_mempool);
+out_destroy_write_cache:
+       kmem_cache_destroy(nfs_wdata_cachep);
+       return -ENOMEM;
 }
 
 void nfs_destroy_writepagecache(void)
 {
        mempool_destroy(nfs_commit_mempool);
+       kmem_cache_destroy(nfs_cdata_cachep);
        mempool_destroy(nfs_wdata_mempool);
        kmem_cache_destroy(nfs_wdata_cachep);
 }
index 6522cac6057c900fccdac3138475ea4c0aa0a830..6a10812711c1d37bca6660530cd6c34cbb7b30fb 100644 (file)
@@ -676,17 +676,13 @@ static const struct super_operations nilfs_sops = {
        .alloc_inode    = nilfs_alloc_inode,
        .destroy_inode  = nilfs_destroy_inode,
        .dirty_inode    = nilfs_dirty_inode,
-       /* .write_inode    = nilfs_write_inode, */
-       /* .drop_inode    = nilfs_drop_inode, */
        .evict_inode    = nilfs_evict_inode,
        .put_super      = nilfs_put_super,
-       /* .write_super    = nilfs_write_super, */
        .sync_fs        = nilfs_sync_fs,
        .freeze_fs      = nilfs_freeze,
        .unfreeze_fs    = nilfs_unfreeze,
        .statfs         = nilfs_statfs,
        .remount_fs     = nilfs_remount,
-       /* .umount_begin */
        .show_options = nilfs_show_options
 };
 
index 6eee4177807bf611874208c09fce9440979fbc4f..be1267a34ceae883b7d705c967347ad4a4185b57 100644 (file)
@@ -107,8 +107,6 @@ struct the_nilfs {
         * used for
         * - loading the latest checkpoint exclusively.
         * - allocating a new full segment.
-        * - protecting s_dirt in the super_block struct
-        *   (see nilfs_write_super) and the following fields.
         */
        struct buffer_head     *ns_sbh[2];
        struct nilfs_super_block *ns_sbp[2];
index f3d96e7e7b19d4254924a59dfc4121aa5d8635b4..e1f2cdb91a4dc494473986f1b0c8b91f23614a43 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -717,7 +717,7 @@ cleanup_all:
                         * here, so just reset the state.
                         */
                        file_reset_write(f);
-                       mnt_drop_write(f->f_path.mnt);
+                       __mnt_drop_write(f->f_path.mnt);
                }
        }
 cleanup_file:
@@ -852,9 +852,10 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
        int lookup_flags = 0;
        int acc_mode;
 
-       if (!(flags & O_CREAT))
-               mode = 0;
-       op->mode = mode;
+       if (flags & O_CREAT)
+               op->mode = (mode & S_IALLUGO) | S_IFREG;
+       else
+               op->mode = 0;
 
        /* Must never be set by userspace */
        flags &= ~FMODE_NONOTIFY;
index b05cf47463d0c2347e8eca1597001f96dd2a97fc..0902cfa6a12efd21e4ebd52a39333b7f9d6270eb 100644 (file)
@@ -536,46 +536,6 @@ void drop_super(struct super_block *sb)
 
 EXPORT_SYMBOL(drop_super);
 
-/**
- * sync_supers - helper for periodic superblock writeback
- *
- * Call the write_super method if present on all dirty superblocks in
- * the system.  This is for the periodic writeback used by most older
- * filesystems.  For data integrity superblock writeback use
- * sync_filesystems() instead.
- *
- * Note: check the dirty flag before waiting, so we don't
- * hold up the sync while mounting a device. (The newly
- * mounted device won't need syncing.)
- */
-void sync_supers(void)
-{
-       struct super_block *sb, *p = NULL;
-
-       spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (hlist_unhashed(&sb->s_instances))
-                       continue;
-               if (sb->s_op->write_super && sb->s_dirt) {
-                       sb->s_count++;
-                       spin_unlock(&sb_lock);
-
-                       down_read(&sb->s_umount);
-                       if (sb->s_root && sb->s_dirt && (sb->s_flags & MS_BORN))
-                               sb->s_op->write_super(sb);
-                       up_read(&sb->s_umount);
-
-                       spin_lock(&sb_lock);
-                       if (p)
-                               __put_super(p);
-                       p = sb;
-               }
-       }
-       if (p)
-               __put_super(p);
-       spin_unlock(&sb_lock);
-}
-
 /**
  *     iterate_supers - call function for all active superblocks
  *     @f: function to call
index 35389ca2d267093895681dc0f01dfa1e5f577d79..7bd6e72afd1136a3141e42227553ba5daa5ffcba 100644 (file)
  *
  * A thing to keep in mind: inode @i_mutex is locked in most VFS operations we
  * implement. However, this is not true for 'ubifs_writepage()', which may be
- * called with @i_mutex unlocked. For example, when pdflush is doing background
- * write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex. At "normal"
- * work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g. in the
- * "sys_write -> alloc_pages -> direct reclaim path". So, in 'ubifs_writepage()'
- * we are only guaranteed that the page is locked.
+ * called with @i_mutex unlocked. For example, when flusher thread is doing
+ * background write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex.
+ * At "normal" work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g.
+ * in the "sys_write -> alloc_pages -> direct reclaim path". So, in
+ * 'ubifs_writepage()' we are only guaranteed that the page is locked.
  *
  * Similarly, @i_mutex is not always locked in 'ubifs_readpage()', e.g., the
  * read-ahead path does not lock it ("sys_read -> generic_file_aio_read ->
index 1c766c39c03819b4d088f19f0215c63a89f2b539..c3fa6c5327a3bb7b6939206c118a9d6ace0ee039 100644 (file)
@@ -303,7 +303,7 @@ static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc)
        mutex_lock(&ui->ui_mutex);
        /*
         * Due to races between write-back forced by budgeting
-        * (see 'sync_some_inodes()') and pdflush write-back, the inode may
+        * (see 'sync_some_inodes()') and background write-back, the inode may
         * have already been synchronized, do not do this again. This might
         * also happen if it was synchronized in an VFS operation, e.g.
         * 'ubifs_link()'.
index 2c744c7a5b3dcdd452d1c531884faa0ed0a3e29b..26a92fc28a590ce68a198b326632835f46cda1d9 100644 (file)
@@ -491,11 +491,11 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b);
 
 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state);
 
-acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags);
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state);
 
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void))
 
-acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags);
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
 
 acpi_status acpi_leave_sleep_state(u8 sleep_state);
 
index 3af87de6a68cd1a9afbcf21aaa4a47151158416e..3d00bd5bd7e30bdfb11689512f7e502d22d4ab71 100644 (file)
@@ -803,7 +803,7 @@ typedef u8 acpi_adr_space_type;
 
 /* Sleep function dispatch */
 
-typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state, u8 flags);
+typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state);
 
 struct acpi_sleep_functions {
        ACPI_SLEEP_FUNCTION legacy_function;
index 580a6d35c70078bd91bff6619860b5159b7130b2..c04e0db8a2d6df273472a04bfb882aecdc0d54ce 100644 (file)
@@ -26,7 +26,13 @@ static inline void
 __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
 {
        if (unlikely(atomic_xchg(count, 0) != 1))
-               fail_fn(count);
+               /*
+                * We failed to acquire the lock, so mark it contended
+                * to ensure that any waiting tasks are woken up by the
+                * unlock slow path.
+                */
+               if (likely(atomic_xchg(count, -1) != 1))
+                       fail_fn(count);
 }
 
 /**
@@ -43,7 +49,8 @@ static inline int
 __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
 {
        if (unlikely(atomic_xchg(count, 0) != 1))
-               return fail_fn(count);
+               if (likely(atomic_xchg(count, -1) != 1))
+                       return fail_fn(count);
        return 0;
 }
 
index a1a0386e0160d9278f6b74e213f26915a87551af..ced362533e3c770f6dc8f4cb3a3872aeb52e455d 100644 (file)
@@ -166,8 +166,6 @@ struct drm_display_mode {
        int crtc_vsync_start;
        int crtc_vsync_end;
        int crtc_vtotal;
-       int crtc_hadjusted;
-       int crtc_vadjusted;
 
        /* Driver private mode info */
        int private_size;
index 7ff5c99b16389330e21110a8c43b3b8877484f82..c78bb997e2c60846a1f5e261664d96ee1656fe6d 100644 (file)
        {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 58056865b8e9601bc40da73198a82d0bcb406960..dc3a8cd7db8a0741ff5b4478476e8d0e3d566b9c 100644 (file)
@@ -964,6 +964,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_IB_VM_MAX_SIZE     0x0f
 /* max pipes - needed for compute shaders */
 #define RADEON_INFO_MAX_PIPES          0x10
+/* timestamp for GL_ARB_timer_query (OpenGL), returns the current GPU clock */
+#define RADEON_INFO_TIMESTAMP          0x11
 
 struct drm_radeon_info {
        uint32_t                request;
index d9a7544748785d020ba77f74392fb1275fbe02fd..fa217607c582e7feb5cf1ef301b1659f7b9db1ff 100644 (file)
@@ -391,6 +391,7 @@ header-y += v4l2-dv-timings.h
 header-y += v4l2-mediabus.h
 header-y += v4l2-subdev.h
 header-y += veth.h
+header-y += vfio.h
 header-y += vhost.h
 header-y += videodev2.h
 header-y += virtio_9p.h
index 3ad510b25283ee1e5285929b702d739fb0afc31a..4f2a76224509ef5c652a8503153ca73435b9dde1 100644 (file)
@@ -96,7 +96,7 @@ void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
 void acpi_numa_slit_init (struct acpi_table_slit *slit);
 void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
 void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa);
-void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
+int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
 void acpi_numa_arch_fixup(void);
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
index c97c6b9cd38ee34e501735758de2b710decceae0..2a9a9abc91260c09a7940136a965a08209c5828b 100644 (file)
@@ -124,7 +124,6 @@ void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
 void bdi_start_background_writeback(struct backing_dev_info *bdi);
 int bdi_writeback_thread(void *data);
 int bdi_has_dirty_io(struct backing_dev_info *bdi);
-void bdi_arm_supers_timer(void);
 void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi);
 void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2);
 
index 22ea563ba3eb169f9e04aac1233b404923c42d6e..18fff11fb3eadbe6ebd715a584aa49909d1dd30f 100644 (file)
@@ -3,7 +3,20 @@
 
 #include <linux/compiler.h>
 
-unsigned bcd2bin(unsigned char val) __attribute_const__;
-unsigned char bin2bcd(unsigned val) __attribute_const__;
+#define bcd2bin(x)                                     \
+               (__builtin_constant_p((u8 )(x)) ?       \
+               const_bcd2bin(x) :                      \
+               _bcd2bin(x))
+
+#define bin2bcd(x)                                     \
+               (__builtin_constant_p((u8 )(x)) ?       \
+               const_bin2bcd(x) :                      \
+               _bin2bcd(x))
+
+#define const_bcd2bin(x)       (((x) & 0x0f) + ((x) >> 4) * 10)
+#define const_bin2bcd(x)       ((((x) / 10) << 4) + (x) % 10)
+
+unsigned _bcd2bin(unsigned char val) __attribute_const__;
+unsigned char _bin2bcd(unsigned val) __attribute_const__;
 
 #endif /* _BCD_H */
index 3c80885fa829dcb6fe60616b9aba6e85bea550fb..d323a4b4143c6e2d1f43b4a82e459fad157d5f04 100644 (file)
 #define  BCMA_CC_CHIPST_4313_OTP_PRESENT       2
 #define  BCMA_CC_CHIPST_4331_SPROM_PRESENT     2
 #define  BCMA_CC_CHIPST_4331_OTP_PRESENT       4
+#define  BCMA_CC_CHIPST_43228_ILP_DIV_EN       0x00000001
+#define  BCMA_CC_CHIPST_43228_OTP_PRESENT      0x00000002
+#define  BCMA_CC_CHIPST_43228_SERDES_REFCLK_PADSEL     0x00000004
+#define  BCMA_CC_CHIPST_43228_SDIO_MODE                0x00000008
+#define  BCMA_CC_CHIPST_43228_SDIO_OTP_PRESENT 0x00000010
+#define  BCMA_CC_CHIPST_43228_SDIO_RESET       0x00000020
 #define  BCMA_CC_CHIPST_4706_PKG_OPTION                BIT(0) /* 0: full-featured package 1: low-cost package */
 #define  BCMA_CC_CHIPST_4706_SFLASH_PRESENT    BIT(1) /* 0: parallel, 1: serial flash is present */
 #define  BCMA_CC_CHIPST_4706_SFLASH_TYPE       BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
index 018055efc0343b2a8f7e800255ff53b9e10a3584..e52958d7c2d119cb416587466f4a4d2a5bb1e8d0 100644 (file)
@@ -74,20 +74,21 @@ struct can_frame {
 /*
  * defined bits for canfd_frame.flags
  *
- * As the default for CAN FD should be to support the high data rate in the
- * payload section of the frame (HDR) and to support up to 64 byte in the
- * data section (EDL) the bits are only set in the non-default case.
- * Btw. as long as there's no real implementation for CAN FD network driver
- * these bits are only preliminary.
+ * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
+ * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
+ * the CAN controllers bitstream processor into the CAN FD mode which creates
+ * two new options within the CAN FD frame specification:
  *
- * RX: NOHDR/NOEDL - info about received CAN FD frame
- *     ESI         - bit from originating CAN controller
- * TX: NOHDR/NOEDL - control per-frame settings if supported by CAN controller
- *     ESI         - bit is set by local CAN controller
+ * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
+ * Error State Indicator - represents the error state of the transmitting node
+ *
+ * As the CANFD_ESI bit is internally generated by the transmitting CAN
+ * controller only the CANFD_BRS bit is relevant for real CAN controllers when
+ * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
+ * sense for virtual CAN interfaces to test applications with echoed frames.
  */
-#define CANFD_NOHDR 0x01 /* frame without high data rate */
-#define CANFD_NOEDL 0x02 /* frame without extended data length */
-#define CANFD_ESI   0x04 /* error state indicator */
+#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
+#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
 
 /**
  * struct canfd_frame - CAN flexible data rate frame structure
index 133ddcf83397036a5c20ed6431db3b789eeab37a..ef658147e4e8391eec61aa7559a1452fcffe6a79 100644 (file)
@@ -22,7 +22,7 @@ extern int sysctl_extfrag_handler(struct ctl_table *table, int write,
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *mask,
-                       bool sync);
+                       bool sync, bool *contended);
 extern int compact_pgdat(pg_data_t *pgdat, int order);
 extern unsigned long compaction_suitable(struct zone *zone, int order);
 
@@ -64,7 +64,7 @@ static inline bool compaction_deferred(struct zone *zone, int order)
 #else
 static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *nodemask,
-                       bool sync)
+                       bool sync, bool *contended)
 {
        return COMPACT_CONTINUE;
 }
index 103adc6d7e3a740dc72cb9f47caa0def680fe1f9..ec45ccd8708a85f54a903d769b0b5c2fbaf8bc3f 100644 (file)
@@ -503,6 +503,8 @@ extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size);
 extern int __init efi_uart_console_only (void);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
                struct resource *data_resource, struct resource *bss_resource);
+extern unsigned long efi_get_time(void);
+extern int efi_set_rtc_mmss(unsigned long nowtime);
 extern void efi_reserve_boot_services(void);
 extern struct efi_memory_map memmap;
 
index 38dba16c417646ff28f9ea78dea28a268d65d125..aa110476a95be0b1d479555346c560d45ecc0b20 100644 (file)
@@ -1491,7 +1491,6 @@ struct sb_writers {
 struct super_block {
        struct list_head        s_list;         /* Keep this first */
        dev_t                   s_dev;          /* search index; _not_ kdev_t */
-       unsigned char           s_dirt;
        unsigned char           s_blocksize_bits;
        unsigned long           s_blocksize;
        loff_t                  s_maxbytes;     /* Max file size */
@@ -1861,7 +1860,6 @@ struct super_operations {
        int (*drop_inode) (struct inode *);
        void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
-       void (*write_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
        int (*freeze_fs) (struct super_block *);
        int (*unfreeze_fs) (struct super_block *);
@@ -2397,7 +2395,6 @@ extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end,
                           int datasync);
 extern int vfs_fsync(struct file *file, int datasync);
 extern int generic_write_sync(struct file *file, loff_t pos, loff_t count);
-extern void sync_supers(void);
 extern void emergency_sync(void);
 extern void emergency_remount(void);
 #ifdef CONFIG_BLOCK
index 15be561e7397e68ba1f4fb8d4e8900afb4285e0a..ccfc4bb3dc4899272ced9dd40e33f5e410274704 100644 (file)
@@ -19,6 +19,7 @@
 
 #define FSL_UTMI_PHY_DLY       10      /*As per P1010RM, delay for UTMI
                                PHY CLK to become stable - 10ms*/
+#define FSL_USB_PHY_CLK_TIMEOUT        1000    /* uSec */
 #define FSL_USB_VER_OLD                0
 #define FSL_USB_VER_1_6                1
 #define FSL_USB_VER_2_2                2
index af961d6f7ab14edc6b3a0c8ec813124fba5415da..642928cf57b4b47672c6fd18552b3fd3e114153e 100644 (file)
@@ -306,9 +306,10 @@ extern void *perf_trace_buf_prepare(int size, unsigned short type,
 
 static inline void
 perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
-                      u64 count, struct pt_regs *regs, void *head)
+                      u64 count, struct pt_regs *regs, void *head,
+                      struct task_struct *task)
 {
-       perf_tp_event(addr, count, raw_data, size, regs, head, rctx);
+       perf_tp_event(addr, count, raw_data, size, regs, head, rctx, task);
 }
 #endif
 
index 9303348965fbdbc8a8d6d706949b543d54c5609b..d8c713e148e3a5c15fc166e507fe811210872027 100644 (file)
@@ -57,6 +57,9 @@
  *
  * 7.19
  *  - add FUSE_FALLOCATE
+ *
+ * 7.20
+ *  - add FUSE_AUTO_INVAL_DATA
  */
 
 #ifndef _LINUX_FUSE_H
@@ -88,7 +91,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 19
+#define FUSE_KERNEL_MINOR_VERSION 20
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -163,10 +166,19 @@ struct fuse_file_lock {
 /**
  * INIT request/reply flags
  *
+ * FUSE_ASYNC_READ: asynchronous read requests
  * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
+ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported)
+ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB
  * FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ * FUSE_SPLICE_WRITE: kernel supports splice write on the device
+ * FUSE_SPLICE_MOVE: kernel supports splice move on the device
+ * FUSE_SPLICE_READ: kernel supports splice read on the device
  * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
+ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
+ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -175,7 +187,12 @@ struct fuse_file_lock {
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
 #define FUSE_DONT_MASK         (1 << 6)
+#define FUSE_SPLICE_WRITE      (1 << 7)
+#define FUSE_SPLICE_MOVE       (1 << 8)
+#define FUSE_SPLICE_READ       (1 << 9)
 #define FUSE_FLOCK_LOCKS       (1 << 10)
+#define FUSE_HAS_IOCTL_DIR     (1 << 11)
+#define FUSE_AUTO_INVAL_DATA   (1 << 12)
 
 /**
  * CUSE INIT request/reply flags
index bb7f30971858ca5127de592cdaa0cec227935384..305f23cd7cff53f3ef97794db7d6aa7dde6035c6 100644 (file)
@@ -22,7 +22,7 @@
  *
  * - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
  * - bit 26 is the NMI_MASK
- * - bit 28 is the PREEMPT_ACTIVE flag
+ * - bit 27 is the PREEMPT_ACTIVE flag
  *
  * PREEMPT_MASK: 0x000000ff
  * SOFTIRQ_MASK: 0x0000ff00
index 6960fc1841a7adc3bd42ff5b9a2221b78f2b9eb2..aa2e167e1ef434a696a55322bd941bdb3983bf50 100644 (file)
@@ -96,21 +96,6 @@ static inline void team_netpoll_send_skb(struct team_port *port,
 }
 #endif
 
-static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
-                                     struct sk_buff *skb)
-{
-       BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
-                    sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
-       skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
-
-       skb->dev = port->dev;
-       if (unlikely(netpoll_tx_running(port->dev))) {
-               team_netpoll_send_skb(port, skb);
-               return 0;
-       }
-       return dev_queue_xmit(skb);
-}
-
 struct team_mode_ops {
        int (*init)(struct team *team);
        void (*exit)(struct team *team);
@@ -200,6 +185,21 @@ struct team {
        long mode_priv[TEAM_MODE_PRIV_LONGS];
 };
 
+static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
+                                     struct sk_buff *skb)
+{
+       BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
+                    sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
+       skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
+
+       skb->dev = port->dev;
+       if (unlikely(netpoll_tx_running(team->dev))) {
+               team_netpoll_send_skb(port, skb);
+               return 0;
+       }
+       return dev_queue_xmit(skb);
+}
+
 static inline struct hlist_head *team_port_index_hash(struct team *team,
                                                      int port_index)
 {
index b76b4a87065e3615cbfc1b17e81b9fd90bcf8898..be91f344d5fce1b3b8a41ff149ece8b917715542 100644 (file)
@@ -87,6 +87,8 @@
 #define ADF4350_MAX_BANDSEL_CLK                125000 /* Hz */
 #define ADF4350_MAX_FREQ_REFIN         250000000 /* Hz */
 #define ADF4350_MAX_MODULUS            4095
+#define ADF4350_MAX_R_CNT              1023
+
 
 /**
  * struct adf4350_platform_data - platform specific information
index f875b316249d257ce2f56e7243e4463c9d4994e2..16625d799b6fc1ca85f89d5d9f81415332c8e86e 100644 (file)
@@ -2,6 +2,7 @@
 #define LINUX_INPUT_EETI_TS_H
 
 struct eeti_ts_platform_data {
+       int irq_gpio;
        unsigned int irq_active_high;
 };
 
index 54d6d690073c1cb5119671b99df70af3ddfc615d..7e83370e6fd2b134691e7fa348529e70d0a1ae56 100644 (file)
@@ -20,6 +20,7 @@
 #define __LINUX_IOMMU_H
 
 #include <linux/errno.h>
+#include <linux/types.h>
 
 #define IOMMU_READ     (1)
 #define IOMMU_WRITE    (2)
@@ -30,6 +31,7 @@ struct iommu_group;
 struct bus_type;
 struct device;
 struct iommu_domain;
+struct notifier_block;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ       0x0
index 379e433e15e0fc97fc3f376b610f12ff77f694ae..879db26ec4013297fb76f16143b87ec9db52b5e4 100644 (file)
@@ -369,6 +369,7 @@ struct ipv6_pinfo {
        __u8                    rcv_tclass;
 
        __u32                   dst_cookie;
+       __u32                   rx_dst_cookie;
 
        struct ipv6_mc_socklist __rcu *ipv6_mc_list;
        struct ipv6_ac_socklist *ipv6_ac_list;
index 553fb66da130a3a9b3700958c5cce22a6b5cda73..216b0ba109d72f453836568e1aa6c7b7c85e21a6 100644 (file)
@@ -349,6 +349,7 @@ enum {
        IRQCHIP_MASK_ON_SUSPEND         = (1 <<  2),
        IRQCHIP_ONOFFLINE_ENABLED       = (1 <<  3),
        IRQCHIP_SKIP_SET_WAKE           = (1 <<  4),
+       IRQCHIP_ONESHOT_SAFE            = (1 <<  5),
 };
 
 /* This include will go away once we isolated irq_desc usage to core code */
index f334c7fab96762ab4131c9886df87d4d6d4dde9d..3efc43f3f162c3427099cb31fdafd5c1e5d226de 100644 (file)
@@ -1125,6 +1125,7 @@ extern int           jbd2_journal_destroy    (journal_t *);
 extern int        jbd2_journal_recover    (journal_t *journal);
 extern int        jbd2_journal_wipe       (journal_t *, int);
 extern int        jbd2_journal_skip_recovery   (journal_t *);
+extern void       jbd2_journal_update_sb_errno(journal_t *);
 extern void       jbd2_journal_update_sb_log_tail      (journal_t *, tid_t,
                                unsigned long, int);
 extern void       __jbd2_journal_abort_hard    (journal_t *);
index 265e2c3cbd1cd74d2b3efd416aa9301c90ae90ad..82680541576d2f2d307ba9bfb1847681f290f49b 100644 (file)
@@ -39,9 +39,6 @@
 # error Invalid value of HZ.
 #endif
 
-/* LATCH is used in the interval timer and ftape setup. */
-#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
-
 /* Suppose we want to divide two numbers NOM and DEN: NOM/DEN, then we can
  * improve accuracy by shifting LSH bits, hence calculating:
  *     (NOM << LSH) / DEN
 #define SH_DIV(NOM,DEN,LSH) (   (((NOM) / (DEN)) << (LSH))              \
                              + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
 
-/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
-#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
+#ifdef CLOCK_TICK_RATE
+/* LATCH is used in the interval timer and ftape setup. */
+# define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
+/*
+ * HZ is the requested value. However the CLOCK_TICK_RATE may not allow
+ * for exactly HZ. So SHIFTED_HZ is high res HZ ("<< 8" is for accuracy)
+ */
+# define SHIFTED_HZ (SH_DIV(CLOCK_TICK_RATE, LATCH, 8))
+#else
+# define SHIFTED_HZ (HZ << 8)
+#endif
 
-/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
-#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
+/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */
+#define TICK_NSEC (SH_DIV(1000000UL * 1000, SHIFTED_HZ, 8))
 
 /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
 #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
 
-/* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */
-/* a value TUSEC for TICK_USEC (can be set bij adjtimex)               */
-#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8))
+/*
+ * TICK_USEC_TO_NSEC is the time between ticks in nsec assuming SHIFTED_HZ and
+ * a value TUSEC for TICK_USEC (can be set bij adjtimex)
+ */
+#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV(TUSEC * USER_HZ * 1000, SHIFTED_HZ, 8))
 
 /* some arch's have a small-data section that can be accessed register-relative
  * but that can only take up to, say, 4-byte variables. jiffies being part of
index 064725854db8c7eff3c5a38a093aec190a6c6c7f..42d9e863a3139ad953c23f53ef36f4cc19182dd8 100644 (file)
@@ -75,8 +75,6 @@ extern const char *kdb_diemsg;
 #define KDB_FLAG_CATASTROPHIC  (1 << 1) /* A catastrophic event has occurred */
 #define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */
 #define KDB_FLAG_NOIPI         (1 << 3) /* Do not send IPIs */
-#define KDB_FLAG_ONLY_DO_DUMP  (1 << 4) /* Only do a dump, used when
-                                         * kdb is off */
 #define KDB_FLAG_NO_CONSOLE    (1 << 5) /* No console is available,
                                          * kdb is disabled */
 #define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do
index 9c07dcebded747493041c8e6a5c18d68bc43fabf..65af6887872f1e62d51afa7381ac3b790a302182 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/bug.h>
 #include <linux/atomic.h>
 #include <linux/kernel.h>
+#include <linux/mutex.h>
 
 struct kref {
        atomic_t refcount;
@@ -93,4 +94,21 @@ static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)
 {
        return kref_sub(kref, 1, release);
 }
+
+static inline int kref_put_mutex(struct kref *kref,
+                                void (*release)(struct kref *kref),
+                                struct mutex *lock)
+{
+       WARN_ON(release == NULL);
+        if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
+               mutex_lock(lock);
+               if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
+                       mutex_unlock(lock);
+                       return 0;
+               }
+               release(kref);
+               return 1;
+       }
+       return 0;
+}
 #endif /* _KREF_H_ */
index 40c372165f3edc0413a709c57c4e728bd0198ca5..32a1b5cfeba1f426547127233c84732363fc4e30 100644 (file)
@@ -16,6 +16,7 @@ struct pcap_subdev {
 struct pcap_platform_data {
        unsigned int irq_base;
        unsigned int config;
+       int gpio;
        void (*init) (void *);  /* board specific init */
        int num_subdevs;
        struct pcap_subdev *subdevs;
index eb06e58bed0b2dc9c7e2d6a9b166d69380556e58..59dc05f382475d67d5d4326c852f3b7d49332e3b 100644 (file)
@@ -953,7 +953,8 @@ struct net_device_ops {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*ndo_poll_controller)(struct net_device *dev);
        int                     (*ndo_netpoll_setup)(struct net_device *dev,
-                                                    struct netpoll_info *info);
+                                                    struct netpoll_info *info,
+                                                    gfp_t gfp);
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
@@ -1300,6 +1301,8 @@ struct net_device {
        /* for setting kernel sock attribute on TCP connection setup */
 #define GSO_MAX_SIZE           65536
        unsigned int            gso_max_size;
+#define GSO_MAX_SEGS           65535
+       u16                     gso_max_segs;
 
 #ifdef CONFIG_DCB
        /* Data Center Bridging netlink ops */
@@ -1519,6 +1522,8 @@ struct packet_type {
        struct sk_buff          **(*gro_receive)(struct sk_buff **head,
                                               struct sk_buff *skb);
        int                     (*gro_complete)(struct sk_buff *skb);
+       bool                    (*id_match)(struct packet_type *ptype,
+                                           struct sock *sk);
        void                    *af_packet_priv;
        struct list_head        list;
 };
index 0dfc8b7210a3c3df26d582aef6399c65ab1c0519..89f2a627f3f086febbcf1a93ab0fe9f42b6eac30 100644 (file)
@@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr
                                      unsigned int dataoff, unsigned int datalen,
                                      const char *name,
                                      unsigned int *matchoff, unsigned int *matchlen,
-                                     union nf_inet_addr *addr);
+                                     union nf_inet_addr *addr, bool delim);
 extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
                                        unsigned int off, unsigned int datalen,
                                        const char *name,
index 28f5389c924b51b76cf88dc5da1af7f3a0853138..66d5379c305e60d17dcde8b60d286f0b57b23a16 100644 (file)
@@ -23,6 +23,7 @@ struct netpoll {
        u8 remote_mac[ETH_ALEN];
 
        struct list_head rx; /* rx_np list element */
+       struct rcu_head rcu;
 };
 
 struct netpoll_info {
@@ -38,28 +39,40 @@ struct netpoll_info {
        struct delayed_work tx_work;
 
        struct netpoll *netpoll;
+       struct rcu_head rcu;
 };
 
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
 void netpoll_print_options(struct netpoll *np);
 int netpoll_parse_options(struct netpoll *np, char *opt);
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev);
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp);
 int netpoll_setup(struct netpoll *np);
 int netpoll_trap(void);
 void netpoll_set_trap(int trap);
 void __netpoll_cleanup(struct netpoll *np);
+void __netpoll_free_rcu(struct netpoll *np);
 void netpoll_cleanup(struct netpoll *np);
-int __netpoll_rx(struct sk_buff *skb);
+int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo);
 void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                             struct net_device *dev);
 static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
 {
+       unsigned long flags;
+       local_irq_save(flags);
        netpoll_send_skb_on_dev(np, skb, np->dev);
+       local_irq_restore(flags);
 }
 
 
 
 #ifdef CONFIG_NETPOLL
+static inline bool netpoll_rx_on(struct sk_buff *skb)
+{
+       struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
+
+       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
+}
+
 static inline bool netpoll_rx(struct sk_buff *skb)
 {
        struct netpoll_info *npinfo;
@@ -67,14 +80,14 @@ static inline bool netpoll_rx(struct sk_buff *skb)
        bool ret = false;
 
        local_irq_save(flags);
-       npinfo = rcu_dereference_bh(skb->dev->npinfo);
 
-       if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
+       if (!netpoll_rx_on(skb))
                goto out;
 
+       npinfo = rcu_dereference_bh(skb->dev->npinfo);
        spin_lock(&npinfo->rx_lock);
        /* check rx_flags again with the lock held */
-       if (npinfo->rx_flags && __netpoll_rx(skb))
+       if (npinfo->rx_flags && __netpoll_rx(skb, npinfo))
                ret = true;
        spin_unlock(&npinfo->rx_lock);
 
@@ -83,13 +96,6 @@ out:
        return ret;
 }
 
-static inline int netpoll_rx_on(struct sk_buff *skb)
-{
-       struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
-
-       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
-}
-
 static inline int netpoll_receive_skb(struct sk_buff *skb)
 {
        if (!list_empty(&skb->dev->napi_list))
@@ -119,7 +125,7 @@ static inline void netpoll_poll_unlock(void *have)
        }
 }
 
-static inline int netpoll_tx_running(struct net_device *dev)
+static inline bool netpoll_tx_running(struct net_device *dev)
 {
        return irqs_disabled();
 }
@@ -127,11 +133,11 @@ static inline int netpoll_tx_running(struct net_device *dev)
 #else
 static inline bool netpoll_rx(struct sk_buff *skb)
 {
-       return 0;
+       return false;
 }
-static inline int netpoll_rx_on(struct sk_buff *skb)
+static inline bool netpoll_rx_on(struct sk_buff *skb)
 {
-       return 0;
+       return false;
 }
 static inline int netpoll_receive_skb(struct sk_buff *skb)
 {
@@ -147,9 +153,9 @@ static inline void netpoll_poll_unlock(void *have)
 static inline void netpoll_netdev_init(struct net_device *dev)
 {
 }
-static inline int netpoll_tx_running(struct net_device *dev)
+static inline bool netpoll_tx_running(struct net_device *dev)
 {
-       return 0;
+       return false;
 }
 #endif
 
index 880805774f9f105425a7eade9721b9965f7d43c9..92ce5783b707df8ea90306aaf145f1fbba3d02a2 100644 (file)
@@ -69,6 +69,7 @@ struct nfs_pageio_descriptor {
        const struct nfs_pgio_completion_ops *pg_completion_ops;
        struct pnfs_layout_segment *pg_lseg;
        struct nfs_direct_req   *pg_dreq;
+       void                    *pg_layout_private;
 };
 
 #define NFS_WBACK_BUSY(req)    (test_bit(PG_BUSY,&(req)->wb_flags))
index 00485e084394d4ca1a5782b3cd54fc63e9b06acd..ac7c8ae254f251933e48f04d5c877eaaa3ec6e09 100644 (file)
@@ -1248,6 +1248,7 @@ struct nfs_pgio_header {
        void (*release) (struct nfs_pgio_header *hdr);
        const struct nfs_pgio_completion_ops *completion_ops;
        struct nfs_direct_req   *dreq;
+       void                    *layout_private;
        spinlock_t              lock;
        /* fields protected by lock */
        int                     pnfs_error;
index 5919ee33f2b7b2d930fa3f6dd877984be5ed5e0d..1b1163225f3b8ab1eafacbb21e83ab8f86d50d42 100644 (file)
@@ -190,10 +190,17 @@ extern struct device_node *of_get_parent(const struct device_node *node);
 extern struct device_node *of_get_next_parent(struct device_node *node);
 extern struct device_node *of_get_next_child(const struct device_node *node,
                                             struct device_node *prev);
+extern struct device_node *of_get_next_available_child(
+       const struct device_node *node, struct device_node *prev);
+
 #define for_each_child_of_node(parent, child) \
        for (child = of_get_next_child(parent, NULL); child != NULL; \
             child = of_get_next_child(parent, child))
 
+#define for_each_available_child_of_node(parent, child) \
+       for (child = of_get_next_available_child(parent, NULL); child != NULL; \
+            child = of_get_next_available_child(parent, child))
+
 static inline int of_get_child_count(const struct device_node *np)
 {
        struct device_node *child;
index 76c5c8b724a77253e3ca635c90e53ed6230b3c5f..7602ccb3f40ec672001be2eae9be3395604493f2 100644 (file)
@@ -1272,7 +1272,8 @@ static inline bool perf_paranoid_kernel(void)
 extern void perf_event_init(void);
 extern void perf_tp_event(u64 addr, u64 count, void *record,
                          int entry_size, struct pt_regs *regs,
-                         struct hlist_head *head, int rctx);
+                         struct hlist_head *head, int rctx,
+                         struct task_struct *task);
 extern void perf_bp_event(struct perf_event *event, void *data);
 
 #ifndef perf_misc_flags
index 6dd96fb45482b00b0ede76c92f83fc6bd76f0f2f..e9b7f4350844435daf050bd539de04d44fe4b6fa 100644 (file)
@@ -20,6 +20,7 @@
 /* This struct is private to the core and should be regarded as a cookie */
 struct pinctrl;
 struct pinctrl_state;
+struct device;
 
 #ifdef CONFIG_PINCTRL
 
index c147e7024f11f2859d8f648b1abac437bac941f1..b8c86648a2f95dc6f83aab668fd9a7e07f277b4e 100644 (file)
@@ -334,14 +334,6 @@ static inline void lockup_detector_init(void)
 }
 #endif
 
-#if defined(CONFIG_LOCKUP_DETECTOR) && defined(CONFIG_SUSPEND)
-void lockup_detector_bootcpu_resume(void);
-#else
-static inline void lockup_detector_bootcpu_resume(void)
-{
-}
-#endif
-
 #ifdef CONFIG_DETECT_HUNG_TASK
 extern unsigned int  sysctl_hung_task_panic;
 extern unsigned long sysctl_hung_task_check_count;
index 4e5a73cdbbef18463920022626931d02c0540eb9..3dea6a9d568f416ccd1b704eec1d4bff9dea6d90 100644 (file)
@@ -1242,8 +1242,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Check that the @parent process has sufficient permission to trace the
  *     current process before allowing the current process to present itself
  *     to the @parent process for tracing.
- *     The parent process will still have to undergo the ptrace_access_check
- *     checks before it is allowed to trace this one.
  *     @parent contains the task_struct structure for debugger process.
  *     Return 0 if permission is granted.
  * @capget:
index ffe0442e18d2f4e2d7b8d8eb8f22ffbc532e67e4..b9178812d9df5f703b2e2126f1a4df2669f083cc 100644 (file)
@@ -144,8 +144,8 @@ static inline bool strstarts(const char *str, const char *prefix)
 {
        return strncmp(str, prefix, strlen(prefix)) == 0;
 }
-#endif
 
 extern size_t memweight(const void *ptr, size_t bytes);
 
+#endif /* __KERNEL__ */
 #endif /* _LINUX_STRING_H_ */
index 99bc88b1fc02734a30619038d2f9a7f430b4a951..7c5ceb20e03a8cf2195ae114e1f78905668158e5 100644 (file)
@@ -232,7 +232,7 @@ struct timex {
  * estimated error = NTP dispersion.
  */
 extern unsigned long tick_usec;                /* USER_HZ period (usec) */
-extern unsigned long tick_nsec;                /* ACTHZ          period (nsec) */
+extern unsigned long tick_nsec;                /* SHIFTED_HZ period (nsec) */
 
 extern void ntp_init(void);
 extern void ntp_clear(void);
index e91cd43394dfa82f3926c356abb4543b2e14bf36..fec12d667211dd398ba07ed5127b9e3485bcdd49 100644 (file)
@@ -164,6 +164,7 @@ int arch_update_cpu_topology(void);
                                | 0*SD_SHARE_CPUPOWER                   \
                                | 0*SD_SHARE_PKG_RESOURCES              \
                                | 0*SD_SERIALIZE                        \
+                               | 1*SD_PREFER_SIBLING                   \
                                ,                                       \
        .last_balance           = jiffies,                              \
        .balance_interval       = 1,                                    \
index 30d1ae38eab1912c89e8458759fba9bf1d21eed5..07915a32fb9dcda932989cb495798cdc48bb1059 100644 (file)
@@ -384,6 +384,13 @@ enum usb_device_removable {
        USB_DEVICE_FIXED,
 };
 
+enum usb_port_connect_type {
+       USB_PORT_CONNECT_TYPE_UNKNOWN = 0,
+       USB_PORT_CONNECT_TYPE_HOT_PLUG,
+       USB_PORT_CONNECT_TYPE_HARD_WIRED,
+       USB_PORT_NOT_USED,
+};
+
 /*
  * USB 3.0 Link Power Management (LPM) parameters.
  *
@@ -469,7 +476,6 @@ struct usb3_lpm_parameters {
  *     access from userspace
  * @usbfs_dentry: usbfs dentry entry for the device
  * @maxchild: number of ports if hub
- * @children: child devices - USB devices that are attached to this hub
  * @quirks: quirks of the whole device
  * @urbnum: number of URBs submitted for the whole device
  * @active_duration: total time device is not suspended
@@ -543,7 +549,6 @@ struct usb_device {
        struct list_head filelist;
 
        int maxchild;
-       struct usb_device **children;
 
        u32 quirks;
        atomic_t urbnum;
@@ -572,6 +577,19 @@ static inline struct usb_device *interface_to_usbdev(struct usb_interface *intf)
 
 extern struct usb_device *usb_get_dev(struct usb_device *dev);
 extern void usb_put_dev(struct usb_device *dev);
+extern struct usb_device *usb_hub_find_child(struct usb_device *hdev,
+       int port1);
+
+/**
+ * usb_hub_for_each_child - iterate over all child devices on the hub
+ * @hdev:  USB device belonging to the usb hub
+ * @port1: portnum associated with child device
+ * @child: child device pointer
+ */
+#define usb_hub_for_each_child(hdev, port1, child) \
+       for (port1 = 1, child = usb_hub_find_child(hdev, port1); \
+               port1 <= hdev->maxchild; \
+               child = usb_hub_find_child(hdev, ++port1))
 
 /* USB device locking */
 #define usb_lock_device(udev)          device_lock(&(udev)->dev)
@@ -584,6 +602,16 @@ extern int usb_lock_device_for_reset(struct usb_device *udev,
 extern int usb_reset_device(struct usb_device *dev);
 extern void usb_queue_reset_device(struct usb_interface *dev);
 
+#ifdef CONFIG_ACPI
+extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
+       bool enable);
+extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
+#else
+static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
+       bool enable) { return 0; }
+static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
+       { return true; }
+#endif
 
 /* USB autosuspend and autoresume */
 #ifdef CONFIG_USB_SUSPEND
index b6c2863b2c942cafec851abd791a8d93efe13f3b..7692dc69ccf7aeeb16ebc682b57d519c56642ba1 100644 (file)
@@ -236,8 +236,8 @@ struct usb_hub_descriptor {
 
                struct {
                        __u8 bHubHdrDecLat;
-                       __u16 wHubDelay;
-                       __u16 DeviceRemovable;
+                       __le16 wHubDelay;
+                       __le16 DeviceRemovable;
                }  __attribute__ ((packed)) ss;
        } u;
 } __attribute__ ((packed));
index 9d8c3b6344937fa8808962b17edc885e2180c2a3..f8dda0621800db910be2aa51f134a5139daf0243 100644 (file)
@@ -34,6 +34,8 @@
  * the composite model the host can use both functions at the same time.
  */
 
+#include <linux/bcd.h>
+#include <linux/version.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
@@ -46,6 +48,9 @@
  */
 #define USB_GADGET_DELAYED_STATUS       0x7fff /* Impossibly large value */
 
+/* big enough to hold our biggest descriptor */
+#define USB_COMP_EP0_BUFSIZ    1024
+
 struct usb_configuration;
 
 /**
@@ -245,24 +250,31 @@ int usb_add_config(struct usb_composite_dev *,
 void usb_remove_config(struct usb_composite_dev *,
                struct usb_configuration *);
 
+/* predefined index for usb_composite_driver */
+enum {
+       USB_GADGET_MANUFACTURER_IDX     = 0,
+       USB_GADGET_PRODUCT_IDX,
+       USB_GADGET_SERIAL_IDX,
+       USB_GADGET_FIRST_AVAIL_IDX,
+};
+
 /**
  * struct usb_composite_driver - groups configurations into a gadget
  * @name: For diagnostics, identifies the driver.
- * @iProduct: Used as iProduct override if @dev->iProduct is not set.
- *     If NULL value of @name is taken.
- * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
- *     not set. If NULL a default "<system> <release> with <udc>" value
- *     will be used.
- * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
- *     not set.
  * @dev: Template descriptor for the device, including default device
  *     identifiers.
- * @strings: tables of strings, keyed by identifiers assigned during bind()
- *     and language IDs provided in control requests
+ * @strings: tables of strings, keyed by identifiers assigned during @bind
+ *     and language IDs provided in control requests. Note: The first entries
+ *     are predefined. The first entry that may be used is
+ *     USB_GADGET_FIRST_AVAIL_IDX
  * @max_speed: Highest speed the driver supports.
  * @needs_serial: set to 1 if the gadget needs userspace to provide
  *     a serial number.  If one is not provided, warning will be printed.
- * @unbind: Reverses bind; called as a side effect of unregistering
+ * @bind: (REQUIRED) Used to allocate resources that are shared across the
+ *     whole device, such as string IDs, and add its configurations using
+ *     @usb_add_config(). This may fail by returning a negative errno
+ *     value; it should return zero on successful initialization.
+ * @unbind: Reverses @bind; called as a side effect of unregistering
  *     this driver.
  * @disconnect: optional driver disconnect method
  * @suspend: Notifies when the host stops sending USB traffic,
@@ -271,9 +283,9 @@ void usb_remove_config(struct usb_composite_dev *,
  *     before function notifications
  *
  * Devices default to reporting self powered operation.  Devices which rely
- * on bus powered operation should report this in their @bind() method.
+ * on bus powered operation should report this in their @bind method.
  *
- * Before returning from bind, various fields in the template descriptor
+ * Before returning from @bind, various fields in the template descriptor
  * may be overridden.  These include the idVendor/idProduct/bcdDevice values
  * normally to bind the appropriate host side driver, and the three strings
  * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
@@ -283,14 +295,12 @@ void usb_remove_config(struct usb_composite_dev *,
  */
 struct usb_composite_driver {
        const char                              *name;
-       const char                              *iProduct;
-       const char                              *iManufacturer;
-       const char                              *iSerialNumber;
        const struct usb_device_descriptor      *dev;
        struct usb_gadget_strings               **strings;
        enum usb_device_speed                   max_speed;
        unsigned                needs_serial:1;
 
+       int                     (*bind)(struct usb_composite_dev *cdev);
        int                     (*unbind)(struct usb_composite_dev *);
 
        void                    (*disconnect)(struct usb_composite_dev *);
@@ -298,10 +308,10 @@ struct usb_composite_driver {
        /* global suspend hooks */
        void                    (*suspend)(struct usb_composite_dev *);
        void                    (*resume)(struct usb_composite_dev *);
+       struct usb_gadget_driver                gadget_driver;
 };
 
-extern int usb_composite_probe(struct usb_composite_driver *driver,
-                              int (*bind)(struct usb_composite_dev *cdev));
+extern int usb_composite_probe(struct usb_composite_driver *driver);
 extern void usb_composite_unregister(struct usb_composite_driver *driver);
 extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
 
@@ -310,7 +320,6 @@ extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
  * struct usb_composite_device - represents one composite usb gadget
  * @gadget: read-only, abstracts the gadget's usb peripheral controller
  * @req: used for control responses; buffer is pre-allocated
- * @bufsiz: size of buffer pre-allocated in @req
  * @config: the currently active configuration
  *
  * One of these devices is allocated and initialized before the
@@ -341,7 +350,6 @@ extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
 struct usb_composite_dev {
        struct usb_gadget               *gadget;
        struct usb_request              *req;
-       unsigned                        bufsiz;
 
        struct usb_configuration        *config;
 
@@ -352,9 +360,7 @@ struct usb_composite_dev {
        struct list_head                configs;
        struct usb_composite_driver     *driver;
        u8                              next_string_id;
-       u8                              manufacturer_override;
-       u8                              product_override;
-       u8                              serial_override;
+       char                            *def_manufacturer;
 
        /* the gadget driver won't enable the data pullup
         * while the deactivation count is nonzero.
@@ -375,6 +381,53 @@ extern int usb_string_ids_tab(struct usb_composite_dev *c,
                              struct usb_string *str);
 extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
 
+/*
+ * Some systems will need runtime overrides for the  product identifiers
+ * published in the device descriptor, either numbers or strings or both.
+ * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+struct usb_composite_overwrite {
+       u16     idVendor;
+       u16     idProduct;
+       u16     bcdDevice;
+       char    *serial_number;
+       char    *manufacturer;
+       char    *product;
+};
+#define USB_GADGET_COMPOSITE_OPTIONS()                                 \
+       static struct usb_composite_overwrite coverwrite;               \
+                                                                       \
+       module_param_named(idVendor, coverwrite.idVendor, ushort, S_IRUGO); \
+       MODULE_PARM_DESC(idVendor, "USB Vendor ID");                    \
+                                                                       \
+       module_param_named(idProduct, coverwrite.idProduct, ushort, S_IRUGO); \
+       MODULE_PARM_DESC(idProduct, "USB Product ID");                  \
+                                                                       \
+       module_param_named(bcdDevice, coverwrite.bcdDevice, ushort, S_IRUGO); \
+       MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");        \
+                                                                       \
+       module_param_named(iSerialNumber, coverwrite.serial_number, charp, \
+                       S_IRUGO); \
+       MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");         \
+                                                                       \
+       module_param_named(iManufacturer, coverwrite.manufacturer, charp, \
+                       S_IRUGO); \
+       MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");     \
+                                                                       \
+       module_param_named(iProduct, coverwrite.product, charp, S_IRUGO); \
+       MODULE_PARM_DESC(iProduct, "USB Product string")
+
+void usb_composite_overwrite_options(struct usb_composite_dev *cdev,
+               struct usb_composite_overwrite *covr);
+
+static inline u16 get_default_bcdDevice(void)
+{
+       u16 bcdDevice;
+
+       bcdDevice = bin2bcd((LINUX_VERSION_CODE >> 16 & 0xff)) << 8;
+       bcdDevice |= bin2bcd((LINUX_VERSION_CODE >> 8 & 0xff));
+       return bcdDevice;
+}
 
 /* messaging utils */
 #define DBG(d, fmt, args...) \
index 1894f42fe3f7bd1df44a0f46bc1eb456421f5d31..c9d09f8b7ff2d66579ee58700658667347ef8094 100644 (file)
@@ -41,6 +41,14 @@ struct usb_ehci_pdata {
        unsigned        big_endian_mmio:1;
        unsigned        port_power_on:1;
        unsigned        port_power_off:1;
+
+       /* Turn on all power and clocks */
+       int (*power_on)(struct platform_device *pdev);
+       /* Turn off all power and clocks */
+       void (*power_off)(struct platform_device *pdev);
+       /* Turn on only VBUS suspend power and hotplug detection,
+        * turn off everything else */
+       void (*power_suspend)(struct platform_device *pdev);
 };
 
 #endif /* __USB_CORE_EHCI_PDRIVER_H */
index 9517466ababbcb1b2ede5d106c39da30da5bf5d9..5b6e50888248d044c4f9f277165cc5ad7b9a7ad6 100644 (file)
@@ -474,7 +474,8 @@ struct usb_gadget_ops {
 
        /* Those two are deprecated */
        int     (*start)(struct usb_gadget_driver *,
-                       int (*bind)(struct usb_gadget *));
+                       int (*bind)(struct usb_gadget *,
+                               struct usb_gadget_driver *driver));
        int     (*stop)(struct usb_gadget_driver *);
 };
 
@@ -502,6 +503,8 @@ struct usb_gadget_ops {
  * @name: Identifies the controller hardware type.  Used in diagnostics
  *     and sometimes configuration.
  * @dev: Driver model state for this abstract device.
+ * @out_epnum: last used out ep number
+ * @in_epnum: last used in ep number
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -536,6 +539,8 @@ struct usb_gadget {
        unsigned                        a_alt_hnp_support:1;
        const char                      *name;
        struct device                   dev;
+       unsigned                        out_epnum;
+       unsigned                        in_epnum;
 };
 
 static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
@@ -558,14 +563,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
  */
 static inline int gadget_is_dualspeed(struct usb_gadget *g)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       /* runtime test would check "g->max_speed" ... that might be
-        * useful to work around hardware bugs, but is mostly pointless
-        */
-       return 1;
-#else
-       return 0;
-#endif
+       return g->max_speed >= USB_SPEED_HIGH;
 }
 
 /**
@@ -575,15 +573,7 @@ static inline int gadget_is_dualspeed(struct usb_gadget *g)
  */
 static inline int gadget_is_superspeed(struct usb_gadget *g)
 {
-#ifdef CONFIG_USB_GADGET_SUPERSPEED
-       /*
-        * runtime test would check "g->max_speed" ... that might be
-        * useful to work around hardware bugs, but is mostly pointless
-        */
-       return 1;
-#else
-       return 0;
-#endif
+       return g->max_speed >= USB_SPEED_SUPER;
 }
 
 /**
@@ -781,6 +771,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
  *     when the host is disconnected.  May be called in_interrupt; this
  *     may not sleep.  Some devices can't detect disconnect, so this might
  *     not be called except as part of controller shutdown.
+ * @bind: the driver's bind callback
  * @unbind: Invoked when the driver is unbound from a gadget,
  *     usually from rmmod (after a disconnect is reported).
  *     Called in a context that permits sleeping.
@@ -835,6 +826,8 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
 struct usb_gadget_driver {
        char                    *function;
        enum usb_device_speed   max_speed;
+       int                     (*bind)(struct usb_gadget *gadget,
+                                       struct usb_gadget_driver *driver);
        void                    (*unbind)(struct usb_gadget *);
        int                     (*setup)(struct usb_gadget *,
                                        const struct usb_ctrlrequest *);
@@ -860,7 +853,6 @@ struct usb_gadget_driver {
 /**
  * usb_gadget_probe_driver - probe a gadget driver
  * @driver: the driver being registered
- * @bind: the driver's bind callback
  * Context: can sleep
  *
  * Call this in your gadget driver's module initialization function,
@@ -869,8 +861,7 @@ struct usb_gadget_driver {
  * registration call returns.  It's expected that the @bind() function will
  * be in init sections.
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *));
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver);
 
 /**
  * usb_gadget_unregister_driver - unregister a gadget driver
index c5fdb148fc02ccea72ca2b911caa0ab0f7f4be88..608050b2545f917f790fca91bc9f89042626752c 100644 (file)
@@ -135,8 +135,8 @@ struct usb_hcd {
 
        unsigned int            irq;            /* irq allocated */
        void __iomem            *regs;          /* device memory/io */
-       u64                     rsrc_start;     /* memory/io resource start */
-       u64                     rsrc_len;       /* memory/io resource length */
+       resource_size_t         rsrc_start;     /* memory/io resource start */
+       resource_size_t         rsrc_len;       /* memory/io resource length */
        unsigned                power_budget;   /* in mA, 0 = no limit */
 
        /* bandwidth_mutex should be taken before adding or removing
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h
new file mode 100644 (file)
index 0000000..28884c7
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __LINUX_USB_NOP_XCEIV_H
+#define __LINUX_USB_NOP_XCEIV_H
+
+#include <linux/usb/otg.h>
+
+struct nop_usb_xceiv_platform_data {
+       enum usb_phy_type type;
+};
+
+#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
+/* sometimes transceivers are accessed only through e.g. ULPI */
+extern void usb_nop_xceiv_register(void);
+extern void usb_nop_xceiv_unregister(void);
+#else
+static inline void usb_nop_xceiv_register(void)
+{
+}
+
+static inline void usb_nop_xceiv_unregister(void)
+{
+}
+#endif
+
+#endif /* __LINUX_USB_NOP_XCEIV_H */
index 2808f2a9cce806f461f1379239c3f0edf9b2dafd..74e7755168b72c3efed2c39e46a39d7eefc5f858 100644 (file)
@@ -33,6 +33,14 @@ struct usb_ohci_pdata {
        unsigned        big_endian_desc:1;
        unsigned        big_endian_mmio:1;
        unsigned        no_big_frame_no:1;
+
+       /* Turn on all power and clocks */
+       int (*power_on)(struct platform_device *pdev);
+       /* Turn off all power and clocks */
+       void (*power_off)(struct platform_device *pdev);
+       /* Turn on only VBUS suspend power and hotplug detection,
+        * turn off everything else */
+       void (*power_suspend)(struct platform_device *pdev);
 };
 
 #endif /* __USB_CORE_OHCI_PDRIVER_H */
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h
new file mode 100644 (file)
index 0000000..0ea17f8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * omap_usb.h -- omap usb2 phy header file
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_OMAP_USB2_H
+#define __DRIVERS_OMAP_USB2_H
+
+#include <linux/usb/otg.h>
+
+struct omap_usb {
+       struct usb_phy          phy;
+       struct phy_companion    *comparator;
+       struct device           *dev;
+       u32 __iomem             *control_dev;
+       struct clk              *wkupclk;
+       u8                      is_suspended:1;
+};
+
+#define        PHY_PD  0x1
+
+#define        phy_to_omapusb(x)       container_of((x), struct omap_usb, phy)
+
+#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
+extern int omap_usb2_set_comparator(struct phy_companion *comparator);
+#else
+static inline int omap_usb2_set_comparator(struct phy_companion *comparator)
+{
+       return -ENODEV;
+}
+#endif
+
+#endif /* __DRIVERS_OMAP_USB_H */
index 45824be0a2f9e01b09d80b405f390bd27f2fdbcc..e8a5fe87c6bdeb0700310503defff73ee630864a 100644 (file)
@@ -9,56 +9,7 @@
 #ifndef __LINUX_USB_OTG_H
 #define __LINUX_USB_OTG_H
 
-#include <linux/notifier.h>
-
-/* OTG defines lots of enumeration states before device reset */
-enum usb_otg_state {
-       OTG_STATE_UNDEFINED = 0,
-
-       /* single-role peripheral, and dual-role default-b */
-       OTG_STATE_B_IDLE,
-       OTG_STATE_B_SRP_INIT,
-       OTG_STATE_B_PERIPHERAL,
-
-       /* extra dual-role default-b states */
-       OTG_STATE_B_WAIT_ACON,
-       OTG_STATE_B_HOST,
-
-       /* dual-role default-a */
-       OTG_STATE_A_IDLE,
-       OTG_STATE_A_WAIT_VRISE,
-       OTG_STATE_A_WAIT_BCON,
-       OTG_STATE_A_HOST,
-       OTG_STATE_A_SUSPEND,
-       OTG_STATE_A_PERIPHERAL,
-       OTG_STATE_A_WAIT_VFALL,
-       OTG_STATE_A_VBUS_ERR,
-};
-
-enum usb_phy_events {
-       USB_EVENT_NONE,         /* no events or cable disconnected */
-       USB_EVENT_VBUS,         /* vbus valid event */
-       USB_EVENT_ID,           /* id was grounded */
-       USB_EVENT_CHARGER,      /* usb dedicated charger */
-       USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
-};
-
-/* associate a type with PHY */
-enum usb_phy_type {
-       USB_PHY_TYPE_UNDEFINED,
-       USB_PHY_TYPE_USB2,
-       USB_PHY_TYPE_USB3,
-};
-
-struct usb_phy;
-
-/* for transceivers connected thru an ULPI interface, the user must
- * provide access ops
- */
-struct usb_phy_io_ops {
-       int (*read)(struct usb_phy *x, u32 reg);
-       int (*write)(struct usb_phy *x, u32 val, u32 reg);
-};
+#include <linux/usb/phy.h>
 
 struct usb_otg {
        u8                      default_a;
@@ -85,134 +36,9 @@ struct usb_otg {
 
 };
 
-/*
- * the otg driver needs to interact with both device side and host side
- * usb controllers.  it decides which controller is active at a given
- * moment, using the transceiver, ID signal, HNP and sometimes static
- * configuration information (including "board isn't wired for otg").
- */
-struct usb_phy {
-       struct device           *dev;
-       const char              *label;
-       unsigned int             flags;
-
-       enum usb_phy_type       type;
-       enum usb_otg_state      state;
-       enum usb_phy_events     last_event;
-
-       struct usb_otg          *otg;
-
-       struct device           *io_dev;
-       struct usb_phy_io_ops   *io_ops;
-       void __iomem            *io_priv;
-
-       /* for notification of usb_phy_events */
-       struct atomic_notifier_head     notifier;
-
-       /* to pass extra port status to the root hub */
-       u16                     port_status;
-       u16                     port_change;
-
-       /* to support controllers that have multiple transceivers */
-       struct list_head        head;
-
-       /* initialize/shutdown the OTG controller */
-       int     (*init)(struct usb_phy *x);
-       void    (*shutdown)(struct usb_phy *x);
-
-       /* effective for B devices, ignored for A-peripheral */
-       int     (*set_power)(struct usb_phy *x,
-                               unsigned mA);
-
-       /* for non-OTG B devices: set transceiver into suspend mode */
-       int     (*set_suspend)(struct usb_phy *x,
-                               int suspend);
-
-       /* notify phy connect status change */
-       int     (*notify_connect)(struct usb_phy *x, int port);
-       int     (*notify_disconnect)(struct usb_phy *x, int port);
-};
-
-
-/* for board-specific init logic */
-extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
-extern void usb_remove_phy(struct usb_phy *);
-
-#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
-/* sometimes transceivers are accessed only through e.g. ULPI */
-extern void usb_nop_xceiv_register(void);
-extern void usb_nop_xceiv_unregister(void);
-#else
-static inline void usb_nop_xceiv_register(void)
-{
-}
-
-static inline void usb_nop_xceiv_unregister(void)
-{
-}
-#endif
-
-/* helpers for direct access thru low-level io interface */
-static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
-{
-       if (x->io_ops && x->io_ops->read)
-               return x->io_ops->read(x, reg);
-
-       return -EINVAL;
-}
-
-static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
-{
-       if (x->io_ops && x->io_ops->write)
-               return x->io_ops->write(x, val, reg);
-
-       return -EINVAL;
-}
-
-static inline int
-usb_phy_init(struct usb_phy *x)
-{
-       if (x->init)
-               return x->init(x);
-
-       return 0;
-}
-
-static inline void
-usb_phy_shutdown(struct usb_phy *x)
-{
-       if (x->shutdown)
-               x->shutdown(x);
-}
-
-/* for usb host and peripheral controller drivers */
 #ifdef CONFIG_USB_OTG_UTILS
-extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
-extern struct usb_phy *devm_usb_get_phy(struct device *dev,
-       enum usb_phy_type type);
-extern void usb_put_phy(struct usb_phy *);
-extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
 extern const char *otg_state_string(enum usb_otg_state state);
 #else
-static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
-{
-       return NULL;
-}
-
-static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
-       enum usb_phy_type type)
-{
-       return NULL;
-}
-
-static inline void usb_put_phy(struct usb_phy *x)
-{
-}
-
-static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
-{
-}
-
 static inline const char *otg_state_string(enum usb_otg_state state)
 {
        return NULL;
@@ -261,42 +87,6 @@ otg_set_peripheral(struct usb_otg *otg, struct usb_gadget *periph)
        return -ENOTSUPP;
 }
 
-static inline int
-usb_phy_set_power(struct usb_phy *x, unsigned mA)
-{
-       if (x && x->set_power)
-               return x->set_power(x, mA);
-       return 0;
-}
-
-/* Context: can sleep */
-static inline int
-usb_phy_set_suspend(struct usb_phy *x, int suspend)
-{
-       if (x->set_suspend != NULL)
-               return x->set_suspend(x, suspend);
-       else
-               return 0;
-}
-
-static inline int
-usb_phy_notify_connect(struct usb_phy *x, int port)
-{
-       if (x->notify_connect)
-               return x->notify_connect(x, port);
-       else
-               return 0;
-}
-
-static inline int
-usb_phy_notify_disconnect(struct usb_phy *x, int port)
-{
-       if (x->notify_disconnect)
-               return x->notify_disconnect(x, port);
-       else
-               return 0;
-}
-
 static inline int
 otg_start_srp(struct usb_otg *otg)
 {
@@ -306,31 +96,7 @@ otg_start_srp(struct usb_otg *otg)
        return -ENOTSUPP;
 }
 
-/* notifiers */
-static inline int
-usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&x->notifier, nb);
-}
-
-static inline void
-usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
-{
-       atomic_notifier_chain_unregister(&x->notifier, nb);
-}
-
 /* for OTG controller drivers (and maybe other stuff) */
 extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
 
-static inline const char *usb_phy_type_string(enum usb_phy_type type)
-{
-       switch (type) {
-       case USB_PHY_TYPE_USB2:
-               return "USB2 PHY";
-       case USB_PHY_TYPE_USB3:
-               return "USB3 PHY";
-       default:
-               return "UNKNOWN PHY TYPE";
-       }
-}
 #endif /* __LINUX_USB_OTG_H */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
new file mode 100644 (file)
index 0000000..06b5bae
--- /dev/null
@@ -0,0 +1,233 @@
+/* USB OTG (On The Go) defines */
+/*
+ *
+ * These APIs may be used between USB controllers.  USB device drivers
+ * (for either host or peripheral roles) don't use these calls; they
+ * continue to use just usb_device and usb_gadget.
+ */
+
+#ifndef __LINUX_USB_PHY_H
+#define __LINUX_USB_PHY_H
+
+#include <linux/notifier.h>
+
+enum usb_phy_events {
+       USB_EVENT_NONE,         /* no events or cable disconnected */
+       USB_EVENT_VBUS,         /* vbus valid event */
+       USB_EVENT_ID,           /* id was grounded */
+       USB_EVENT_CHARGER,      /* usb dedicated charger */
+       USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
+};
+
+/* associate a type with PHY */
+enum usb_phy_type {
+       USB_PHY_TYPE_UNDEFINED,
+       USB_PHY_TYPE_USB2,
+       USB_PHY_TYPE_USB3,
+};
+
+/* OTG defines lots of enumeration states before device reset */
+enum usb_otg_state {
+       OTG_STATE_UNDEFINED = 0,
+
+       /* single-role peripheral, and dual-role default-b */
+       OTG_STATE_B_IDLE,
+       OTG_STATE_B_SRP_INIT,
+       OTG_STATE_B_PERIPHERAL,
+
+       /* extra dual-role default-b states */
+       OTG_STATE_B_WAIT_ACON,
+       OTG_STATE_B_HOST,
+
+       /* dual-role default-a */
+       OTG_STATE_A_IDLE,
+       OTG_STATE_A_WAIT_VRISE,
+       OTG_STATE_A_WAIT_BCON,
+       OTG_STATE_A_HOST,
+       OTG_STATE_A_SUSPEND,
+       OTG_STATE_A_PERIPHERAL,
+       OTG_STATE_A_WAIT_VFALL,
+       OTG_STATE_A_VBUS_ERR,
+};
+
+struct usb_phy;
+struct usb_otg;
+
+/* for transceivers connected thru an ULPI interface, the user must
+ * provide access ops
+ */
+struct usb_phy_io_ops {
+       int (*read)(struct usb_phy *x, u32 reg);
+       int (*write)(struct usb_phy *x, u32 val, u32 reg);
+};
+
+struct usb_phy {
+       struct device           *dev;
+       const char              *label;
+       unsigned int             flags;
+
+       enum usb_phy_type       type;
+       enum usb_otg_state      state;
+       enum usb_phy_events     last_event;
+
+       struct usb_otg          *otg;
+
+       struct device           *io_dev;
+       struct usb_phy_io_ops   *io_ops;
+       void __iomem            *io_priv;
+
+       /* for notification of usb_phy_events */
+       struct atomic_notifier_head     notifier;
+
+       /* to pass extra port status to the root hub */
+       u16                     port_status;
+       u16                     port_change;
+
+       /* to support controllers that have multiple transceivers */
+       struct list_head        head;
+
+       /* initialize/shutdown the OTG controller */
+       int     (*init)(struct usb_phy *x);
+       void    (*shutdown)(struct usb_phy *x);
+
+       /* effective for B devices, ignored for A-peripheral */
+       int     (*set_power)(struct usb_phy *x,
+                               unsigned mA);
+
+       /* for non-OTG B devices: set transceiver into suspend mode */
+       int     (*set_suspend)(struct usb_phy *x,
+                               int suspend);
+
+       /* notify phy connect status change */
+       int     (*notify_connect)(struct usb_phy *x, int port);
+       int     (*notify_disconnect)(struct usb_phy *x, int port);
+};
+
+
+/* for board-specific init logic */
+extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
+extern void usb_remove_phy(struct usb_phy *);
+
+/* helpers for direct access thru low-level io interface */
+static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
+{
+       if (x->io_ops && x->io_ops->read)
+               return x->io_ops->read(x, reg);
+
+       return -EINVAL;
+}
+
+static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
+{
+       if (x->io_ops && x->io_ops->write)
+               return x->io_ops->write(x, val, reg);
+
+       return -EINVAL;
+}
+
+static inline int
+usb_phy_init(struct usb_phy *x)
+{
+       if (x->init)
+               return x->init(x);
+
+       return 0;
+}
+
+static inline void
+usb_phy_shutdown(struct usb_phy *x)
+{
+       if (x->shutdown)
+               x->shutdown(x);
+}
+
+/* for usb host and peripheral controller drivers */
+#ifdef CONFIG_USB_OTG_UTILS
+extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
+extern struct usb_phy *devm_usb_get_phy(struct device *dev,
+       enum usb_phy_type type);
+extern void usb_put_phy(struct usb_phy *);
+extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
+#else
+static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
+{
+       return NULL;
+}
+
+static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
+       enum usb_phy_type type)
+{
+       return NULL;
+}
+
+static inline void usb_put_phy(struct usb_phy *x)
+{
+}
+
+static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
+{
+}
+
+#endif
+
+static inline int
+usb_phy_set_power(struct usb_phy *x, unsigned mA)
+{
+       if (x && x->set_power)
+               return x->set_power(x, mA);
+       return 0;
+}
+
+/* Context: can sleep */
+static inline int
+usb_phy_set_suspend(struct usb_phy *x, int suspend)
+{
+       if (x->set_suspend != NULL)
+               return x->set_suspend(x, suspend);
+       else
+               return 0;
+}
+
+static inline int
+usb_phy_notify_connect(struct usb_phy *x, int port)
+{
+       if (x->notify_connect)
+               return x->notify_connect(x, port);
+       else
+               return 0;
+}
+
+static inline int
+usb_phy_notify_disconnect(struct usb_phy *x, int port)
+{
+       if (x->notify_disconnect)
+               return x->notify_disconnect(x, port);
+       else
+               return 0;
+}
+
+/* notifiers */
+static inline int
+usb_register_notifier(struct usb_phy *x, struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&x->notifier, nb);
+}
+
+static inline void
+usb_unregister_notifier(struct usb_phy *x, struct notifier_block *nb)
+{
+       atomic_notifier_chain_unregister(&x->notifier, nb);
+}
+
+static inline const char *usb_phy_type_string(enum usb_phy_type type)
+{
+       switch (type) {
+       case USB_PHY_TYPE_USB2:
+               return "USB2 PHY";
+       case USB_PHY_TYPE_USB3:
+               return "USB3 PHY";
+       default:
+               return "UNKNOWN PHY TYPE";
+       }
+}
+#endif /* __LINUX_USB_PHY_H */
diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h
new file mode 100644 (file)
index 0000000..edd2ec2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * phy-companion.h -- phy companion to indicate the comparator part of PHY
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __DRIVERS_PHY_COMPANION_H
+#define __DRIVERS_PHY_COMPANION_H
+
+#include <linux/usb/otg.h>
+
+/* phy_companion to take care of VBUS, ID and srp capabilities */
+struct phy_companion {
+
+       /* effective for A-peripheral, ignored for B devices */
+       int     (*set_vbus)(struct phy_companion *x, bool enabled);
+
+       /* for B devices only:  start session with A-Host */
+       int     (*start_srp)(struct phy_companion *x);
+};
+
+#endif /* __DRIVERS_PHY_COMPANION_H */
index 3e93de7ecbc365c59e680f626990d8be80df0f43..52f944dfe2fd68305f1f19a4f08c018e9226595c 100644 (file)
@@ -19,8 +19,8 @@
 /* device can't handle its Configuration or Interface strings */
 #define USB_QUIRK_CONFIG_INTF_STRINGS  0x00000008
 
-/*device will morph if reset, don't use reset for handling errors */
-#define USB_QUIRK_RESET_MORPHS         0x00000010
+/* device can't be reset(e.g morph devices), don't use reset */
+#define USB_QUIRK_RESET                        0x00000010
 
 /* device has more interface descriptions than the bNumInterfaces count,
    and can't handle talking to these interfaces */
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
new file mode 100644 (file)
index 0000000..176b1ca
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __TEGRA_USB_PHY_H
+#define __TEGRA_USB_PHY_H
+
+#include <linux/clk.h>
+#include <linux/usb/otg.h>
+
+struct tegra_utmip_config {
+       u8 hssync_start_delay;
+       u8 elastic_limit;
+       u8 idle_wait_delay;
+       u8 term_range_adj;
+       u8 xcvr_setup;
+       u8 xcvr_lsfslew;
+       u8 xcvr_lsrslew;
+};
+
+struct tegra_ulpi_config {
+       int reset_gpio;
+       const char *clk;
+};
+
+enum tegra_usb_phy_port_speed {
+       TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
+       TEGRA_USB_PHY_PORT_SPEED_LOW,
+       TEGRA_USB_PHY_PORT_SPEED_HIGH,
+};
+
+enum tegra_usb_phy_mode {
+       TEGRA_USB_PHY_MODE_DEVICE,
+       TEGRA_USB_PHY_MODE_HOST,
+};
+
+struct tegra_xtal_freq;
+
+struct tegra_usb_phy {
+       int instance;
+       const struct tegra_xtal_freq *freq;
+       void __iomem *regs;
+       void __iomem *pad_regs;
+       struct clk *clk;
+       struct clk *pll_u;
+       struct clk *pad_clk;
+       enum tegra_usb_phy_mode mode;
+       void *config;
+       struct usb_phy *ulpi;
+       struct usb_phy u_phy;
+       struct device *dev;
+};
+
+struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
+       void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
+
+void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
+
+void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
+                                enum tegra_usb_phy_port_speed port_speed);
+
+void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
+
+#endif /* __TEGRA_USB_PHY_H */
index e84e769aaddc39ec51515c0b1169727115c51ad9..bf99cd01be206ebeb170d826e176c3ac22e1493e 100644 (file)
 enum { US_DO_ALL_FLAGS };
 #undef US_FLAG
 
-/*
- * The bias field for libusual and friends.
- */
-#define USB_US_TYPE_NONE   0
-#define USB_US_TYPE_STOR   1           /* usb-storage */
-#define USB_US_TYPE_UB     2           /* ub */
-
-#define USB_US_TYPE(flags)             (((flags) >> 24) & 0xFF)
-#define USB_US_ORIG_FLAGS(flags)       ((flags) & 0x00FFFFFF)
-
 #include <linux/usb/storage.h>
 
-/*
- */
 extern int usb_usual_ignore_device(struct usb_interface *intf);
 extern struct usb_device_id usb_storage_usb_ids[];
 
-#ifdef CONFIG_USB_LIBUSUAL
-
-extern void usb_usual_set_present(int type);
-extern void usb_usual_clear_present(int type);
-extern int usb_usual_check_type(const struct usb_device_id *, int type);
-#else
-
-#define usb_usual_set_present(t)       do { } while(0)
-#define usb_usual_clear_present(t)     do { } while(0)
-#define usb_usual_check_type(id, t)    (0)
-#endif /* CONFIG_USB_LIBUSUAL */
-
 #endif /* __LINUX_USB_USUAL_H */
index 3b74666be027d438ed4631d2e872a1f606c2225a..4abe28e41cbcd90ce9297ac65bafbcc9add4c861 100644 (file)
@@ -131,6 +131,19 @@ struct usbdevfs_hub_portinfo {
 #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM                0x04
 #define USBDEVFS_CAP_BULK_SCATTER_GATHER       0x08
 
+/* USBDEVFS_DISCONNECT_CLAIM flags & struct */
+
+/* disconnect-and-claim if the driver matches the driver field */
+#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER    0x01
+/* disconnect-and-claim except when the driver matches the driver field */
+#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER        0x02
+
+struct usbdevfs_disconnect_claim {
+       unsigned int interface;
+       unsigned int flags;
+       char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
 #ifdef __KERNEL__
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
@@ -211,5 +224,6 @@ struct usbdevfs_ioctl32 {
 #define USBDEVFS_CLAIM_PORT        _IOR('U', 24, unsigned int)
 #define USBDEVFS_RELEASE_PORT      _IOR('U', 25, unsigned int)
 #define USBDEVFS_GET_CAPABILITIES  _IOR('U', 26, __u32)
+#define USBDEVFS_DISCONNECT_CLAIM  _IOR('U', 27, struct usbdevfs_disconnect_claim)
 
 #endif /* _LINUX_USBDEVICE_FS_H */
index c66fe3332d8376ab4fd226d60d7afd16e94b1a9f..50c3e8fa06a865b439047f80a0ac9be9a26cfeeb 100644 (file)
@@ -104,7 +104,6 @@ static inline void wait_on_inode(struct inode *inode)
        wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE);
 }
 
-
 /*
  * mm/page-writeback.c
  */
index 493fa0c790051ecd10a41050e7c7a05d323a52b0..3d254e10ff30e7ab3c5a4fee2ee0b38f1309bd94 100644 (file)
@@ -96,6 +96,7 @@ enum ieee80211_band {
  *     is not permitted.
  * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel
  *     is not permitted.
+ * @IEEE80211_CHAN_NO_OFDM: OFDM is not allowed on this channel.
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
@@ -104,6 +105,7 @@ enum ieee80211_channel_flags {
        IEEE80211_CHAN_RADAR            = 1<<3,
        IEEE80211_CHAN_NO_HT40PLUS      = 1<<4,
        IEEE80211_CHAN_NO_HT40MINUS     = 1<<5,
+       IEEE80211_CHAN_NO_OFDM          = 1<<6,
 };
 
 #define IEEE80211_CHAN_NO_HT40 \
index 550debfc240384f529562e3cc10cafcd342725f4..389cf621161d6903510c023e04e57a4ccd03072c 100644 (file)
@@ -305,6 +305,8 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                        }
                }
        } else if (drop) {
+               u32 delta;
+
                if (params->ecn && INET_ECN_set_ce(skb)) {
                        stats->ecn_mark++;
                } else {
@@ -320,9 +322,11 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                 * assume that the drop rate that controlled the queue on the
                 * last cycle is a good starting point to control it now.
                 */
-               if (codel_time_before(now - vars->drop_next,
+               delta = vars->count - vars->lastcount;
+               if (delta > 1 &&
+                   codel_time_before(now - vars->drop_next,
                                      16 * params->interval)) {
-                       vars->count = (vars->count - vars->lastcount) | 1;
+                       vars->count = delta;
                        /* we dont care if rec_inv_sqrt approximation
                         * is not very precise :
                         * Next Newton steps will correct it quadratically.
index baf59789006427bc7c373449b62b271e6e777d15..621e3513ef5ed2c833a16902761b3d5c1ed2ebaf 100644 (file)
@@ -110,7 +110,7 @@ struct dst_entry {
 };
 
 extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
-extern const u32 dst_default_metrics[RTAX_MAX];
+extern const u32 dst_default_metrics[];
 
 #define DST_METRICS_READ_ONLY  0x1UL
 #define __DST_METRICS_PTR(Y)   \
index 5ee66f517b4f6c34734be9d5f6552439802a5a38..ba1d3615acbb7bc481e7b676d897140cea0213b6 100644 (file)
@@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops {
        int         (*queue_xmit)(struct sk_buff *skb, struct flowi *fl);
        void        (*send_check)(struct sock *sk, struct sk_buff *skb);
        int         (*rebuild_header)(struct sock *sk);
+       void        (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb);
        int         (*conn_request)(struct sock *sk, struct sk_buff *skb);
        struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
                                      struct request_sock *req,
index 83b567fe194163b74f734cedaf1dffff28e914a6..613cfa4016728300da88a8fc6f1f664de99da5cc 100644 (file)
@@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
        return flags;
 }
 
-static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
-{
-       struct dst_entry *dst = skb_dst(skb);
-
-       dst_hold(dst);
-       sk->sk_rx_dst = dst;
-       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
-}
-
 #endif /* _INET_SOCK_H */
index bd5e444a19ce43482f09f695c6e3b36a303302b3..5a5d84d3d2c6b6e3777035a631fb10e7479ab8de 100644 (file)
@@ -120,7 +120,7 @@ extern struct sk_buff  *__ip_make_skb(struct sock *sk,
                                      struct flowi4 *fl4,
                                      struct sk_buff_head *queue,
                                      struct inet_cork *cork);
-extern int             ip_send_skb(struct sk_buff *skb);
+extern int             ip_send_skb(struct net *net, struct sk_buff *skb);
 extern int             ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4);
 extern void            ip_flush_pending_frames(struct sock *sk);
 extern struct sk_buff  *ip_make_skb(struct sock *sk,
index 226c846cab08bdf84e0991aee83124c42e6aab0d..f2d0fc570527baf216f34cd364c0162330dcbd28 100644 (file)
@@ -133,7 +133,7 @@ extern int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
 extern void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb);
 extern void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb);
 
-extern int llc_station_init(void);
+extern void llc_station_init(void);
 extern void llc_station_exit(void);
 
 #ifdef CONFIG_PROC_FS
index 079d7887dac13697d0dfc5d0cc6ce256800151d0..7dc0854f0b3891992696002b7f75edf7a01233ab 100644 (file)
@@ -70,9 +70,11 @@ static __inline__ void scm_destroy(struct scm_cookie *scm)
 }
 
 static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
-                              struct scm_cookie *scm)
+                              struct scm_cookie *scm, bool forcecreds)
 {
        memset(scm, 0, sizeof(*scm));
+       if (forcecreds)
+               scm_set_cred(scm, task_tgid(current), current_cred());
        unix_get_peersec_dgram(sock, scm);
        if (msg->msg_controllen <= 0)
                return 0;
index b3730239bf1828bd9fb618b8b8988b37832fe5c3..72132aef53fc61a721ce23c8fbc4fe17cb7a9699 100644 (file)
@@ -218,6 +218,7 @@ struct cg_proto;
   *    @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
   *    @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
   *    @sk_gso_max_size: Maximum GSO segment size to build
+  *    @sk_gso_max_segs: Maximum number of GSO segments
   *    @sk_lingertime: %SO_LINGER l_linger setting
   *    @sk_backlog: always used with the per-socket spinlock held
   *    @sk_callback_lock: used with the callbacks in the end of this struct
@@ -338,6 +339,7 @@ struct sock {
        netdev_features_t       sk_route_nocaps;
        int                     sk_gso_type;
        unsigned int            sk_gso_max_size;
+       u16                     sk_gso_max_segs;
        int                     sk_rcvlowat;
        unsigned long           sk_lingertime;
        struct sk_buff_head     sk_error_queue;
index e19124b84cd2a299a28737e60e1e0346efe24c2f..1f000ffe70758c0596b8c4d18230e781b88f495f 100644 (file)
@@ -464,6 +464,7 @@ extern int tcp_disconnect(struct sock *sk, int flags);
 void tcp_connect_init(struct sock *sk);
 void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);
 int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size);
+void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb);
 
 /* From syncookies.c */
 extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
index d9509eb29b80f989eb47531877279ae93f31f85c..976a81abe1a231de348085a92c8f3110a21fc3fa 100644 (file)
@@ -213,6 +213,9 @@ struct xfrm_state {
        struct xfrm_lifetime_cur curlft;
        struct tasklet_hrtimer  mtimer;
 
+       /* used to fix curlft->add_time when changing date */
+       long            saved_tmo;
+
        /* Last used time */
        unsigned long           lastused;
 
@@ -238,6 +241,7 @@ static inline struct net *xs_net(struct xfrm_state *x)
 
 /* xflags - make enum if more show up */
 #define XFRM_TIME_DEFER        1
+#define XFRM_SOFT_EXPIRE 2
 
 enum {
        XFRM_STATE_VOID,
@@ -288,6 +292,8 @@ struct xfrm_policy_afinfo {
                                                  struct flowi *fl,
                                                  int reverse);
        int                     (*get_tos)(const struct flowi *fl);
+       void                    (*init_dst)(struct net *net,
+                                           struct xfrm_dst *dst);
        int                     (*init_path)(struct xfrm_dst *path,
                                             struct dst_entry *dst,
                                             int nfheader_len);
index c75c0d1a85e2acabb2e30d43ba1e6150f1268c6a..cdca2ab1e7112f8e79156f39f318d5f3e4405cbd 100644 (file)
@@ -1075,7 +1075,8 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 const char *snd_pcm_format_name(snd_pcm_format_t format);
 
 /**
- * Get a string naming the direction of a stream
+ * snd_pcm_stream_str - Get a string naming the direction of a stream
+ * @substream: the pcm substream instance
  */
 static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
 {
index 128ce46fa48a799fa9b3b332a07d2babfee01925..015cea01ae39bedd1a1bf796e23a8f90f061e5e2 100644 (file)
@@ -503,8 +503,6 @@ struct se_cmd {
        u32                     se_ordered_id;
        /* Total size in bytes associated with command */
        u32                     data_length;
-       /* SCSI Presented Data Transfer Length */
-       u32                     cmd_spdtl;
        u32                     residual_count;
        u32                     orig_fe_lun;
        /* Persistent Reservation key */
index ea7a2035456d4f913e15b9997696ab5ca4934ad1..5a8671e8a67ff8fa8f715311300901181555d78e 100644 (file)
@@ -73,6 +73,9 @@ DECLARE_EVENT_CLASS(sched_wakeup_template,
                __entry->prio           = p->prio;
                __entry->success        = success;
                __entry->target_cpu     = task_cpu(p);
+       )
+       TP_perf_assign(
+               __perf_task(p);
        ),
 
        TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
@@ -325,6 +328,7 @@ DECLARE_EVENT_CLASS(sched_stat_template,
        )
        TP_perf_assign(
                __perf_count(delay);
+               __perf_task(tsk);
        ),
 
        TP_printk("comm=%s pid=%d delay=%Lu [ns]",
index c6bc2faaf2611533b1b2a72e6d3e191fa6033616..a763888a36f961339d5a437190c1c944077f875f 100644 (file)
@@ -712,6 +712,9 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 #undef __perf_count
 #define __perf_count(c) __count = (c)
 
+#undef __perf_task
+#define __perf_task(t) __task = (t)
+
 #undef TP_perf_assign
 #define TP_perf_assign(args...) args
 
@@ -725,6 +728,7 @@ perf_trace_##call(void *__data, proto)                                      \
        struct ftrace_raw_##call *entry;                                \
        struct pt_regs __regs;                                          \
        u64 __addr = 0, __count = 1;                                    \
+       struct task_struct *__task = NULL;                              \
        struct hlist_head *head;                                        \
        int __entry_size;                                               \
        int __data_size;                                                \
@@ -752,7 +756,7 @@ perf_trace_##call(void *__data, proto)                                      \
                                                                        \
        head = this_cpu_ptr(event_call->perf_events);                   \
        perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
-               __count, &__regs, head);                                \
+               __count, &__regs, head, __task);                        \
 }
 
 /*
index e60679de61c3a050640554966d34542fcc13a7bd..b28673087ac006e79f4563b1a06d39eb1b163d37 100644 (file)
@@ -461,10 +461,6 @@ static void __init mm_init(void)
        percpu_init_late();
        pgtable_cache_init();
        vmalloc_init();
-#ifdef CONFIG_X86
-       if (efi_enabled)
-               efi_enter_virtual_mode();
-#endif
 }
 
 asmlinkage void __init start_kernel(void)
@@ -606,6 +602,10 @@ asmlinkage void __init start_kernel(void)
        calibrate_delay();
        pidmap_init();
        anon_vma_init();
+#ifdef CONFIG_X86
+       if (efi_enabled)
+               efi_enter_virtual_mode();
+#endif
        thread_info_cache_init();
        cred_init();
        fork_init(totalram_pages);
index f8e54f5b90804ea58309da551fcd40dd8cf12333..9a08acc9e64923ea8af5bb9286d6f2ddd48c052e 100644 (file)
@@ -726,7 +726,6 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
                        struct mq_attr *attr)
 {
        const struct cred *cred = current_cred();
-       struct file *result;
        int ret;
 
        if (attr) {
@@ -748,21 +747,11 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
        }
 
        mode &= ~current_umask();
-       ret = mnt_want_write(path->mnt);
-       if (ret)
-               return ERR_PTR(ret);
        ret = vfs_create(dir, path->dentry, mode, true);
        path->dentry->d_fsdata = NULL;
-       if (!ret)
-               result = dentry_open(path, oflag, cred);
-       else
-               result = ERR_PTR(ret);
-       /*
-        * dentry_open() took a persistent mnt_want_write(),
-        * so we can now drop this one.
-        */
-       mnt_drop_write(path->mnt);
-       return result;
+       if (ret)
+               return ERR_PTR(ret);
+       return dentry_open(path, oflag, cred);
 }
 
 /* Opens existing queue */
@@ -788,7 +777,9 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
        struct mq_attr attr;
        int fd, error;
        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
-       struct dentry *root = ipc_ns->mq_mnt->mnt_root;
+       struct vfsmount *mnt = ipc_ns->mq_mnt;
+       struct dentry *root = mnt->mnt_root;
+       int ro;
 
        if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
                return -EFAULT;
@@ -802,6 +793,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
        if (fd < 0)
                goto out_putname;
 
+       ro = mnt_want_write(mnt);       /* we'll drop it in any case */
        error = 0;
        mutex_lock(&root->d_inode->i_mutex);
        path.dentry = lookup_one_len(name, root, strlen(name));
@@ -809,7 +801,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
                error = PTR_ERR(path.dentry);
                goto out_putfd;
        }
-       path.mnt = mntget(ipc_ns->mq_mnt);
+       path.mnt = mntget(mnt);
 
        if (oflag & O_CREAT) {
                if (path.dentry->d_inode) {     /* entry already exists */
@@ -820,6 +812,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
                        }
                        filp = do_open(&path, oflag);
                } else {
+                       if (ro) {
+                               error = ro;
+                               goto out;
+                       }
                        filp = do_create(ipc_ns, root->d_inode,
                                                &path, oflag, mode,
                                                u_attr ? &attr : NULL);
@@ -845,6 +841,7 @@ out_putfd:
                fd = error;
        }
        mutex_unlock(&root->d_inode->i_mutex);
+       mnt_drop_write(mnt);
 out_putname:
        putname(name);
        return fd;
@@ -857,40 +854,38 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
        struct dentry *dentry;
        struct inode *inode = NULL;
        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
+       struct vfsmount *mnt = ipc_ns->mq_mnt;
 
        name = getname(u_name);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
-       mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex,
-                       I_MUTEX_PARENT);
-       dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
+       err = mnt_want_write(mnt);
+       if (err)
+               goto out_name;
+       mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT);
+       dentry = lookup_one_len(name, mnt->mnt_root, strlen(name));
        if (IS_ERR(dentry)) {
                err = PTR_ERR(dentry);
                goto out_unlock;
        }
 
-       if (!dentry->d_inode) {
-               err = -ENOENT;
-               goto out_err;
-       }
-
        inode = dentry->d_inode;
-       if (inode)
+       if (!inode) {
+               err = -ENOENT;
+       } else {
                ihold(inode);
-       err = mnt_want_write(ipc_ns->mq_mnt);
-       if (err)
-               goto out_err;
-       err = vfs_unlink(dentry->d_parent->d_inode, dentry);
-       mnt_drop_write(ipc_ns->mq_mnt);
-out_err:
+               err = vfs_unlink(dentry->d_parent->d_inode, dentry);
+       }
        dput(dentry);
 
 out_unlock:
-       mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
-       putname(name);
+       mutex_unlock(&mnt->mnt_root->d_inode->i_mutex);
        if (inode)
                iput(inode);
+       mnt_drop_write(mnt);
+out_name:
+       putname(name);
 
        return err;
 }
index 3a5ca582ba1ebe2373803bfbf1887357d05b523e..ed206fd88cca76e75a0d8866ab703a7f6fdf38d6 100644 (file)
@@ -250,7 +250,6 @@ static void untag_chunk(struct node *p)
                spin_unlock(&hash_lock);
                spin_unlock(&entry->lock);
                fsnotify_destroy_mark(entry);
-               fsnotify_put_mark(entry);
                goto out;
        }
 
@@ -259,7 +258,7 @@ static void untag_chunk(struct node *p)
 
        fsnotify_duplicate_mark(&new->mark, entry);
        if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) {
-               free_chunk(new);
+               fsnotify_put_mark(&new->mark);
                goto Fallback;
        }
 
@@ -293,7 +292,7 @@ static void untag_chunk(struct node *p)
        spin_unlock(&hash_lock);
        spin_unlock(&entry->lock);
        fsnotify_destroy_mark(entry);
-       fsnotify_put_mark(entry);
+       fsnotify_put_mark(&new->mark);  /* drop initial reference */
        goto out;
 
 Fallback:
@@ -322,7 +321,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
 
        entry = &chunk->mark;
        if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) {
-               free_chunk(chunk);
+               fsnotify_put_mark(entry);
                return -ENOSPC;
        }
 
@@ -347,6 +346,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
        insert_hash(chunk);
        spin_unlock(&hash_lock);
        spin_unlock(&entry->lock);
+       fsnotify_put_mark(entry);       /* drop initial reference */
        return 0;
 }
 
@@ -396,7 +396,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
        fsnotify_duplicate_mark(chunk_entry, old_entry);
        if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) {
                spin_unlock(&old_entry->lock);
-               free_chunk(chunk);
+               fsnotify_put_mark(chunk_entry);
                fsnotify_put_mark(old_entry);
                return -ENOSPC;
        }
@@ -444,8 +444,8 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
        spin_unlock(&chunk_entry->lock);
        spin_unlock(&old_entry->lock);
        fsnotify_destroy_mark(old_entry);
+       fsnotify_put_mark(chunk_entry); /* drop initial reference */
        fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */
-       fsnotify_put_mark(old_entry); /* and kill it */
        return 0;
 }
 
@@ -916,7 +916,12 @@ static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify
        struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
 
        evict_chunk(chunk);
-       fsnotify_put_mark(entry);
+
+       /*
+        * We are guaranteed to have at least one reference to the mark from
+        * either the inode or the caller of fsnotify_destroy_mark().
+        */
+       BUG_ON(atomic_read(&entry->refcnt) < 1);
 }
 
 static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
index 8b68ce78ff170b8777be887a3bc8407c59863ba5..be7b33b73d3001eef1b676ad1efde4f318824902 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kdb.h>
 #include <linux/kdebug.h>
 #include <linux/export.h>
+#include <linux/hardirq.h>
 #include "kdb_private.h"
 #include "../debug_core.h"
 
@@ -52,6 +53,9 @@ int kdb_stub(struct kgdb_state *ks)
        if (atomic_read(&kgdb_setting_breakpoint))
                reason = KDB_REASON_KEYBOARD;
 
+       if (in_nmi())
+               reason = KDB_REASON_NMI;
+
        for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {
                if ((bp->bp_enabled) && (bp->bp_addr == addr)) {
                        reason = KDB_REASON_BREAK;
index bb9520f0f6ff8e607d0b08b2561efa62f4ba3b8d..0a69d2adc4f3cb7fb49a14c3ccefb87cfe0084bd 100644 (file)
@@ -715,9 +715,6 @@ kdb_printit:
        /* check for having reached the LINES number of printed lines */
        if (kdb_nextline == linecount) {
                char buf1[16] = "";
-#if defined(CONFIG_SMP)
-               char buf2[32];
-#endif
 
                /* Watch out for recursion here.  Any routine that calls
                 * kdb_printf will come back through here.  And kdb_read
@@ -732,14 +729,6 @@ kdb_printit:
                if (moreprompt == NULL)
                        moreprompt = "more> ";
 
-#if defined(CONFIG_SMP)
-               if (strchr(moreprompt, '%')) {
-                       sprintf(buf2, moreprompt, get_cpu());
-                       put_cpu();
-                       moreprompt = buf2;
-               }
-#endif
-
                kdb_input_flush();
                c = console_drivers;
 
index 1f91413edb87d0c9b77efc4e84c9b2f9729e9b8c..31df1706b9a9344bf3d63a1b0146987378060ed4 100644 (file)
@@ -139,11 +139,10 @@ static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t);
 static char *__env[] = {
 #if defined(CONFIG_SMP)
  "PROMPT=[%d]kdb> ",
- "MOREPROMPT=[%d]more> ",
 #else
  "PROMPT=kdb> ",
- "MOREPROMPT=more> ",
 #endif
+ "MOREPROMPT=more> ",
  "RADIX=16",
  "MDCOUNT=8",                  /* lines of md output */
  KDB_PLATFORM_ENV,
@@ -1236,18 +1235,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
                *cmdbuf = '\0';
                *(cmd_hist[cmd_head]) = '\0';
 
-               if (KDB_FLAG(ONLY_DO_DUMP)) {
-                       /* kdb is off but a catastrophic error requires a dump.
-                        * Take the dump and reboot.
-                        * Turn on logging so the kdb output appears in the log
-                        * buffer in the dump.
-                        */
-                       const char *setargs[] = { "set", "LOGGING", "1" };
-                       kdb_set(2, setargs);
-                       kdb_reboot(0, NULL);
-                       /*NOTREACHED*/
-               }
-
 do_full_getstr:
 #if defined(CONFIG_SMP)
                snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
index 6581a040f39926dd46878640413bfd180922415a..98d4597f43d69e35a76535fac7d0bb6821ebdf7f 100644 (file)
@@ -153,7 +153,8 @@ put_callchain_entry(int rctx)
        put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
 }
 
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+struct perf_callchain_entry *
+perf_callchain(struct perf_event *event, struct pt_regs *regs)
 {
        int rctx;
        struct perf_callchain_entry *entry;
@@ -178,6 +179,12 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
        }
 
        if (regs) {
+               /*
+                * Disallow cross-task user callchains.
+                */
+               if (event->ctx->task && event->ctx->task != current)
+                       goto exit_put;
+
                perf_callchain_store(entry, PERF_CONTEXT_USER);
                perf_callchain_user(entry, regs);
        }
index f1cf0edeb39afa1a3f6543a2f383ac8c4828127b..b7935fcec7d923b0b0b89fe0fe7dfdf61967b447 100644 (file)
@@ -4039,7 +4039,7 @@ void perf_prepare_sample(struct perf_event_header *header,
        if (sample_type & PERF_SAMPLE_CALLCHAIN) {
                int size = 1;
 
-               data->callchain = perf_callchain(regs);
+               data->callchain = perf_callchain(event, regs);
 
                if (data->callchain)
                        size += data->callchain->nr;
@@ -5209,7 +5209,8 @@ static int perf_tp_event_match(struct perf_event *event,
 }
 
 void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
-                  struct pt_regs *regs, struct hlist_head *head, int rctx)
+                  struct pt_regs *regs, struct hlist_head *head, int rctx,
+                  struct task_struct *task)
 {
        struct perf_sample_data data;
        struct perf_event *event;
@@ -5228,6 +5229,31 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
                        perf_swevent_event(event, count, &data, regs);
        }
 
+       /*
+        * If we got specified a target task, also iterate its context and
+        * deliver this event there too.
+        */
+       if (task && task != current) {
+               struct perf_event_context *ctx;
+               struct trace_entry *entry = record;
+
+               rcu_read_lock();
+               ctx = rcu_dereference(task->perf_event_ctxp[perf_sw_context]);
+               if (!ctx)
+                       goto unlock;
+
+               list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
+                       if (event->attr.type != PERF_TYPE_TRACEPOINT)
+                               continue;
+                       if (event->attr.config != entry->type)
+                               continue;
+                       if (perf_tp_event_match(event, &data, regs))
+                               perf_swevent_event(event, count, &data, regs);
+               }
+unlock:
+               rcu_read_unlock();
+       }
+
        perf_swevent_put_recursion_context(rctx);
 }
 EXPORT_SYMBOL_GPL(perf_tp_event);
index b0b107f90afc983a0a7abd4b2f0f9519670f2275..a096c19f2c2a1aba50b62df4b91618cdcdb276d9 100644 (file)
@@ -101,7 +101,8 @@ __output_copy(struct perf_output_handle *handle,
 }
 
 /* Callchain handling */
-extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
+extern struct perf_callchain_entry *
+perf_callchain(struct perf_event *event, struct pt_regs *regs);
 extern int get_callchain_buffers(void);
 extern void put_callchain_buffers(void);
 
index e2b0fb9a0b3b3d0d5871ee37bf08618a6bf052e7..3717e7b306e08c0e8c2d3a66219c3cae13176d99 100644 (file)
@@ -2231,11 +2231,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
  * @uaddr2:    the pi futex we will take prior to returning to user-space
  *
  * The caller will wait on uaddr and will be requeued by futex_requeue() to
- * uaddr2 which must be PI aware.  Normal wakeup will wake on uaddr2 and
- * complete the acquisition of the rt_mutex prior to returning to userspace.
- * This ensures the rt_mutex maintains an owner when it has waiters; without
- * one, the pi logic wouldn't know which task to boost/deboost, if there was a
- * need to.
+ * uaddr2 which must be PI aware and unique from uaddr.  Normal wakeup will wake
+ * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to
+ * userspace.  This ensures the rt_mutex maintains an owner when it has waiters;
+ * without one, the pi logic would not know which task to boost/deboost, if
+ * there was a need to.
  *
  * We call schedule in futex_wait_queue_me() when we enqueue and return there
  * via the following:
@@ -2272,6 +2272,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
        struct futex_q q = futex_q_init;
        int res, ret;
 
+       if (uaddr == uaddr2)
+               return -EINVAL;
+
        if (!bitset)
                return -EINVAL;
 
@@ -2343,7 +2346,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                 * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
                 * the pi_state.
                 */
-               WARN_ON(!&q.pi_state);
+               WARN_ON(!q.pi_state);
                pi_mutex = &q.pi_state->pi_mutex;
                ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1);
                debug_rt_mutex_free_waiter(&rt_waiter);
@@ -2370,7 +2373,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
         * fault, unlock the rt_mutex and return the fault to userspace.
         */
        if (ret == -EFAULT) {
-               if (rt_mutex_owner(pi_mutex) == current)
+               if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
                        rt_mutex_unlock(pi_mutex);
        } else if (ret == -EINTR) {
                /*
index 0a8e8f059627dec4ee56bab79849e0f86372d3b5..4c69326aa773f6469b7170d66814d7480ea12ea7 100644 (file)
@@ -943,6 +943,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                goto out_thread;
        }
 
+       /*
+        * Drivers are often written to work w/o knowledge about the
+        * underlying irq chip implementation, so a request for a
+        * threaded irq without a primary hard irq context handler
+        * requires the ONESHOT flag to be set. Some irq chips like
+        * MSI based interrupts are per se one shot safe. Check the
+        * chip flags, so we can avoid the unmask dance at the end of
+        * the threaded handler for those.
+        */
+       if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
+               new->flags &= ~IRQF_ONESHOT;
+
        /*
         * The following block of code has to be executed atomically
         */
@@ -1017,7 +1029,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 */
                new->thread_mask = 1 << ffz(thread_mask);
 
-       } else if (new->handler == irq_default_primary_handler) {
+       } else if (new->handler == irq_default_primary_handler &&
+                  !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
                /*
                 * The interrupt was requested with handler = NULL, so
                 * we use the default primary handler for it. But it
index 1da39ea248fdf3bee6f16f536693b0daad10afbe..c8b7446b27dfc21add10f610e1692a2f3acee7ed 100644 (file)
@@ -178,9 +178,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
        arch_suspend_enable_irqs();
        BUG_ON(irqs_disabled());
 
-       /* Kick the lockup detector */
-       lockup_detector_bootcpu_resume();
-
  Enable_cpus:
        enable_nonboot_cpus();
 
index 6a76ab9d4476466b5ba3b3e37d38aadbb2e02644..66a2ea37b5763b450929a5f955e3bc81ad130a1c 100644 (file)
@@ -1034,6 +1034,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                        struct log *msg = log_from_idx(idx);
 
                        len += msg_print_text(msg, prev, true, NULL, 0);
+                       prev = msg->flags;
                        idx = log_next(idx);
                        seq++;
                }
@@ -1046,6 +1047,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                        struct log *msg = log_from_idx(idx);
 
                        len -= msg_print_text(msg, prev, true, NULL, 0);
+                       prev = msg->flags;
                        idx = log_next(idx);
                        seq++;
                }
index d325c4b2dcbb0c5995a903d76e3035129d1590c3..fbf1fd098dc6cca687f0e9296a931aa0425c6fee 100644 (file)
@@ -3142,6 +3142,20 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 # define nsecs_to_cputime(__nsecs)     nsecs_to_jiffies(__nsecs)
 #endif
 
+static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total)
+{
+       u64 temp = (__force u64) rtime;
+
+       temp *= (__force u64) utime;
+
+       if (sizeof(cputime_t) == 4)
+               temp = div_u64(temp, (__force u32) total);
+       else
+               temp = div64_u64(temp, (__force u64) total);
+
+       return (__force cputime_t) temp;
+}
+
 void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
        cputime_t rtime, utime = p->utime, total = utime + p->stime;
@@ -3151,13 +3165,9 @@ void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
         */
        rtime = nsecs_to_cputime(p->se.sum_exec_runtime);
 
-       if (total) {
-               u64 temp = (__force u64) rtime;
-
-               temp *= (__force u64) utime;
-               do_div(temp, (__force u32) total);
-               utime = (__force cputime_t) temp;
-       } else
+       if (total)
+               utime = scale_utime(utime, rtime, total);
+       else
                utime = rtime;
 
        /*
@@ -3184,13 +3194,9 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
        total = cputime.utime + cputime.stime;
        rtime = nsecs_to_cputime(cputime.sum_exec_runtime);
 
-       if (total) {
-               u64 temp = (__force u64) rtime;
-
-               temp *= (__force u64) cputime.utime;
-               do_div(temp, (__force u32) total);
-               utime = (__force cputime_t) temp;
-       } else
+       if (total)
+               utime = scale_utime(cputime.utime, rtime, total);
+       else
                utime = rtime;
 
        sig->prev_utime = max(sig->prev_utime, utime);
@@ -4340,9 +4346,7 @@ recheck:
         */
        if (unlikely(policy == p->policy && (!rt_policy(policy) ||
                        param->sched_priority == p->rt_priority))) {
-
-               __task_rq_unlock(rq);
-               raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+               task_rq_unlock(rq, p, &flags);
                return 0;
        }
 
@@ -7248,6 +7252,7 @@ int in_sched_functions(unsigned long addr)
 
 #ifdef CONFIG_CGROUP_SCHED
 struct task_group root_task_group;
+LIST_HEAD(task_groups);
 #endif
 
 DECLARE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
index d72586fdf6607db63c5f43a2e1fbbb32ff0ac2c7..23aa789c53ee5c6e061c6bf2b0f8181292695044 100644 (file)
@@ -65,8 +65,8 @@ static int convert_prio(int prio)
 int cpupri_find(struct cpupri *cp, struct task_struct *p,
                struct cpumask *lowest_mask)
 {
-       int                  idx      = 0;
-       int                  task_pri = convert_prio(p->prio);
+       int idx = 0;
+       int task_pri = convert_prio(p->prio);
 
        if (task_pri >= MAX_RT_PRIO)
                return 0;
@@ -137,9 +137,9 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p,
  */
 void cpupri_set(struct cpupri *cp, int cpu, int newpri)
 {
-       int                 *currpri = &cp->cpu_to_pri[cpu];
-       int                  oldpri  = *currpri;
-       int                  do_mb = 0;
+       int *currpri = &cp->cpu_to_pri[cpu];
+       int oldpri = *currpri;
+       int do_mb = 0;
 
        newpri = convert_prio(newpri);
 
index 22321db64952f9461b9e03a3e90bd99217478f8f..c219bf8d704c5460291abee8416264ee32d36e22 100644 (file)
@@ -3069,6 +3069,9 @@ struct lb_env {
        int                     new_dst_cpu;
        enum cpu_idle_type      idle;
        long                    imbalance;
+       /* The set of CPUs under consideration for load-balancing */
+       struct cpumask          *cpus;
+
        unsigned int            flags;
 
        unsigned int            loop;
@@ -3384,6 +3387,14 @@ static int tg_load_down(struct task_group *tg, void *data)
 
 static void update_h_load(long cpu)
 {
+       struct rq *rq = cpu_rq(cpu);
+       unsigned long now = jiffies;
+
+       if (rq->h_load_throttle == now)
+               return;
+
+       rq->h_load_throttle = now;
+
        rcu_read_lock();
        walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
        rcu_read_unlock();
@@ -3653,8 +3664,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
  */
 static inline void update_sg_lb_stats(struct lb_env *env,
                        struct sched_group *group, int load_idx,
-                       int local_group, const struct cpumask *cpus,
-                       int *balance, struct sg_lb_stats *sgs)
+                       int local_group, int *balance, struct sg_lb_stats *sgs)
 {
        unsigned long nr_running, max_nr_running, min_nr_running;
        unsigned long load, max_cpu_load, min_cpu_load;
@@ -3671,7 +3681,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
        max_nr_running = 0;
        min_nr_running = ~0UL;
 
-       for_each_cpu_and(i, sched_group_cpus(group), cpus) {
+       for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
                struct rq *rq = cpu_rq(i);
 
                nr_running = rq->nr_running;
@@ -3800,8 +3810,7 @@ static bool update_sd_pick_busiest(struct lb_env *env,
  * @sds: variable to hold the statistics for this sched_domain.
  */
 static inline void update_sd_lb_stats(struct lb_env *env,
-                                     const struct cpumask *cpus,
-                                     int *balance, struct sd_lb_stats *sds)
+                                       int *balance, struct sd_lb_stats *sds)
 {
        struct sched_domain *child = env->sd->child;
        struct sched_group *sg = env->sd->groups;
@@ -3818,8 +3827,7 @@ static inline void update_sd_lb_stats(struct lb_env *env,
 
                local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
                memset(&sgs, 0, sizeof(sgs));
-               update_sg_lb_stats(env, sg, load_idx, local_group,
-                                  cpus, balance, &sgs);
+               update_sg_lb_stats(env, sg, load_idx, local_group, balance, &sgs);
 
                if (local_group && !(*balance))
                        return;
@@ -4055,7 +4063,6 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
  * to restore balance.
  *
  * @env: The load balancing environment.
- * @cpus: The set of CPUs under consideration for load-balancing.
  * @balance: Pointer to a variable indicating if this_cpu
  *     is the appropriate cpu to perform load balancing at this_level.
  *
@@ -4065,7 +4072,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
  *                put to idle by rebalancing its tasks onto our group.
  */
 static struct sched_group *
-find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance)
+find_busiest_group(struct lb_env *env, int *balance)
 {
        struct sd_lb_stats sds;
 
@@ -4075,7 +4082,7 @@ find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance)
         * Compute the various statistics relavent for load balancing at
         * this level.
         */
-       update_sd_lb_stats(env, cpus, balance, &sds);
+       update_sd_lb_stats(env, balance, &sds);
 
        /*
         * this_cpu is not the appropriate cpu to perform load balancing at
@@ -4155,8 +4162,7 @@ ret:
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
 static struct rq *find_busiest_queue(struct lb_env *env,
-                                    struct sched_group *group,
-                                    const struct cpumask *cpus)
+                                    struct sched_group *group)
 {
        struct rq *busiest = NULL, *rq;
        unsigned long max_load = 0;
@@ -4171,7 +4177,7 @@ static struct rq *find_busiest_queue(struct lb_env *env,
                if (!capacity)
                        capacity = fix_small_capacity(env->sd, group);
 
-               if (!cpumask_test_cpu(i, cpus))
+               if (!cpumask_test_cpu(i, env->cpus))
                        continue;
 
                rq = cpu_rq(i);
@@ -4252,6 +4258,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
                .dst_grpmask    = sched_group_cpus(sd->groups),
                .idle           = idle,
                .loop_break     = sched_nr_migrate_break,
+               .cpus           = cpus,
        };
 
        cpumask_copy(cpus, cpu_active_mask);
@@ -4260,7 +4267,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
        schedstat_inc(sd, lb_count[idle]);
 
 redo:
-       group = find_busiest_group(&env, cpus, balance);
+       group = find_busiest_group(&env, balance);
 
        if (*balance == 0)
                goto out_balanced;
@@ -4270,7 +4277,7 @@ redo:
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(&env, group, cpus);
+       busiest = find_busiest_queue(&env, group);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[idle]);
                goto out_balanced;
@@ -4294,11 +4301,10 @@ redo:
                env.src_rq    = busiest;
                env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
 
+               update_h_load(env.src_cpu);
 more_balance:
                local_irq_save(flags);
                double_rq_lock(this_rq, busiest);
-               if (!env.loop)
-                       update_h_load(env.src_cpu);
 
                /*
                 * cur_ld_moved - load moved in current iteration
index 573e1ca01102066468e65aee96c57ea30cccd6de..944cb68420e957cbde71f9cacaaa4e81c4b1de20 100644 (file)
@@ -788,6 +788,19 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
        const struct cpumask *span;
 
        span = sched_rt_period_mask();
+#ifdef CONFIG_RT_GROUP_SCHED
+       /*
+        * FIXME: isolated CPUs should really leave the root task group,
+        * whether they are isolcpus or were isolated via cpusets, lest
+        * the timer run on a CPU which does not service all runqueues,
+        * potentially leaving other CPUs indefinitely throttled.  If
+        * isolation is really required, the user will turn the throttle
+        * off to kill the perturbations it causes anyway.  Meanwhile,
+        * this maintains functionality for boot and/or troubleshooting.
+        */
+       if (rt_b == &root_task_group.rt_bandwidth)
+               span = cpu_online_mask;
+#endif
        for_each_cpu(i, span) {
                int enqueue = 0;
                struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i);
index c35a1a7dd4d67f4654e1d4dd9236d6c4d910f258..f6714d009e779a225ef295d33ceff7f2f8573be8 100644 (file)
@@ -80,7 +80,7 @@ extern struct mutex sched_domains_mutex;
 struct cfs_rq;
 struct rt_rq;
 
-static LIST_HEAD(task_groups);
+extern struct list_head task_groups;
 
 struct cfs_bandwidth {
 #ifdef CONFIG_CFS_BANDWIDTH
@@ -374,7 +374,11 @@ struct rq {
 #ifdef CONFIG_FAIR_GROUP_SCHED
        /* list of leaf cfs_rq on this cpu: */
        struct list_head leaf_cfs_rq_list;
-#endif
+#ifdef CONFIG_SMP
+       unsigned long h_load_throttle;
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
 #ifdef CONFIG_RT_GROUP_SCHED
        struct list_head leaf_rt_rq_list;
 #endif
index 7b386e86fd2352c1a0fef2be23672a9c8ef194db..da5eb5bed84a2ca8db2443ccb71817d48f06c1f5 100644 (file)
@@ -27,8 +27,10 @@ static struct task_struct *pick_next_task_stop(struct rq *rq)
 {
        struct task_struct *stop = rq->stop;
 
-       if (stop && stop->on_rq)
+       if (stop && stop->on_rq) {
+               stop->se.exec_start = rq->clock_task;
                return stop;
+       }
 
        return NULL;
 }
@@ -52,6 +54,21 @@ static void yield_task_stop(struct rq *rq)
 
 static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
 {
+       struct task_struct *curr = rq->curr;
+       u64 delta_exec;
+
+       delta_exec = rq->clock_task - curr->se.exec_start;
+       if (unlikely((s64)delta_exec < 0))
+               delta_exec = 0;
+
+       schedstat_set(curr->se.statistics.exec_max,
+                       max(curr->se.statistics.exec_max, delta_exec));
+
+       curr->se.sum_exec_runtime += delta_exec;
+       account_group_exec_runtime(curr, delta_exec);
+
+       curr->se.exec_start = rq->clock_task;
+       cpuacct_charge(curr, delta_exec);
 }
 
 static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
@@ -60,6 +77,9 @@ static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
 
 static void set_curr_task_stop(struct rq *rq)
 {
+       struct task_struct *stop = rq->stop;
+
+       stop->se.exec_start = rq->clock_task;
 }
 
 static void switched_to_stop(struct rq *rq, struct task_struct *p)
index 91d4e1742a0c4ec1cd8805b6663f5a95b5d42b3b..d320d44903bd0ab8ce3a1dc3e40dee28a26e714f 100644 (file)
@@ -75,6 +75,7 @@ void task_work_run(void)
                        p = q->next;
                        q->func(q);
                        q = p;
+                       cond_resched();
                }
        }
 }
index a470154e040826f9549e5faf9ed4aefd174de698..46da0537c10b4d78e3c5645d8b709bb3503cc2af 100644 (file)
@@ -37,7 +37,7 @@
  * requested HZ value. It is also not recommended
  * for "tick-less" systems.
  */
-#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ))
+#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/SHIFTED_HZ))
 
 /* Since jiffies uses a simple NSEC_PER_JIFFY multiplier
  * conversion, the .shift value could be zero. However
index b7fbadc5c973c928e531cf6d701f1520e4809812..24174b4d669b1280c632d4ed0126dc2f1bb297ef 100644 (file)
@@ -28,7 +28,7 @@ DEFINE_SPINLOCK(ntp_lock);
 /* USER_HZ period (usecs): */
 unsigned long                  tick_usec = TICK_USEC;
 
-/* ACTHZ period (nsecs): */
+/* SHIFTED_HZ period (nsecs): */
 unsigned long                  tick_nsec;
 
 static u64                     tick_length;
index f045cc50832d0fc8aee045755d3ba60d655f2647..e16af197a2bc54c8f81070a1043ed1f81923679f 100644 (file)
@@ -65,14 +65,14 @@ struct timekeeper {
         * used instead.
         */
        struct timespec         wall_to_monotonic;
-       /* time spent in suspend */
-       struct timespec         total_sleep_time;
-       /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
-       struct timespec         raw_time;
        /* Offset clock monotonic -> clock realtime */
        ktime_t                 offs_real;
+       /* time spent in suspend */
+       struct timespec         total_sleep_time;
        /* Offset clock monotonic -> clock boottime */
        ktime_t                 offs_boot;
+       /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
+       struct timespec         raw_time;
        /* Seqlock for all timekeeper values */
        seqlock_t               lock;
 };
@@ -108,13 +108,38 @@ static struct timespec tk_xtime(struct timekeeper *tk)
 static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts)
 {
        tk->xtime_sec = ts->tv_sec;
-       tk->xtime_nsec = ts->tv_nsec << tk->shift;
+       tk->xtime_nsec = (u64)ts->tv_nsec << tk->shift;
 }
 
 static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts)
 {
        tk->xtime_sec += ts->tv_sec;
-       tk->xtime_nsec += ts->tv_nsec << tk->shift;
+       tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift;
+}
+
+static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)
+{
+       struct timespec tmp;
+
+       /*
+        * Verify consistency of: offset_real = -wall_to_monotonic
+        * before modifying anything
+        */
+       set_normalized_timespec(&tmp, -tk->wall_to_monotonic.tv_sec,
+                                       -tk->wall_to_monotonic.tv_nsec);
+       WARN_ON_ONCE(tk->offs_real.tv64 != timespec_to_ktime(tmp).tv64);
+       tk->wall_to_monotonic = wtm;
+       set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec);
+       tk->offs_real = timespec_to_ktime(tmp);
+}
+
+static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t)
+{
+       /* Verify consistency before modifying */
+       WARN_ON_ONCE(tk->offs_boot.tv64 != timespec_to_ktime(tk->total_sleep_time).tv64);
+
+       tk->total_sleep_time    = t;
+       tk->offs_boot           = timespec_to_ktime(t);
 }
 
 /**
@@ -217,14 +242,6 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
        return nsec + arch_gettimeoffset();
 }
 
-static void update_rt_offset(struct timekeeper *tk)
-{
-       struct timespec tmp, *wtm = &tk->wall_to_monotonic;
-
-       set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec);
-       tk->offs_real = timespec_to_ktime(tmp);
-}
-
 /* must hold write on timekeeper.lock */
 static void timekeeping_update(struct timekeeper *tk, bool clearntp)
 {
@@ -234,12 +251,10 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)
                tk->ntp_error = 0;
                ntp_clear();
        }
-       update_rt_offset(tk);
        xt = tk_xtime(tk);
        update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult);
 }
 
-
 /**
  * timekeeping_forward_now - update clock to the current time
  *
@@ -277,18 +292,19 @@ static void timekeeping_forward_now(struct timekeeper *tk)
  */
 void getnstimeofday(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs = 0;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               ts->tv_sec = timekeeper.xtime_sec;
-               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
+               ts->tv_sec = tk->xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(tk);
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        timespec_add_ns(ts, nsecs);
 }
@@ -296,19 +312,18 @@ EXPORT_SYMBOL(getnstimeofday);
 
 ktime_t ktime_get(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned int seq;
        s64 secs, nsecs;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               secs = timekeeper.xtime_sec +
-                               timekeeper.wall_to_monotonic.tv_sec;
-               nsecs = timekeeping_get_ns(&timekeeper) +
-                               timekeeper.wall_to_monotonic.tv_nsec;
+               seq = read_seqbegin(&tk->lock);
+               secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
+               nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
        /*
         * Use ktime_set/ktime_add_ns to create a proper ktime on
         * 32-bit architectures without CONFIG_KTIME_SCALAR.
@@ -327,18 +342,19 @@ EXPORT_SYMBOL_GPL(ktime_get);
  */
 void ktime_get_ts(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec tomono;
        unsigned int seq;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               ts->tv_sec = timekeeper.xtime_sec;
-               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
-               tomono = timekeeper.wall_to_monotonic;
+               seq = read_seqbegin(&tk->lock);
+               ts->tv_sec = tk->xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(tk);
+               tomono = tk->wall_to_monotonic;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
                                ts->tv_nsec + tomono.tv_nsec);
@@ -358,22 +374,23 @@ EXPORT_SYMBOL_GPL(ktime_get_ts);
  */
 void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs_raw, nsecs_real;
 
        WARN_ON_ONCE(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               *ts_raw = timekeeper.raw_time;
-               ts_real->tv_sec = timekeeper.xtime_sec;
+               *ts_raw = tk->raw_time;
+               ts_real->tv_sec = tk->xtime_sec;
                ts_real->tv_nsec = 0;
 
-               nsecs_raw = timekeeping_get_ns_raw(&timekeeper);
-               nsecs_real = timekeeping_get_ns(&timekeeper);
+               nsecs_raw = timekeeping_get_ns_raw(tk);
+               nsecs_real = timekeeping_get_ns(tk);
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        timespec_add_ns(ts_raw, nsecs_raw);
        timespec_add_ns(ts_real, nsecs_real);
@@ -406,28 +423,28 @@ EXPORT_SYMBOL(do_gettimeofday);
  */
 int do_settimeofday(const struct timespec *tv)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec ts_delta, xt;
        unsigned long flags;
 
        if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
 
-       xt = tk_xtime(&timekeeper);
+       xt = tk_xtime(tk);
        ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
        ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
 
-       timekeeper.wall_to_monotonic =
-                       timespec_sub(timekeeper.wall_to_monotonic, ts_delta);
+       tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, ts_delta));
 
-       tk_set_xtime(&timekeeper, tv);
+       tk_set_xtime(tk, tv);
 
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
@@ -436,7 +453,6 @@ int do_settimeofday(const struct timespec *tv)
 }
 EXPORT_SYMBOL(do_settimeofday);
 
-
 /**
  * timekeeping_inject_offset - Adds or subtracts from the current time.
  * @tv:                pointer to the timespec variable containing the offset
@@ -445,23 +461,23 @@ EXPORT_SYMBOL(do_settimeofday);
  */
 int timekeeping_inject_offset(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
 
        if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
 
 
-       tk_xtime_add(&timekeeper, ts);
-       timekeeper.wall_to_monotonic =
-                               timespec_sub(timekeeper.wall_to_monotonic, *ts);
+       tk_xtime_add(tk, ts);
+       tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
 
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
@@ -477,23 +493,24 @@ EXPORT_SYMBOL(timekeeping_inject_offset);
  */
 static int change_clocksource(void *data)
 {
+       struct timekeeper *tk = &timekeeper;
        struct clocksource *new, *old;
        unsigned long flags;
 
        new = (struct clocksource *) data;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
        if (!new->enable || new->enable(new) == 0) {
-               old = timekeeper.clock;
-               tk_setup_internals(&timekeeper, new);
+               old = tk->clock;
+               tk_setup_internals(tk, new);
                if (old->disable)
                        old->disable(old);
        }
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        return 0;
 }
@@ -507,7 +524,9 @@ static int change_clocksource(void *data)
  */
 void timekeeping_notify(struct clocksource *clock)
 {
-       if (timekeeper.clock == clock)
+       struct timekeeper *tk = &timekeeper;
+
+       if (tk->clock == clock)
                return;
        stop_machine(change_clocksource, clock, NULL);
        tick_clock_notify();
@@ -536,35 +555,36 @@ EXPORT_SYMBOL_GPL(ktime_get_real);
  */
 void getrawmonotonic(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               nsecs = timekeeping_get_ns_raw(&timekeeper);
-               *ts = timekeeper.raw_time;
+               seq = read_seqbegin(&tk->lock);
+               nsecs = timekeeping_get_ns_raw(tk);
+               *ts = tk->raw_time;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        timespec_add_ns(ts, nsecs);
 }
 EXPORT_SYMBOL(getrawmonotonic);
 
-
 /**
  * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
  */
 int timekeeping_valid_for_hres(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        int ret;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               ret = timekeeper.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
+               ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        return ret;
 }
@@ -574,15 +594,16 @@ int timekeeping_valid_for_hres(void)
  */
 u64 timekeeping_max_deferment(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        u64 ret;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               ret = timekeeper.clock->max_idle_ns;
+               ret = tk->clock->max_idle_ns;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        return ret;
 }
@@ -622,46 +643,43 @@ void __attribute__((weak)) read_boot_clock(struct timespec *ts)
  */
 void __init timekeeping_init(void)
 {
+       struct timekeeper *tk = &timekeeper;
        struct clocksource *clock;
        unsigned long flags;
-       struct timespec now, boot;
+       struct timespec now, boot, tmp;
 
        read_persistent_clock(&now);
        read_boot_clock(&boot);
 
-       seqlock_init(&timekeeper.lock);
+       seqlock_init(&tk->lock);
 
        ntp_init();
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
        clock = clocksource_default_clock();
        if (clock->enable)
                clock->enable(clock);
-       tk_setup_internals(&timekeeper, clock);
+       tk_setup_internals(tk, clock);
 
-       tk_set_xtime(&timekeeper, &now);
-       timekeeper.raw_time.tv_sec = 0;
-       timekeeper.raw_time.tv_nsec = 0;
+       tk_set_xtime(tk, &now);
+       tk->raw_time.tv_sec = 0;
+       tk->raw_time.tv_nsec = 0;
        if (boot.tv_sec == 0 && boot.tv_nsec == 0)
-               boot = tk_xtime(&timekeeper);
-
-       set_normalized_timespec(&timekeeper.wall_to_monotonic,
-                               -boot.tv_sec, -boot.tv_nsec);
-       update_rt_offset(&timekeeper);
-       timekeeper.total_sleep_time.tv_sec = 0;
-       timekeeper.total_sleep_time.tv_nsec = 0;
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+               boot = tk_xtime(tk);
+
+       set_normalized_timespec(&tmp, -boot.tv_sec, -boot.tv_nsec);
+       tk_set_wall_to_mono(tk, tmp);
+
+       tmp.tv_sec = 0;
+       tmp.tv_nsec = 0;
+       tk_set_sleep_time(tk, tmp);
+
+       write_sequnlock_irqrestore(&tk->lock, flags);
 }
 
 /* time in seconds when suspend began */
 static struct timespec timekeeping_suspend_time;
 
-static void update_sleep_time(struct timespec t)
-{
-       timekeeper.total_sleep_time = t;
-       timekeeper.offs_boot = timespec_to_ktime(t);
-}
-
 /**
  * __timekeeping_inject_sleeptime - Internal function to add sleep interval
  * @delta: pointer to a timespec delta value
@@ -677,13 +695,11 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
                                        "sleep delta value!\n");
                return;
        }
-
        tk_xtime_add(tk, delta);
-       tk->wall_to_monotonic = timespec_sub(tk->wall_to_monotonic, *delta);
-       update_sleep_time(timespec_add(tk->total_sleep_time, *delta));
+       tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta));
+       tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta));
 }
 
-
 /**
  * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values
  * @delta: pointer to a timespec delta value
@@ -696,6 +712,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
  */
 void timekeeping_inject_sleeptime(struct timespec *delta)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
        struct timespec ts;
 
@@ -704,21 +721,20 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
        if (!(ts.tv_sec == 0 && ts.tv_nsec == 0))
                return;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
 
-       __timekeeping_inject_sleeptime(&timekeeper, delta);
+       __timekeeping_inject_sleeptime(tk, delta);
 
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
 }
 
-
 /**
  * timekeeping_resume - Resumes the generic timekeeping subsystem.
  *
@@ -728,6 +744,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
  */
 static void timekeeping_resume(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
        struct timespec ts;
 
@@ -735,18 +752,18 @@ static void timekeeping_resume(void)
 
        clocksource_resume();
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
        if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
                ts = timespec_sub(ts, timekeeping_suspend_time);
-               __timekeeping_inject_sleeptime(&timekeeper, &ts);
+               __timekeeping_inject_sleeptime(tk, &ts);
        }
        /* re-base the last cycle value */
-       timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
-       timekeeper.ntp_error = 0;
+       tk->clock->cycle_last = tk->clock->read(tk->clock);
+       tk->ntp_error = 0;
        timekeeping_suspended = 0;
-       timekeeping_update(&timekeeper, false);
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       timekeeping_update(tk, false);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        touch_softlockup_watchdog();
 
@@ -758,14 +775,15 @@ static void timekeeping_resume(void)
 
 static int timekeeping_suspend(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
        struct timespec         delta, delta_delta;
        static struct timespec  old_delta;
 
        read_persistent_clock(&timekeeping_suspend_time);
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
-       timekeeping_forward_now(&timekeeper);
+       write_seqlock_irqsave(&tk->lock, flags);
+       timekeeping_forward_now(tk);
        timekeeping_suspended = 1;
 
        /*
@@ -774,7 +792,7 @@ static int timekeeping_suspend(void)
         * try to compensate so the difference in system time
         * and persistent_clock time stays close to constant.
         */
-       delta = timespec_sub(tk_xtime(&timekeeper), timekeeping_suspend_time);
+       delta = timespec_sub(tk_xtime(tk), timekeeping_suspend_time);
        delta_delta = timespec_sub(delta, old_delta);
        if (abs(delta_delta.tv_sec)  >= 2) {
                /*
@@ -787,7 +805,7 @@ static int timekeeping_suspend(void)
                timekeeping_suspend_time =
                        timespec_add(timekeeping_suspend_time, delta_delta);
        }
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
        clocksource_suspend();
@@ -898,27 +916,29 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
                 * the error. This causes the likely below to be unlikely.
                 *
                 * The proper fix is to avoid rounding up by using
-                * the high precision timekeeper.xtime_nsec instead of
+                * the high precision tk->xtime_nsec instead of
                 * xtime.tv_nsec everywhere. Fixing this will take some
                 * time.
                 */
                if (likely(error <= interval))
                        adj = 1;
                else
-                       adj = timekeeping_bigadjust(tk, error, &interval,
-                                                       &offset);
-       } else if (error < -interval) {
-               /* See comment above, this is just switched for the negative */
-               error >>= 2;
-               if (likely(error >= -interval)) {
-                       adj = -1;
-                       interval = -interval;
-                       offset = -offset;
-               } else
-                       adj = timekeeping_bigadjust(tk, error, &interval,
-                                                       &offset);
-       } else
-               return;
+                       adj = timekeeping_bigadjust(tk, error, &interval, &offset);
+       } else {
+               if (error < -interval) {
+                       /* See comment above, this is just switched for the negative */
+                       error >>= 2;
+                       if (likely(error >= -interval)) {
+                               adj = -1;
+                               interval = -interval;
+                               offset = -offset;
+                       } else {
+                               adj = timekeeping_bigadjust(tk, error, &interval, &offset);
+                       }
+               } else {
+                       goto out_adjust;
+               }
+       }
 
        if (unlikely(tk->clock->maxadj &&
                (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) {
@@ -981,6 +1001,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
        tk->xtime_nsec -= offset;
        tk->ntp_error -= (interval - offset) << tk->ntp_error_shift;
 
+out_adjust:
        /*
         * It may be possible that when we entered this function, xtime_nsec
         * was very small.  Further, if we're slightly speeding the clocksource
@@ -1003,7 +1024,6 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
 
 }
 
-
 /**
  * accumulate_nsecs_to_secs - Accumulates nsecs into secs
  *
@@ -1024,15 +1044,21 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
 
                /* Figure out if its a leap sec and apply if needed */
                leap = second_overflow(tk->xtime_sec);
-               tk->xtime_sec += leap;
-               tk->wall_to_monotonic.tv_sec -= leap;
-               if (leap)
-                       clock_was_set_delayed();
+               if (unlikely(leap)) {
+                       struct timespec ts;
+
+                       tk->xtime_sec += leap;
+
+                       ts.tv_sec = leap;
+                       ts.tv_nsec = 0;
+                       tk_set_wall_to_mono(tk,
+                               timespec_sub(tk->wall_to_monotonic, ts));
 
+                       clock_was_set_delayed();
+               }
        }
 }
 
-
 /**
  * logarithmic_accumulation - shifted accumulation of cycles
  *
@@ -1076,7 +1102,6 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
        return offset;
 }
 
-
 /**
  * update_wall_time - Uses the current clocksource to increment the wall time
  *
@@ -1084,21 +1109,22 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
 static void update_wall_time(void)
 {
        struct clocksource *clock;
+       struct timekeeper *tk = &timekeeper;
        cycle_t offset;
        int shift = 0, maxshift;
        unsigned long flags;
        s64 remainder;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
        /* Make sure we're fully resumed: */
        if (unlikely(timekeeping_suspended))
                goto out;
 
-       clock = timekeeper.clock;
+       clock = tk->clock;
 
 #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
-       offset = timekeeper.cycle_interval;
+       offset = tk->cycle_interval;
 #else
        offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
 #endif
@@ -1111,19 +1137,19 @@ static void update_wall_time(void)
         * chunk in one go, and then try to consume the next smaller
         * doubled multiple.
         */
-       shift = ilog2(offset) - ilog2(timekeeper.cycle_interval);
+       shift = ilog2(offset) - ilog2(tk->cycle_interval);
        shift = max(0, shift);
        /* Bound shift to one less than what overflows tick_length */
        maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
        shift = min(shift, maxshift);
-       while (offset >= timekeeper.cycle_interval) {
-               offset = logarithmic_accumulation(&timekeeper, offset, shift);
-               if(offset < timekeeper.cycle_interval<<shift)
+       while (offset >= tk->cycle_interval) {
+               offset = logarithmic_accumulation(tk, offset, shift);
+               if (offset < tk->cycle_interval<<shift)
                        shift--;
        }
 
        /* correct the clock when NTP error is too big */
-       timekeeping_adjust(&timekeeper, offset);
+       timekeeping_adjust(tk, offset);
 
 
        /*
@@ -1135,21 +1161,21 @@ static void update_wall_time(void)
        * the vsyscall implementations are converted to use xtime_nsec
        * (shifted nanoseconds), this can be killed.
        */
-       remainder = timekeeper.xtime_nsec & ((1 << timekeeper.shift) - 1);
-       timekeeper.xtime_nsec -= remainder;
-       timekeeper.xtime_nsec += 1 << timekeeper.shift;
-       timekeeper.ntp_error += remainder << timekeeper.ntp_error_shift;
+       remainder = tk->xtime_nsec & ((1 << tk->shift) - 1);
+       tk->xtime_nsec -= remainder;
+       tk->xtime_nsec += 1 << tk->shift;
+       tk->ntp_error += remainder << tk->ntp_error_shift;
 
        /*
         * Finally, make sure that after the rounding
         * xtime_nsec isn't larger than NSEC_PER_SEC
         */
-       accumulate_nsecs_to_secs(&timekeeper);
+       accumulate_nsecs_to_secs(tk);
 
-       timekeeping_update(&timekeeper, false);
+       timekeeping_update(tk, false);
 
 out:
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
 }
 
@@ -1166,18 +1192,18 @@ out:
  */
 void getboottime(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec boottime = {
-               .tv_sec = timekeeper.wall_to_monotonic.tv_sec +
-                               timekeeper.total_sleep_time.tv_sec,
-               .tv_nsec = timekeeper.wall_to_monotonic.tv_nsec +
-                               timekeeper.total_sleep_time.tv_nsec
+               .tv_sec = tk->wall_to_monotonic.tv_sec +
+                               tk->total_sleep_time.tv_sec,
+               .tv_nsec = tk->wall_to_monotonic.tv_nsec +
+                               tk->total_sleep_time.tv_nsec
        };
 
        set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(getboottime);
 
-
 /**
  * get_monotonic_boottime - Returns monotonic time since boot
  * @ts:                pointer to the timespec to be set
@@ -1189,19 +1215,20 @@ EXPORT_SYMBOL_GPL(getboottime);
  */
 void get_monotonic_boottime(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec tomono, sleep;
        unsigned int seq;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               ts->tv_sec = timekeeper.xtime_sec;
-               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
-               tomono = timekeeper.wall_to_monotonic;
-               sleep = timekeeper.total_sleep_time;
+               seq = read_seqbegin(&tk->lock);
+               ts->tv_sec = tk->xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(tk);
+               tomono = tk->wall_to_monotonic;
+               sleep = tk->total_sleep_time;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
                        ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec);
@@ -1231,31 +1258,38 @@ EXPORT_SYMBOL_GPL(ktime_get_boottime);
  */
 void monotonic_to_bootbased(struct timespec *ts)
 {
-       *ts = timespec_add(*ts, timekeeper.total_sleep_time);
+       struct timekeeper *tk = &timekeeper;
+
+       *ts = timespec_add(*ts, tk->total_sleep_time);
 }
 EXPORT_SYMBOL_GPL(monotonic_to_bootbased);
 
 unsigned long get_seconds(void)
 {
-       return timekeeper.xtime_sec;
+       struct timekeeper *tk = &timekeeper;
+
+       return tk->xtime_sec;
 }
 EXPORT_SYMBOL(get_seconds);
 
 struct timespec __current_kernel_time(void)
 {
-       return tk_xtime(&timekeeper);
+       struct timekeeper *tk = &timekeeper;
+
+       return tk_xtime(tk);
 }
 
 struct timespec current_kernel_time(void)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec now;
        unsigned long seq;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               now = tk_xtime(&timekeeper);
-       } while (read_seqretry(&timekeeper.lock, seq));
+               now = tk_xtime(tk);
+       } while (read_seqretry(&tk->lock, seq));
 
        return now;
 }
@@ -1263,15 +1297,16 @@ EXPORT_SYMBOL(current_kernel_time);
 
 struct timespec get_monotonic_coarse(void)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec now, mono;
        unsigned long seq;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               now = tk_xtime(&timekeeper);
-               mono = timekeeper.wall_to_monotonic;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               now = tk_xtime(tk);
+               mono = tk->wall_to_monotonic;
+       } while (read_seqretry(&tk->lock, seq));
 
        set_normalized_timespec(&now, now.tv_sec + mono.tv_sec,
                                now.tv_nsec + mono.tv_nsec);
@@ -1300,14 +1335,15 @@ void do_timer(unsigned long ticks)
 void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
                                struct timespec *wtom, struct timespec *sleep)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               *xtim = tk_xtime(&timekeeper);
-               *wtom = timekeeper.wall_to_monotonic;
-               *sleep = timekeeper.total_sleep_time;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               seq = read_seqbegin(&tk->lock);
+               *xtim = tk_xtime(tk);
+               *wtom = tk->wall_to_monotonic;
+               *sleep = tk->total_sleep_time;
+       } while (read_seqretry(&tk->lock, seq));
 }
 
 #ifdef CONFIG_HIGH_RES_TIMERS
@@ -1321,19 +1357,20 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
  */
 ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
 {
+       struct timekeeper *tk = &timekeeper;
        ktime_t now;
        unsigned int seq;
        u64 secs, nsecs;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               secs = timekeeper.xtime_sec;
-               nsecs = timekeeping_get_ns(&timekeeper);
+               secs = tk->xtime_sec;
+               nsecs = timekeeping_get_ns(tk);
 
-               *offs_real = timekeeper.offs_real;
-               *offs_boot = timekeeper.offs_boot;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               *offs_real = tk->offs_real;
+               *offs_boot = tk->offs_boot;
+       } while (read_seqretry(&tk->lock, seq));
 
        now = ktime_add_ns(ktime_set(secs, 0), nsecs);
        now = ktime_sub(now, *offs_real);
@@ -1346,19 +1383,19 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
  */
 ktime_t ktime_get_monotonic_offset(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        struct timespec wtom;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               wtom = timekeeper.wall_to_monotonic;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               seq = read_seqbegin(&tk->lock);
+               wtom = tk->wall_to_monotonic;
+       } while (read_seqretry(&tk->lock, seq));
 
        return timespec_to_ktime(wtom);
 }
 EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
 
-
 /**
  * xtime_update() - advances the timekeeping infrastructure
  * @ticks:     number of ticks, that have elapsed since the last call.
index a61c09374ebab1fdba0bdd370b56cf70018de62d..8c5e7b908c6814ed5342e63c65b69d4acb9ea037 100644 (file)
@@ -1407,13 +1407,6 @@ SYSCALL_DEFINE1(alarm, unsigned int, seconds)
 
 #endif
 
-#ifndef __alpha__
-
-/*
- * The Alpha uses getxpid, getxuid, and getxgid instead.  Maybe this
- * should be moved into arch/i386 instead?
- */
-
 /**
  * sys_getpid - return the thread group id of the current process
  *
@@ -1469,8 +1462,6 @@ SYSCALL_DEFINE0(getegid)
        return from_kgid_munged(current_user_ns(), current_egid());
 }
 
-#endif
-
 static void process_timeout(unsigned long __data)
 {
        wake_up_process((struct task_struct *)__data);
index fee3752ae8f66f5348199c67b6ad05c5a41346f5..8a6d2ee2086c2cd721dc29ae92d23082370e10db 100644 (file)
@@ -281,7 +281,7 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip)
 
        head = this_cpu_ptr(event_function.perf_events);
        perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0,
-                             1, &regs, head);
+                             1, &regs, head, NULL);
 
 #undef ENTRY_SIZE
 }
index b31d3d5699fea09c235ace4c47e16fc8fb8785e0..1a2117043bb140d06b366d8d6e0798bb69fcad26 100644 (file)
@@ -1002,7 +1002,8 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
        store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
 
        head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
+       perf_trace_buf_submit(entry, size, rctx,
+                                       entry->ip, 1, regs, head, NULL);
 }
 
 /* Kretprobe profile handler */
@@ -1033,7 +1034,8 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
        store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
 
        head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head);
+       perf_trace_buf_submit(entry, size, rctx,
+                                       entry->ret_ip, 1, regs, head, NULL);
 }
 #endif /* CONFIG_PERF_EVENTS */
 
index 96fc733690992bf97dc610c87ff2a6b0ecbb97d8..60e4d78756723189b95d11390bc566a6578a4bbe 100644 (file)
@@ -532,7 +532,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
                               (unsigned long *)&rec->args);
 
        head = this_cpu_ptr(sys_data->enter_event->perf_events);
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
 }
 
 int perf_sysenter_enable(struct ftrace_event_call *call)
@@ -608,7 +608,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
        rec->ret = syscall_get_return_value(current, regs);
 
        head = this_cpu_ptr(sys_data->exit_event->perf_events);
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
 }
 
 int perf_sysexit_enable(struct ftrace_event_call *call)
index 2b36ac68549e2e23d148c81b7905407d344fdc80..03003cd7dd962d1ca31b2574f9d09f77a74f47a4 100644 (file)
@@ -670,7 +670,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
                call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
 
        head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
+       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head, NULL);
 
  out:
        preempt_enable();
index 69add8a9da686a326be90e45aa09ab8427a24875..4b1dfba70f7cf8ae7397623656a9b695028f702a 100644 (file)
@@ -575,7 +575,7 @@ out:
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  */
-static int
+static int __cpuinit
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
@@ -610,27 +610,10 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpu_nfb = {
+static struct notifier_block __cpuinitdata cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
-#ifdef CONFIG_SUSPEND
-/*
- * On exit from suspend we force an offline->online transition on the boot CPU
- * so that the PMU state that was lost while in suspended state gets set up
- * properly for the boot CPU.  This information is required for restarting the
- * NMI watchdog.
- */
-void lockup_detector_bootcpu_resume(void)
-{
-       void *cpu = (void *)(long)smp_processor_id();
-
-       cpu_callback(&cpu_nfb, CPU_DEAD_FROZEN, cpu);
-       cpu_callback(&cpu_nfb, CPU_UP_PREPARE_FROZEN, cpu);
-       cpu_callback(&cpu_nfb, CPU_ONLINE_FROZEN, cpu);
-}
-#endif
-
 void __init lockup_detector_init(void)
 {
        void *cpu = (void *)(long)smp_processor_id();
index 55efaf7423462d9d116aad5e3383e83e0952967e..40d304efe27281151124a874cdbac864f997a7ee 100644 (file)
--- a/lib/bcd.c
+++ b/lib/bcd.c
@@ -1,14 +1,14 @@
 #include <linux/bcd.h>
 #include <linux/export.h>
 
-unsigned bcd2bin(unsigned char val)
+unsigned _bcd2bin(unsigned char val)
 {
        return (val & 0x0f) + (val >> 4) * 10;
 }
-EXPORT_SYMBOL(bcd2bin);
+EXPORT_SYMBOL(_bcd2bin);
 
-unsigned char bin2bcd(unsigned val)
+unsigned char _bin2bcd(unsigned val)
 {
        return ((val / 10) << 4) + val % 10;
 }
-EXPORT_SYMBOL(bin2bcd);
+EXPORT_SYMBOL(_bin2bcd);
index 6b4718e2ee341d7fd7f068d83e31da014d1a5ef0..b41823cc05e61caf4b862418fde58a5025bfb748 100644 (file)
@@ -39,12 +39,6 @@ DEFINE_SPINLOCK(bdi_lock);
 LIST_HEAD(bdi_list);
 LIST_HEAD(bdi_pending_list);
 
-static struct task_struct *sync_supers_tsk;
-static struct timer_list sync_supers_timer;
-
-static int bdi_sync_supers(void *);
-static void sync_supers_timer_fn(unsigned long);
-
 void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2)
 {
        if (wb1 < wb2) {
@@ -250,12 +244,6 @@ static int __init default_bdi_init(void)
 {
        int err;
 
-       sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
-       BUG_ON(IS_ERR(sync_supers_tsk));
-
-       setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
-       bdi_arm_supers_timer();
-
        err = bdi_init(&default_backing_dev_info);
        if (!err)
                bdi_register(&default_backing_dev_info, NULL, "default");
@@ -270,46 +258,6 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi)
        return wb_has_dirty_io(&bdi->wb);
 }
 
-/*
- * kupdated() used to do this. We cannot do it from the bdi_forker_thread()
- * or we risk deadlocking on ->s_umount. The longer term solution would be
- * to implement sync_supers_bdi() or similar and simply do it from the
- * bdi writeback thread individually.
- */
-static int bdi_sync_supers(void *unused)
-{
-       set_user_nice(current, 0);
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-
-               /*
-                * Do this periodically, like kupdated() did before.
-                */
-               sync_supers();
-       }
-
-       return 0;
-}
-
-void bdi_arm_supers_timer(void)
-{
-       unsigned long next;
-
-       if (!dirty_writeback_interval)
-               return;
-
-       next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies;
-       mod_timer(&sync_supers_timer, round_jiffies_up(next));
-}
-
-static void sync_supers_timer_fn(unsigned long unused)
-{
-       wake_up_process(sync_supers_tsk);
-       bdi_arm_supers_timer();
-}
-
 static void wakeup_timer_fn(unsigned long data)
 {
        struct backing_dev_info *bdi = (struct backing_dev_info *)data;
index e78cb968842163ff65154346e6721aac91070319..7fcd3a52e68d4b2a9bfc07c1056b7db3a2b154b1 100644 (file)
@@ -50,6 +50,47 @@ static inline bool migrate_async_suitable(int migratetype)
        return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE;
 }
 
+/*
+ * Compaction requires the taking of some coarse locks that are potentially
+ * very heavily contended. Check if the process needs to be scheduled or
+ * if the lock is contended. For async compaction, back out in the event
+ * if contention is severe. For sync compaction, schedule.
+ *
+ * Returns true if the lock is held.
+ * Returns false if the lock is released and compaction should abort
+ */
+static bool compact_checklock_irqsave(spinlock_t *lock, unsigned long *flags,
+                                     bool locked, struct compact_control *cc)
+{
+       if (need_resched() || spin_is_contended(lock)) {
+               if (locked) {
+                       spin_unlock_irqrestore(lock, *flags);
+                       locked = false;
+               }
+
+               /* async aborts if taking too long or contended */
+               if (!cc->sync) {
+                       if (cc->contended)
+                               *cc->contended = true;
+                       return false;
+               }
+
+               cond_resched();
+               if (fatal_signal_pending(current))
+                       return false;
+       }
+
+       if (!locked)
+               spin_lock_irqsave(lock, *flags);
+       return true;
+}
+
+static inline bool compact_trylock_irqsave(spinlock_t *lock,
+                       unsigned long *flags, struct compact_control *cc)
+{
+       return compact_checklock_irqsave(lock, flags, false, cc);
+}
+
 /*
  * Isolate free pages onto a private freelist. Caller must hold zone->lock.
  * If @strict is true, will abort returning 0 on any invalid PFNs or non-free
@@ -173,7 +214,7 @@ isolate_freepages_range(unsigned long start_pfn, unsigned long end_pfn)
 }
 
 /* Update the number of anon and file isolated pages in the zone */
-static void acct_isolated(struct zone *zone, struct compact_control *cc)
+static void acct_isolated(struct zone *zone, bool locked, struct compact_control *cc)
 {
        struct page *page;
        unsigned int count[2] = { 0, };
@@ -181,8 +222,14 @@ static void acct_isolated(struct zone *zone, struct compact_control *cc)
        list_for_each_entry(page, &cc->migratepages, lru)
                count[!!page_is_file_cache(page)]++;
 
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
-       __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+       /* If locked we can use the interrupt unsafe versions */
+       if (locked) {
+               __mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+               __mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+       } else {
+               mod_zone_page_state(zone, NR_ISOLATED_ANON, count[0]);
+               mod_zone_page_state(zone, NR_ISOLATED_FILE, count[1]);
+       }
 }
 
 /* Similar to reclaim, but different enough that they don't share logic */
@@ -228,6 +275,8 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
        struct list_head *migratelist = &cc->migratepages;
        isolate_mode_t mode = 0;
        struct lruvec *lruvec;
+       unsigned long flags;
+       bool locked;
 
        /*
         * Ensure that there are not too many pages isolated from the LRU
@@ -247,25 +296,22 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 
        /* Time to isolate some pages for migration */
        cond_resched();
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irqsave(&zone->lru_lock, flags);
+       locked = true;
        for (; low_pfn < end_pfn; low_pfn++) {
                struct page *page;
-               bool locked = true;
 
                /* give a chance to irqs before checking need_resched() */
                if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) {
-                       spin_unlock_irq(&zone->lru_lock);
+                       spin_unlock_irqrestore(&zone->lru_lock, flags);
                        locked = false;
                }
-               if (need_resched() || spin_is_contended(&zone->lru_lock)) {
-                       if (locked)
-                               spin_unlock_irq(&zone->lru_lock);
-                       cond_resched();
-                       spin_lock_irq(&zone->lru_lock);
-                       if (fatal_signal_pending(current))
-                               break;
-               } else if (!locked)
-                       spin_lock_irq(&zone->lru_lock);
+
+               /* Check if it is ok to still hold the lock */
+               locked = compact_checklock_irqsave(&zone->lru_lock, &flags,
+                                                               locked, cc);
+               if (!locked)
+                       break;
 
                /*
                 * migrate_pfn does not necessarily start aligned to a
@@ -349,9 +395,10 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                }
        }
 
-       acct_isolated(zone, cc);
+       acct_isolated(zone, locked, cc);
 
-       spin_unlock_irq(&zone->lru_lock);
+       if (locked)
+               spin_unlock_irqrestore(&zone->lru_lock, flags);
 
        trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
 
@@ -383,6 +430,20 @@ static bool suitable_migration_target(struct page *page)
        return false;
 }
 
+/*
+ * Returns the start pfn of the last page block in a zone.  This is the starting
+ * point for full compaction of a zone.  Compaction searches for free pages from
+ * the end of each zone, while isolate_freepages_block scans forward inside each
+ * page block.
+ */
+static unsigned long start_free_pfn(struct zone *zone)
+{
+       unsigned long free_pfn;
+       free_pfn = zone->zone_start_pfn + zone->spanned_pages;
+       free_pfn &= ~(pageblock_nr_pages-1);
+       return free_pfn;
+}
+
 /*
  * Based on information in the current compact_control, find blocks
  * suitable for isolating free pages from and then isolate them.
@@ -422,17 +483,6 @@ static void isolate_freepages(struct zone *zone,
                                        pfn -= pageblock_nr_pages) {
                unsigned long isolated;
 
-               /*
-                * Skip ahead if another thread is compacting in the area
-                * simultaneously. If we wrapped around, we can only skip
-                * ahead if zone->compact_cached_free_pfn also wrapped to
-                * above our starting point.
-                */
-               if (cc->order > 0 && (!cc->wrapped ||
-                                     zone->compact_cached_free_pfn >
-                                     cc->start_free_pfn))
-                       pfn = min(pfn, zone->compact_cached_free_pfn);
-
                if (!pfn_valid(pfn))
                        continue;
 
@@ -458,7 +508,16 @@ static void isolate_freepages(struct zone *zone,
                 * are disabled
                 */
                isolated = 0;
-               spin_lock_irqsave(&zone->lock, flags);
+
+               /*
+                * The zone lock must be held to isolate freepages. This
+                * unfortunately this is a very coarse lock and can be
+                * heavily contended if there are parallel allocations
+                * or parallel compactions. For async compaction do not
+                * spin on the lock
+                */
+               if (!compact_trylock_irqsave(&zone->lock, &flags, cc))
+                       break;
                if (suitable_migration_target(page)) {
                        end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);
                        isolated = isolate_freepages_block(pfn, end_pfn,
@@ -474,7 +533,15 @@ static void isolate_freepages(struct zone *zone,
                 */
                if (isolated) {
                        high_pfn = max(high_pfn, pfn);
-                       if (cc->order > 0)
+
+                       /*
+                        * If the free scanner has wrapped, update
+                        * compact_cached_free_pfn to point to the highest
+                        * pageblock with free pages. This reduces excessive
+                        * scanning of full pageblocks near the end of the
+                        * zone
+                        */
+                       if (cc->order > 0 && cc->wrapped)
                                zone->compact_cached_free_pfn = high_pfn;
                }
        }
@@ -484,6 +551,11 @@ static void isolate_freepages(struct zone *zone,
 
        cc->free_pfn = high_pfn;
        cc->nr_freepages = nr_freepages;
+
+       /* If compact_cached_free_pfn is reset then set it now */
+       if (cc->order > 0 && !cc->wrapped &&
+                       zone->compact_cached_free_pfn == start_free_pfn(zone))
+               zone->compact_cached_free_pfn = high_pfn;
 }
 
 /*
@@ -570,20 +642,6 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
        return ISOLATE_SUCCESS;
 }
 
-/*
- * Returns the start pfn of the last page block in a zone.  This is the starting
- * point for full compaction of a zone.  Compaction searches for free pages from
- * the end of each zone, while isolate_freepages_block scans forward inside each
- * page block.
- */
-static unsigned long start_free_pfn(struct zone *zone)
-{
-       unsigned long free_pfn;
-       free_pfn = zone->zone_start_pfn + zone->spanned_pages;
-       free_pfn &= ~(pageblock_nr_pages-1);
-       return free_pfn;
-}
-
 static int compact_finished(struct zone *zone,
                            struct compact_control *cc)
 {
@@ -771,7 +829,7 @@ out:
 
 static unsigned long compact_zone_order(struct zone *zone,
                                 int order, gfp_t gfp_mask,
-                                bool sync)
+                                bool sync, bool *contended)
 {
        struct compact_control cc = {
                .nr_freepages = 0,
@@ -780,6 +838,7 @@ static unsigned long compact_zone_order(struct zone *zone,
                .migratetype = allocflags_to_migratetype(gfp_mask),
                .zone = zone,
                .sync = sync,
+               .contended = contended,
        };
        INIT_LIST_HEAD(&cc.freepages);
        INIT_LIST_HEAD(&cc.migratepages);
@@ -801,7 +860,7 @@ int sysctl_extfrag_threshold = 500;
  */
 unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *nodemask,
-                       bool sync)
+                       bool sync, bool *contended)
 {
        enum zone_type high_zoneidx = gfp_zone(gfp_mask);
        int may_enter_fs = gfp_mask & __GFP_FS;
@@ -825,7 +884,8 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                                                                nodemask) {
                int status;
 
-               status = compact_zone_order(zone, order, gfp_mask, sync);
+               status = compact_zone_order(zone, order, gfp_mask, sync,
+                                               contended);
                rc = max(status, rc);
 
                /* If a normal allocation would succeed, stop compacting */
@@ -861,7 +921,7 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
                if (cc->order > 0) {
                        int ok = zone_watermark_ok(zone, cc->order,
                                                low_wmark_pages(zone), 0, 0);
-                       if (ok && cc->order > zone->compact_order_failed)
+                       if (ok && cc->order >= zone->compact_order_failed)
                                zone->compact_order_failed = cc->order + 1;
                        /* Currently async compaction is never deferred. */
                        else if (!ok && cc->sync)
index 3314f79d775a5f90c84e3250d8b93b7bd6f99933..b8c91b342e244153ec9b24b4673e6dd2575af267 100644 (file)
@@ -130,6 +130,7 @@ struct compact_control {
        int order;                      /* order a direct compactor needs */
        int migratetype;                /* MOVABLE, RECLAIMABLE etc */
        struct zone *zone;
+       bool *contended;                /* True if a lock was contended */
 };
 
 unsigned long
index e3e86914f11ad7d664ec73e08c98ee5670ef8e16..9adee9fc0d8a6d799843ee0b010e8c4133f227f5 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2309,7 +2309,7 @@ void exit_mmap(struct mm_struct *mm)
        }
        vm_unacct_memory(nr_accounted);
 
-       BUG_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
+       WARN_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
 }
 
 /* Insert vm structure into process list sorted by address
index e5363f34e0250656c357d965a2e8949577cfb607..5ad5ce23c1e082bc999222f42e542d942794c7c7 100644 (file)
@@ -1532,7 +1532,6 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
        proc_dointvec(table, write, buffer, length, ppos);
-       bdi_arm_supers_timer();
        return 0;
 }
 
index 009ac285fea79faca555fc074df33e60b3dc7827..c66fb875104ab99feccb0e116b48b9d54a6011e4 100644 (file)
@@ -1928,6 +1928,17 @@ this_zone_full:
                zlc_active = 0;
                goto zonelist_scan;
        }
+
+       if (page)
+               /*
+                * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was
+                * necessary to allocate the page. The expectation is
+                * that the caller is taking steps that will free more
+                * memory. The caller should avoid the page being used
+                * for !PFMEMALLOC purposes.
+                */
+               page->pfmemalloc = !!(alloc_flags & ALLOC_NO_WATERMARKS);
+
        return page;
 }
 
@@ -2091,7 +2102,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
        int migratetype, bool sync_migration,
-       bool *deferred_compaction,
+       bool *contended_compaction, bool *deferred_compaction,
        unsigned long *did_some_progress)
 {
        struct page *page;
@@ -2106,7 +2117,8 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
 
        current->flags |= PF_MEMALLOC;
        *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
-                                               nodemask, sync_migration);
+                                               nodemask, sync_migration,
+                                               contended_compaction);
        current->flags &= ~PF_MEMALLOC;
        if (*did_some_progress != COMPACT_SKIPPED) {
 
@@ -2152,7 +2164,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
        int migratetype, bool sync_migration,
-       bool *deferred_compaction,
+       bool *contended_compaction, bool *deferred_compaction,
        unsigned long *did_some_progress)
 {
        return NULL;
@@ -2325,6 +2337,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
        unsigned long did_some_progress;
        bool sync_migration = false;
        bool deferred_compaction = false;
+       bool contended_compaction = false;
 
        /*
         * In the slowpath, we sanity check order to avoid ever trying to
@@ -2389,14 +2402,6 @@ rebalance:
                                zonelist, high_zoneidx, nodemask,
                                preferred_zone, migratetype);
                if (page) {
-                       /*
-                        * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was
-                        * necessary to allocate the page. The expectation is
-                        * that the caller is taking steps that will free more
-                        * memory. The caller should avoid the page being used
-                        * for !PFMEMALLOC purposes.
-                        */
-                       page->pfmemalloc = true;
                        goto got_pg;
                }
        }
@@ -2422,6 +2427,7 @@ rebalance:
                                        nodemask,
                                        alloc_flags, preferred_zone,
                                        migratetype, sync_migration,
+                                       &contended_compaction,
                                        &deferred_compaction,
                                        &did_some_progress);
        if (page)
@@ -2431,10 +2437,11 @@ rebalance:
        /*
         * If compaction is deferred for high-order allocations, it is because
         * sync compaction recently failed. In this is the case and the caller
-        * has requested the system not be heavily disrupted, fail the
-        * allocation now instead of entering direct reclaim
+        * requested a movable allocation that does not heavily disrupt the
+        * system then fail the allocation instead of entering direct reclaim.
         */
-       if (deferred_compaction && (gfp_mask & __GFP_NO_KSWAPD))
+       if ((deferred_compaction || contended_compaction) &&
+                                               (gfp_mask & __GFP_NO_KSWAPD))
                goto nopage;
 
        /* Try direct reclaim and then allocating */
@@ -2505,6 +2512,7 @@ rebalance:
                                        nodemask,
                                        alloc_flags, preferred_zone,
                                        migratetype, sync_migration,
+                                       &contended_compaction,
                                        &deferred_compaction,
                                        &did_some_progress);
                if (page)
@@ -2569,8 +2577,6 @@ retry_cpuset:
                page = __alloc_pages_slowpath(gfp_mask, order,
                                zonelist, high_zoneidx, nodemask,
                                preferred_zone, migratetype);
-       else
-               page->pfmemalloc = false;
 
        trace_mm_page_alloc(page, order, gfp_mask, migratetype);
 
index 73a2a83ee2da51333731c4bb5f8307a78c2c5496..402442402af710d5acedf500347cca48f89a6be4 100644 (file)
@@ -137,9 +137,21 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
        return rc;
 }
 
+static inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       if (vlan->netpoll)
+               netpoll_send_skb(vlan->netpoll, skb);
+#else
+       BUG();
+#endif
+       return NETDEV_TX_OK;
+}
+
 static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
                                            struct net_device *dev)
 {
+       struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
        unsigned int len;
        int ret;
@@ -150,29 +162,30 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
         * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
         */
        if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
-           vlan_dev_priv(dev)->flags & VLAN_FLAG_REORDER_HDR) {
+           vlan->flags & VLAN_FLAG_REORDER_HDR) {
                u16 vlan_tci;
-               vlan_tci = vlan_dev_priv(dev)->vlan_id;
+               vlan_tci = vlan->vlan_id;
                vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
                skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
        }
 
-       skb->dev = vlan_dev_priv(dev)->real_dev;
+       skb->dev = vlan->real_dev;
        len = skb->len;
-       if (netpoll_tx_running(dev))
-               return skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev);
+       if (unlikely(netpoll_tx_running(dev)))
+               return vlan_netpoll_send_skb(vlan, skb);
+
        ret = dev_queue_xmit(skb);
 
        if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
                struct vlan_pcpu_stats *stats;
 
-               stats = this_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats);
+               stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
                u64_stats_update_begin(&stats->syncp);
                stats->tx_packets++;
                stats->tx_bytes += len;
                u64_stats_update_end(&stats->syncp);
        } else {
-               this_cpu_inc(vlan_dev_priv(dev)->vlan_pcpu_stats->tx_dropped);
+               this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
        }
 
        return ret;
@@ -669,25 +682,26 @@ static void vlan_dev_poll_controller(struct net_device *dev)
        return;
 }
 
-static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
+static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo,
+                                 gfp_t gfp)
 {
-       struct vlan_dev_priv *info = vlan_dev_priv(dev);
-       struct net_device *real_dev = info->real_dev;
+       struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+       struct net_device *real_dev = vlan->real_dev;
        struct netpoll *netpoll;
        int err = 0;
 
-       netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
+       netpoll = kzalloc(sizeof(*netpoll), gfp);
        err = -ENOMEM;
        if (!netpoll)
                goto out;
 
-       err = __netpoll_setup(netpoll, real_dev);
+       err = __netpoll_setup(netpoll, real_dev, gfp);
        if (err) {
                kfree(netpoll);
                goto out;
        }
 
-       info->netpoll = netpoll;
+       vlan->netpoll = netpoll;
 
 out:
        return err;
@@ -695,19 +709,15 @@ out:
 
 static void vlan_dev_netpoll_cleanup(struct net_device *dev)
 {
-       struct vlan_dev_priv *info = vlan_dev_priv(dev);
-       struct netpoll *netpoll = info->netpoll;
+       struct vlan_dev_priv *vlan= vlan_dev_priv(dev);
+       struct netpoll *netpoll = vlan->netpoll;
 
        if (!netpoll)
                return;
 
-       info->netpoll = NULL;
-
-        /* Wait for transmitting packets to finish before freeing. */
-        synchronize_rcu_bh();
+       vlan->netpoll = NULL;
 
-        __netpoll_cleanup(netpoll);
-        kfree(netpoll);
+       __netpoll_free_rcu(netpoll);
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
 
index b4b44dbed645f74046ae4663a31b805a0ed72b52..0c0ad930a632f23e4c0661a20684c5d572e3dc15 100644 (file)
@@ -812,6 +812,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
 
                if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
                        return -ENOTCONN;
+               memset(&pvc, 0, sizeof(pvc));
                pvc.sap_family = AF_ATMPVC;
                pvc.sap_addr.itf = vcc->dev->number;
                pvc.sap_addr.vpi = vcc->vpi;
index 3a734919c36cbeac2e59e923225096f76380620b..ae0324021407c2b61aaf7c45a39bebb9d419972c 100644 (file)
@@ -95,6 +95,7 @@ static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr,
                return -ENOTCONN;
        *sockaddr_len = sizeof(struct sockaddr_atmpvc);
        addr = (struct sockaddr_atmpvc *)sockaddr;
+       memset(addr, 0, sizeof(*addr));
        addr->sap_family = AF_ATMPVC;
        addr->sap_addr.itf = vcc->dev->number;
        addr->sap_addr.vpi = vcc->vpi;
index b421cc49d2cd1f83a88b905047df40e2853c4b0b..fc866f2e4528c71c82ba125c23fb48fbd430b390 100644 (file)
@@ -200,11 +200,11 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
        if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
                goto out;
 
-       if (!batadv_atomic_dec_not_zero(&bat_priv->gw_reselect))
-               goto out;
-
        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
+       if (!batadv_atomic_dec_not_zero(&bat_priv->gw_reselect) && curr_gw)
+               goto out;
+
        next_gw = batadv_gw_get_best_gw_node(bat_priv);
 
        if (curr_gw == next_gw)
index a438f4b582fc8adccba3a67dfb33326b1ecf4606..99dd8f75b3ff20f0d2a277e1f65ffc284b002f2e 100644 (file)
@@ -197,6 +197,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
 del:
                list_del(&entry->list);
                kfree(entry);
+               kfree(tt_change_node);
                event_removed = true;
                goto unlock;
        }
index 41ff978a33f9078b3e23b7cc3fed67c78921b5c7..715d7e33fba0639d1556088e5ea84a08f6b4ccd4 100644 (file)
@@ -1365,6 +1365,9 @@ static bool hci_resolve_next_name(struct hci_dev *hdev)
                return false;
 
        e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
+       if (!e)
+               return false;
+
        if (hci_resolve_name(hdev, e) == 0) {
                e->name_state = NAME_PENDING;
                return true;
@@ -1393,12 +1396,20 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
                return;
 
        e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
-       if (e) {
+       /* If the device was not found in a list of found devices names of which
+        * are pending. there is no need to continue resolving a next name as it
+        * will be done upon receiving another Remote Name Request Complete
+        * Event */
+       if (!e)
+               return;
+
+       list_del(&e->list);
+       if (name) {
                e->name_state = NAME_KNOWN;
-               list_del(&e->list);
-               if (name)
-                       mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
-                                        e->data.rssi, name, name_len);
+               mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
+                                e->data.rssi, name, name_len);
+       } else {
+               e->name_state = NAME_NOT_KNOWN;
        }
 
        if (hci_resolve_next_name(hdev))
@@ -1762,7 +1773,12 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                if (conn->type == ACL_LINK) {
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
-                       conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+
+                       if (!conn->out && !hci_conn_ssp_enabled(conn) &&
+                           !hci_find_link_key(hdev, &ev->bdaddr))
+                               conn->disc_timeout = HCI_PAIRING_TIMEOUT;
+                       else
+                               conn->disc_timeout = HCI_DISCONN_TIMEOUT;
                } else
                        conn->state = BT_CONNECTED;
 
index a7f04de03d7916add5a20cf44d8e88e5daad495d..19fdac78e555b97c44dd6826bc60ef89a888395b 100644 (file)
@@ -694,6 +694,7 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
        *addr_len = sizeof(*haddr);
        haddr->hci_family = AF_BLUETOOTH;
        haddr->hci_dev    = hdev->id;
+       haddr->hci_channel= 0;
 
        release_sock(sk);
        return 0;
@@ -1009,6 +1010,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
                {
                        struct hci_filter *f = &hci_pi(sk)->filter;
 
+                       memset(&uf, 0, sizeof(uf));
                        uf.type_mask = f->type_mask;
                        uf.opcode    = f->opcode;
                        uf.event_mask[0] = *((u32 *) f->event_mask + 0);
index a8964db04bfb5cd1d0d348ed96c472e4786f3f44..daa149b7003cdd659120e79225a50c6216a6dce4 100644 (file)
@@ -1181,6 +1181,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        sk = chan->sk;
 
        hci_conn_hold(conn->hcon);
+       conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
 
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
index a4bb27e8427e9aabaa48b90727cb23bcf5568f96..1497edd191a2e04ee3121624db92547059f24369 100644 (file)
@@ -245,6 +245,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
+       memset(la, 0, sizeof(struct sockaddr_l2));
        addr->sa_family = AF_BLUETOOTH;
        *len = sizeof(struct sockaddr_l2);
 
@@ -1174,7 +1175,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
 
        chan = l2cap_chan_create();
        if (!chan) {
-               l2cap_sock_kill(sk);
+               sk_free(sk);
                return NULL;
        }
 
index 7e1e59645c056f71400ad9ed4dc0444548c41951..1a17850d093cd652621ac54833c53b8dabd395bc 100644 (file)
@@ -528,6 +528,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
+       memset(sa, 0, sizeof(*sa));
        sa->rc_family  = AF_BLUETOOTH;
        sa->rc_channel = rfcomm_pi(sk)->channel;
        if (peer)
@@ -822,6 +823,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
                }
 
                sec.level = rfcomm_pi(sk)->sec_level;
+               sec.key_size = 0;
 
                len = min_t(unsigned int, len, sizeof(sec));
                if (copy_to_user(optval, (char *) &sec, len))
index cb960773c002efafeb45b888ee8f3ba3e9208490..56f182393c4c7d278a391c1cbf0cccc7ed4424e3 100644 (file)
@@ -456,7 +456,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        size = sizeof(*dl) + dev_num * sizeof(*di);
 
-       dl = kmalloc(size, GFP_KERNEL);
+       dl = kzalloc(size, GFP_KERNEL);
        if (!dl)
                return -ENOMEM;
 
index 40bbe25dcff7f97c9a279c6d087eaed078563364..3589e21edb09817bace527336fd4880e24137ada 100644 (file)
@@ -131,6 +131,15 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
                sco_sock_clear_timer(sk);
                sco_chan_del(sk, err);
                bh_unlock_sock(sk);
+
+               sco_conn_lock(conn);
+               conn->sk = NULL;
+               sco_pi(sk)->conn = NULL;
+               sco_conn_unlock(conn);
+
+               if (conn->hcon)
+                       hci_conn_put(conn->hcon);
+
                sco_sock_kill(sk);
        }
 
@@ -821,16 +830,6 @@ static void sco_chan_del(struct sock *sk, int err)
 
        BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
 
-       if (conn) {
-               sco_conn_lock(conn);
-               conn->sk = NULL;
-               sco_pi(sk)->conn = NULL;
-               sco_conn_unlock(conn);
-
-               if (conn->hcon)
-                       hci_conn_put(conn->hcon);
-       }
-
        sk->sk_state = BT_CLOSED;
        sk->sk_err   = err;
        sk->sk_state_change(sk);
index 16ef0dc85a0a87580c311563028cc567fa826bce..901a616c8083e22f5163f8bbd1613b1529c63519 100644 (file)
@@ -579,8 +579,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
                smp = smp_chan_create(conn);
+       else
+               smp = conn->smp_chan;
 
-       smp = conn->smp_chan;
+       if (!smp)
+               return SMP_UNSPECIFIED;
 
        smp->preq[0] = SMP_CMD_PAIRING_REQ;
        memcpy(&smp->preq[1], req, sizeof(*req));
index 3334845376005cdba3a3b6b2d0b4013da4617446..070e8a68cfc63f856b281b4f19e08181cbd5172f 100644 (file)
@@ -31,9 +31,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        struct net_bridge_mdb_entry *mdst;
        struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
+       rcu_read_lock();
 #ifdef CONFIG_BRIDGE_NETFILTER
        if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
                br_nf_pre_routing_finish_bridge_slow(skb);
+               rcu_read_unlock();
                return NETDEV_TX_OK;
        }
 #endif
@@ -48,7 +50,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
 
-       rcu_read_lock();
        if (is_broadcast_ether_addr(dest))
                br_flood_deliver(br, skb);
        else if (is_multicast_ether_addr(dest)) {
@@ -206,24 +207,23 @@ static void br_poll_controller(struct net_device *br_dev)
 static void br_netpoll_cleanup(struct net_device *dev)
 {
        struct net_bridge *br = netdev_priv(dev);
-       struct net_bridge_port *p, *n;
+       struct net_bridge_port *p;
 
-       list_for_each_entry_safe(p, n, &br->port_list, list) {
+       list_for_each_entry(p, &br->port_list, list)
                br_netpoll_disable(p);
-       }
 }
 
-static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
+static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni,
+                           gfp_t gfp)
 {
        struct net_bridge *br = netdev_priv(dev);
-       struct net_bridge_port *p, *n;
+       struct net_bridge_port *p;
        int err = 0;
 
-       list_for_each_entry_safe(p, n, &br->port_list, list) {
+       list_for_each_entry(p, &br->port_list, list) {
                if (!p->dev)
                        continue;
-
-               err = br_netpoll_enable(p);
+               err = br_netpoll_enable(p, gfp);
                if (err)
                        goto fail;
        }
@@ -236,17 +236,17 @@ fail:
        goto out;
 }
 
-int br_netpoll_enable(struct net_bridge_port *p)
+int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
 {
        struct netpoll *np;
        int err = 0;
 
-       np = kzalloc(sizeof(*p->np), GFP_KERNEL);
+       np = kzalloc(sizeof(*p->np), gfp);
        err = -ENOMEM;
        if (!np)
                goto out;
 
-       err = __netpoll_setup(np, p->dev);
+       err = __netpoll_setup(np, p->dev, gfp);
        if (err) {
                kfree(np);
                goto out;
@@ -267,11 +267,7 @@ void br_netpoll_disable(struct net_bridge_port *p)
 
        p->np = NULL;
 
-       /* Wait for transmitting packets to finish before freeing. */
-       synchronize_rcu_bh();
-
-       __netpoll_cleanup(np);
-       kfree(np);
+       __netpoll_free_rcu(np);
 }
 
 #endif
index e9466d412707849b17b01200240cbb67e66b20af..02015a505d2a41ddbf5c6abea3867613fe7030e8 100644 (file)
@@ -65,7 +65,7 @@ static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 {
        skb->dev = to->dev;
 
-       if (unlikely(netpoll_tx_running(to->dev))) {
+       if (unlikely(netpoll_tx_running(to->br->dev))) {
                if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
                        kfree_skb(skb);
                else {
index e1144e1617be38814ebb2fb497755cb10b646559..1c8fdc3558cd48e9ad5d7be9c3981ebf80878364 100644 (file)
@@ -361,7 +361,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (err)
                goto err2;
 
-       if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
+       if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
                goto err3;
 
        err = netdev_set_master(dev, br->dev);
@@ -427,6 +427,10 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
        if (!p || p->br != br)
                return -EINVAL;
 
+       /* Since more than one interface can be attached to a bridge,
+        * there still maybe an alternate path for netconsole to use;
+        * therefore there is no reason for a NETDEV_RELEASE event.
+        */
        del_nbp(p);
 
        spin_lock_bh(&br->lock);
index a768b2408edff64890dde477df5918c102630a5e..f507d2af9646bcb273cf1f50f98feb065027e14a 100644 (file)
@@ -316,7 +316,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
                netpoll_send_skb(np, skb);
 }
 
-extern int br_netpoll_enable(struct net_bridge_port *p);
+extern int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp);
 extern void br_netpoll_disable(struct net_bridge_port *p);
 #else
 static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
@@ -329,7 +329,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
 {
 }
 
-static inline int br_netpoll_enable(struct net_bridge_port *p)
+static inline int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
 {
        return 0;
 }
index 69771c04ba8fc96a2718f841b6e3d159ee000112..e597733affb82f088203bab569644f312e8d5463 100644 (file)
@@ -94,6 +94,10 @@ static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
 
        /* check the version of IP */
        ip_version = skb_header_pointer(skb, 0, 1, &buf);
+       if (!ip_version) {
+               kfree_skb(skb);
+               return -EINVAL;
+       }
 
        switch (*ip_version >> 4) {
        case 4:
index 69e38db28e5f3efcda5ce871ac5682408eb5aa9e..a8020293f34210620eff72f6193ee35e064f5d69 100644 (file)
@@ -84,7 +84,6 @@ int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
                        return -1;
                }
        } else {
-               pr_info("client%lld fsid %pU\n", ceph_client_id(client), fsid);
                memcpy(&client->fsid, fsid, sizeof(*fsid));
        }
        return 0;
index 54b531a01121aafdbc31a9ba33fd60027280d32e..38b5dc1823d44961e6bbf7d52d36991920f5ddc1 100644 (file)
@@ -189,6 +189,9 @@ int ceph_debugfs_client_init(struct ceph_client *client)
        snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid,
                 client->monc.auth->global_id);
 
+       dout("ceph_debugfs_client_init %p %s\n", client, name);
+
+       BUG_ON(client->debugfs_dir);
        client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
        if (!client->debugfs_dir)
                goto out;
@@ -234,6 +237,7 @@ out:
 
 void ceph_debugfs_client_cleanup(struct ceph_client *client)
 {
+       dout("ceph_debugfs_client_cleanup %p\n", client);
        debugfs_remove(client->debugfs_osdmap);
        debugfs_remove(client->debugfs_monmap);
        debugfs_remove(client->osdc.debugfs_file);
index b9796750034afc093c172dc9ac92b2e864d87271..24c5eea8c45bb1233edfad141baf6a6391e023c6 100644 (file)
@@ -915,7 +915,6 @@ static int prepare_write_connect(struct ceph_connection *con)
        con->out_connect.authorizer_len = auth ?
                cpu_to_le32(auth->authorizer_buf_len) : 0;
 
-       con_out_kvec_reset(con);
        con_out_kvec_add(con, sizeof (con->out_connect),
                                        &con->out_connect);
        if (auth && auth->authorizer_buf_len)
@@ -1557,6 +1556,7 @@ static int process_connect(struct ceph_connection *con)
                        return -1;
                }
                con->auth_retry = 1;
+               con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1577,6 +1577,7 @@ static int process_connect(struct ceph_connection *con)
                       ENTITY_NAME(con->peer_name),
                       ceph_pr_addr(&con->peer_addr.in_addr));
                reset_connection(con);
+               con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1601,6 +1602,7 @@ static int process_connect(struct ceph_connection *con)
                     le32_to_cpu(con->out_connect.connect_seq),
                     le32_to_cpu(con->in_reply.connect_seq));
                con->connect_seq = le32_to_cpu(con->in_reply.connect_seq);
+               con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -1617,6 +1619,7 @@ static int process_connect(struct ceph_connection *con)
                     le32_to_cpu(con->in_reply.global_seq));
                get_global_seq(con->msgr,
                               le32_to_cpu(con->in_reply.global_seq));
+               con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
                        return ret;
@@ -2135,7 +2138,11 @@ more:
                BUG_ON(con->state != CON_STATE_CONNECTING);
                con->state = CON_STATE_NEGOTIATING;
 
-               /* Banner is good, exchange connection info */
+               /*
+                * Received banner is good, exchange connection info.
+                * Do not reset out_kvec, as sending our banner raced
+                * with receiving peer banner after connect completed.
+                */
                ret = prepare_write_connect(con);
                if (ret < 0)
                        goto out;
index 105d533b55f3bcc3e8a2e7a82b80a6459cbb9363..900ea0f043fc0d5cfd7c68b7abc37e607d822165 100644 (file)
@@ -310,6 +310,17 @@ int ceph_monc_open_session(struct ceph_mon_client *monc)
 }
 EXPORT_SYMBOL(ceph_monc_open_session);
 
+/*
+ * We require the fsid and global_id in order to initialize our
+ * debugfs dir.
+ */
+static bool have_debugfs_info(struct ceph_mon_client *monc)
+{
+       dout("have_debugfs_info fsid %d globalid %lld\n",
+            (int)monc->client->have_fsid, monc->auth->global_id);
+       return monc->client->have_fsid && monc->auth->global_id > 0;
+}
+
 /*
  * The monitor responds with mount ack indicate mount success.  The
  * included client ticket allows the client to talk to MDSs and OSDs.
@@ -320,9 +331,12 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
        struct ceph_client *client = monc->client;
        struct ceph_monmap *monmap = NULL, *old = monc->monmap;
        void *p, *end;
+       int had_debugfs_info, init_debugfs = 0;
 
        mutex_lock(&monc->mutex);
 
+       had_debugfs_info = have_debugfs_info(monc);
+
        dout("handle_monmap\n");
        p = msg->front.iov_base;
        end = p + msg->front.iov_len;
@@ -344,12 +358,22 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
 
        if (!client->have_fsid) {
                client->have_fsid = true;
+               if (!had_debugfs_info && have_debugfs_info(monc)) {
+                       pr_info("client%lld fsid %pU\n",
+                               ceph_client_id(monc->client),
+                               &monc->client->fsid);
+                       init_debugfs = 1;
+               }
                mutex_unlock(&monc->mutex);
-               /*
-                * do debugfs initialization without mutex to avoid
-                * creating a locking dependency
-                */
-               ceph_debugfs_client_init(client);
+
+               if (init_debugfs) {
+                       /*
+                        * do debugfs initialization without mutex to avoid
+                        * creating a locking dependency
+                        */
+                       ceph_debugfs_client_init(monc->client);
+               }
+
                goto out_unlocked;
        }
 out:
@@ -865,8 +889,10 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
 {
        int ret;
        int was_auth = 0;
+       int had_debugfs_info, init_debugfs = 0;
 
        mutex_lock(&monc->mutex);
+       had_debugfs_info = have_debugfs_info(monc);
        if (monc->auth->ops)
                was_auth = monc->auth->ops->is_authenticated(monc->auth);
        monc->pending_auth = 0;
@@ -889,7 +915,22 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
                __send_subscribe(monc);
                __resend_generic_request(monc);
        }
+
+       if (!had_debugfs_info && have_debugfs_info(monc)) {
+               pr_info("client%lld fsid %pU\n",
+                       ceph_client_id(monc->client),
+                       &monc->client->fsid);
+               init_debugfs = 1;
+       }
        mutex_unlock(&monc->mutex);
+
+       if (init_debugfs) {
+               /*
+                * do debugfs initialization without mutex to avoid
+                * creating a locking dependency
+                */
+               ceph_debugfs_client_init(monc->client);
+       }
 }
 
 static int __validate_auth(struct ceph_mon_client *monc)
index 0cb3fe8d8e7248c1618829673041135a606b36ff..83988362805ef1453efb37bfcb3692f59f4edd21 100644 (file)
@@ -1055,6 +1055,8 @@ rollback:
  */
 int dev_set_alias(struct net_device *dev, const char *alias, size_t len)
 {
+       char *new_ifalias;
+
        ASSERT_RTNL();
 
        if (len >= IFALIASZ)
@@ -1068,9 +1070,10 @@ int dev_set_alias(struct net_device *dev, const char *alias, size_t len)
                return 0;
        }
 
-       dev->ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL);
-       if (!dev->ifalias)
+       new_ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL);
+       if (!new_ifalias)
                return -ENOMEM;
+       dev->ifalias = new_ifalias;
 
        strlcpy(dev->ifalias, alias, len+1);
        return len;
@@ -1639,6 +1642,19 @@ static inline int deliver_skb(struct sk_buff *skb,
        return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 }
 
+static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb)
+{
+       if (ptype->af_packet_priv == NULL)
+               return false;
+
+       if (ptype->id_match)
+               return ptype->id_match(ptype, skb->sk);
+       else if ((struct sock *)ptype->af_packet_priv == skb->sk)
+               return true;
+
+       return false;
+}
+
 /*
  *     Support routine. Sends outgoing frames to any network
  *     taps currently in use.
@@ -1656,8 +1672,7 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
                 * they originated from - MvS (miquels@drinkel.ow.org)
                 */
                if ((ptype->dev == dev || !ptype->dev) &&
-                   (ptype->af_packet_priv == NULL ||
-                    (struct sock *)ptype->af_packet_priv != skb->sk)) {
+                   (!skb_loop_sk(ptype, skb))) {
                        if (pt_prev) {
                                deliver_skb(skb2, pt_prev, skb->dev);
                                pt_prev = ptype;
@@ -2134,6 +2149,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
        __be16 protocol = skb->protocol;
        netdev_features_t features = skb->dev->features;
 
+       if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
+               features &= ~NETIF_F_GSO_MASK;
+
        if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
                protocol = veh->h_vlan_encapsulated_proto;
@@ -5726,6 +5744,7 @@ EXPORT_SYMBOL(netdev_refcnt_read);
 
 /**
  * netdev_wait_allrefs - wait until all references are gone.
+ * @dev: target net_device
  *
  * This is called when unregistering network devices.
  *
@@ -5986,6 +6005,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        dev_net_set(dev, &init_net);
 
        dev->gso_max_size = GSO_MAX_SIZE;
+       dev->gso_max_segs = GSO_MAX_SEGS;
 
        INIT_LIST_HEAD(&dev->napi_list);
        INIT_LIST_HEAD(&dev->unreg_list);
index 069d51d29414a3245f9b60b66c534f78ce3b1752..56d63612e1e4b9a1ebfc04ddfa1bcd50333e0118 100644 (file)
@@ -149,7 +149,15 @@ int dst_discard(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(dst_discard);
 
-const u32 dst_default_metrics[RTAX_MAX];
+const u32 dst_default_metrics[RTAX_MAX + 1] = {
+       /* This initializer is needed to force linker to place this variable
+        * into const section. Otherwise it might end into bss section.
+        * We really want to avoid false sharing on this variable, and catch
+        * any writes on it.
+        */
+       [RTAX_MAX] = 0xdeadbeef,
+};
+
 
 void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
                int initial_ref, int initial_obsolete, unsigned short flags)
index b4c90e42b4434455c8205f4483991326a85eedb6..346b1eb83a1f0336ed1e9dcf4f5905b733022dff 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/if_vlan.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <asm/unaligned.h>
@@ -54,7 +55,7 @@ static atomic_t trapped;
         MAX_UDP_CHUNK)
 
 static void zap_completion_queue(void);
-static void arp_reply(struct sk_buff *skb);
+static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
 
 static unsigned int carrier_timeout = 4;
 module_param(carrier_timeout, uint, 0644);
@@ -167,15 +168,24 @@ static void poll_napi(struct net_device *dev)
        struct napi_struct *napi;
        int budget = 16;
 
+       WARN_ON_ONCE(!irqs_disabled());
+
        list_for_each_entry(napi, &dev->napi_list, dev_list) {
+               local_irq_enable();
                if (napi->poll_owner != smp_processor_id() &&
                    spin_trylock(&napi->poll_lock)) {
-                       budget = poll_one_napi(dev->npinfo, napi, budget);
+                       rcu_read_lock_bh();
+                       budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
+                                              napi, budget);
+                       rcu_read_unlock_bh();
                        spin_unlock(&napi->poll_lock);
 
-                       if (!budget)
+                       if (!budget) {
+                               local_irq_disable();
                                break;
+                       }
                }
+               local_irq_disable();
        }
 }
 
@@ -185,13 +195,14 @@ static void service_arp_queue(struct netpoll_info *npi)
                struct sk_buff *skb;
 
                while ((skb = skb_dequeue(&npi->arp_tx)))
-                       arp_reply(skb);
+                       netpoll_arp_reply(skb, npi);
        }
 }
 
 static void netpoll_poll_dev(struct net_device *dev)
 {
        const struct net_device_ops *ops;
+       struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
 
        if (!dev || !netif_running(dev))
                return;
@@ -206,17 +217,18 @@ static void netpoll_poll_dev(struct net_device *dev)
        poll_napi(dev);
 
        if (dev->flags & IFF_SLAVE) {
-               if (dev->npinfo) {
+               if (ni) {
                        struct net_device *bond_dev = dev->master;
                        struct sk_buff *skb;
-                       while ((skb = skb_dequeue(&dev->npinfo->arp_tx))) {
+                       struct netpoll_info *bond_ni = rcu_dereference_bh(bond_dev->npinfo);
+                       while ((skb = skb_dequeue(&ni->arp_tx))) {
                                skb->dev = bond_dev;
-                               skb_queue_tail(&bond_dev->npinfo->arp_tx, skb);
+                               skb_queue_tail(&bond_ni->arp_tx, skb);
                        }
                }
        }
 
-       service_arp_queue(dev->npinfo);
+       service_arp_queue(ni);
 
        zap_completion_queue();
 }
@@ -302,6 +314,7 @@ static int netpoll_owner_active(struct net_device *dev)
        return 0;
 }
 
+/* call with IRQ disabled */
 void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                             struct net_device *dev)
 {
@@ -309,8 +322,11 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
        unsigned long tries;
        const struct net_device_ops *ops = dev->netdev_ops;
        /* It is up to the caller to keep npinfo alive. */
-       struct netpoll_info *npinfo = np->dev->npinfo;
+       struct netpoll_info *npinfo;
+
+       WARN_ON_ONCE(!irqs_disabled());
 
+       npinfo = rcu_dereference_bh(np->dev->npinfo);
        if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
                __kfree_skb(skb);
                return;
@@ -319,16 +335,22 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
        /* don't get messages out of order, and no recursion */
        if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) {
                struct netdev_queue *txq;
-               unsigned long flags;
 
                txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
 
-               local_irq_save(flags);
                /* try until next clock tick */
                for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
                     tries > 0; --tries) {
                        if (__netif_tx_trylock(txq)) {
                                if (!netif_xmit_stopped(txq)) {
+                                       if (vlan_tx_tag_present(skb) &&
+                                           !(netif_skb_features(skb) & NETIF_F_HW_VLAN_TX)) {
+                                               skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+                                               if (unlikely(!skb))
+                                                       break;
+                                               skb->vlan_tci = 0;
+                                       }
+
                                        status = ops->ndo_start_xmit(skb, dev);
                                        if (status == NETDEV_TX_OK)
                                                txq_trans_update(txq);
@@ -347,10 +369,9 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                }
 
                WARN_ONCE(!irqs_disabled(),
-                       "netpoll_send_skb(): %s enabled interrupts in poll (%pF)\n",
+                       "netpoll_send_skb_on_dev(): %s enabled interrupts in poll (%pF)\n",
                        dev->name, ops->ndo_start_xmit);
 
-               local_irq_restore(flags);
        }
 
        if (status != NETDEV_TX_OK) {
@@ -423,9 +444,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 }
 EXPORT_SYMBOL(netpoll_send_udp);
 
-static void arp_reply(struct sk_buff *skb)
+static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
-       struct netpoll_info *npinfo = skb->dev->npinfo;
        struct arphdr *arp;
        unsigned char *arp_ptr;
        int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
@@ -543,13 +563,12 @@ static void arp_reply(struct sk_buff *skb)
        spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 }
 
-int __netpoll_rx(struct sk_buff *skb)
+int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
        int proto, len, ulen;
        int hits = 0;
        const struct iphdr *iph;
        struct udphdr *uh;
-       struct netpoll_info *npinfo = skb->dev->npinfo;
        struct netpoll *np, *tmp;
 
        if (list_empty(&npinfo->rx_np))
@@ -565,6 +584,12 @@ int __netpoll_rx(struct sk_buff *skb)
                return 1;
        }
 
+       if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
+               skb = vlan_untag(skb);
+               if (unlikely(!skb))
+                       goto out;
+       }
+
        proto = ntohs(eth_hdr(skb)->h_proto);
        if (proto != ETH_P_IP)
                goto out;
@@ -715,7 +740,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
 }
 EXPORT_SYMBOL(netpoll_parse_options);
 
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 {
        struct netpoll_info *npinfo;
        const struct net_device_ops *ops;
@@ -734,7 +759,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
        }
 
        if (!ndev->npinfo) {
-               npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
+               npinfo = kmalloc(sizeof(*npinfo), gfp);
                if (!npinfo) {
                        err = -ENOMEM;
                        goto out;
@@ -752,7 +777,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
 
                ops = np->dev->netdev_ops;
                if (ops->ndo_netpoll_setup) {
-                       err = ops->ndo_netpoll_setup(ndev, npinfo);
+                       err = ops->ndo_netpoll_setup(ndev, npinfo, gfp);
                        if (err)
                                goto free_npinfo;
                }
@@ -857,7 +882,7 @@ int netpoll_setup(struct netpoll *np)
        refill_skbs();
 
        rtnl_lock();
-       err = __netpoll_setup(np, ndev);
+       err = __netpoll_setup(np, ndev, GFP_KERNEL);
        rtnl_unlock();
 
        if (err)
@@ -878,6 +903,24 @@ static int __init netpoll_init(void)
 }
 core_initcall(netpoll_init);
 
+static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
+{
+       struct netpoll_info *npinfo =
+                       container_of(rcu_head, struct netpoll_info, rcu);
+
+       skb_queue_purge(&npinfo->arp_tx);
+       skb_queue_purge(&npinfo->txq);
+
+       /* we can't call cancel_delayed_work_sync here, as we are in softirq */
+       cancel_delayed_work(&npinfo->tx_work);
+
+       /* clean after last, unfinished work */
+       __skb_queue_purge(&npinfo->txq);
+       /* now cancel it again */
+       cancel_delayed_work(&npinfo->tx_work);
+       kfree(npinfo);
+}
+
 void __netpoll_cleanup(struct netpoll *np)
 {
        struct netpoll_info *npinfo;
@@ -903,20 +946,24 @@ void __netpoll_cleanup(struct netpoll *np)
                        ops->ndo_netpoll_cleanup(np->dev);
 
                RCU_INIT_POINTER(np->dev->npinfo, NULL);
+               call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info);
+       }
+}
+EXPORT_SYMBOL_GPL(__netpoll_cleanup);
 
-               /* avoid racing with NAPI reading npinfo */
-               synchronize_rcu_bh();
+static void rcu_cleanup_netpoll(struct rcu_head *rcu_head)
+{
+       struct netpoll *np = container_of(rcu_head, struct netpoll, rcu);
 
-               skb_queue_purge(&npinfo->arp_tx);
-               skb_queue_purge(&npinfo->txq);
-               cancel_delayed_work_sync(&npinfo->tx_work);
+       __netpoll_cleanup(np);
+       kfree(np);
+}
 
-               /* clean after last, unfinished work */
-               __skb_queue_purge(&npinfo->txq);
-               kfree(npinfo);
-       }
+void __netpoll_free_rcu(struct netpoll *np)
+{
+       call_rcu_bh(&np->rcu, rcu_cleanup_netpoll);
 }
-EXPORT_SYMBOL_GPL(__netpoll_cleanup);
+EXPORT_SYMBOL_GPL(__netpoll_free_rcu);
 
 void netpoll_cleanup(struct netpoll *np)
 {
index ed0c0431fcd8ff225842ec8de8537f54f0a3294f..c75e3f9d060f8e3d086b747255ab65c8104f7dde 100644 (file)
@@ -101,12 +101,10 @@ static int write_update_netdev_table(struct net_device *dev)
        u32 max_len;
        struct netprio_map *map;
 
-       rtnl_lock();
        max_len = atomic_read(&max_prioidx) + 1;
        map = rtnl_dereference(dev->priomap);
        if (!map || map->priomap_len < max_len)
                ret = extend_netdev_table(dev, max_len);
-       rtnl_unlock();
 
        return ret;
 }
@@ -256,17 +254,17 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
        if (!dev)
                goto out_free_devname;
 
+       rtnl_lock();
        ret = write_update_netdev_table(dev);
        if (ret < 0)
                goto out_put_dev;
 
-       rcu_read_lock();
-       map = rcu_dereference(dev->priomap);
+       map = rtnl_dereference(dev->priomap);
        if (map)
                map->priomap[prioidx] = priority;
-       rcu_read_unlock();
 
 out_put_dev:
+       rtnl_unlock();
        dev_put(dev);
 
 out_free_devname:
@@ -277,12 +275,6 @@ out_free_devname:
 void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
        struct task_struct *p;
-       char *tmp = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL);
-
-       if (!tmp) {
-               pr_warn("Unable to attach cgrp due to alloc failure!\n");
-               return;
-       }
 
        cgroup_taskset_for_each(p, cgrp, tset) {
                unsigned int fd;
@@ -296,32 +288,24 @@ void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
                        continue;
                }
 
-               rcu_read_lock();
+               spin_lock(&files->file_lock);
                fdt = files_fdtable(files);
                for (fd = 0; fd < fdt->max_fds; fd++) {
-                       char *path;
                        struct file *file;
                        struct socket *sock;
-                       unsigned long s;
-                       int rv, err = 0;
+                       int err;
 
                        file = fcheck_files(files, fd);
                        if (!file)
                                continue;
 
-                       path = d_path(&file->f_path, tmp, PAGE_SIZE);
-                       rv = sscanf(path, "socket:[%lu]", &s);
-                       if (rv <= 0)
-                               continue;
-
                        sock = sock_from_file(file, &err);
-                       if (!err)
+                       if (sock)
                                sock_update_netprioidx(sock->sk, p);
                }
-               rcu_read_unlock();
+               spin_unlock(&files->file_lock);
                task_unlock(p);
        }
-       kfree(tmp);
 }
 
 static struct cftype ss_files[] = {
index 8f6ccfd68ef4fb6625652f0b34f7f3fdb4b4a91e..040cebeed45b810cf9dd7d85c6ac2cbade98ee77 100644 (file)
@@ -265,6 +265,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
        for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax;
             i++, cmfptr++)
        {
+               struct socket *sock;
                int new_fd;
                err = security_file_receive(fp[i]);
                if (err)
@@ -281,6 +282,9 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
                }
                /* Bump the usage count and install the file. */
                get_file(fp[i]);
+               sock = sock_from_file(fp[i], &err);
+               if (sock)
+                       sock_update_netprioidx(sock->sk, current);
                fd_install(new_fd, fp[i]);
        }
 
index 6b654b3ddfda2a9a03f77bc1d2a5476a2c25e9d4..8f67ced8d6a808689255435dd412df132138af65 100644 (file)
@@ -1458,6 +1458,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
                } else {
                        sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
                        sk->sk_gso_max_size = dst->dev->gso_max_size;
+                       sk->sk_gso_max_segs = dst->dev->gso_max_segs;
                }
        }
 }
index 75c3582a7678ab418771b2a5ad5fd3c069a9e512..fb85d371a8dec875a01205b22ef6ddef5e99d511 100644 (file)
@@ -246,7 +246,7 @@ static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
                                        u32 __user *optval, int __user *optlen)
 {
        int rc = -ENOPROTOOPT;
-       if (ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
+       if (ccid != NULL && ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
                rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len,
                                                 optval, optlen);
        return rc;
@@ -257,7 +257,7 @@ static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk,
                                        u32 __user *optval, int __user *optlen)
 {
        int rc = -ENOPROTOOPT;
-       if (ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
+       if (ccid != NULL && ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
                rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len,
                                                 optval, optlen);
        return rc;
index d65e98798ecaff29110a2ff303d500482162df66..119c04317d48eed4abcb2bbf6071062c8d9784fd 100644 (file)
@@ -535,6 +535,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
        case DCCP_SOCKOPT_CCID_TX_INFO:
                if (len < sizeof(tfrc))
                        return -EINVAL;
+               memset(&tfrc, 0, sizeof(tfrc));
                tfrc.tfrctx_x      = hc->tx_x;
                tfrc.tfrctx_x_recv = hc->tx_x_recv;
                tfrc.tfrctx_x_calc = hc->tx_x_calc;
index f0cdb30921c0bdb5b1639e15d05908dfde6586f9..57bd978483e1fe47a96c964f356432e51e62d6b7 100644 (file)
@@ -367,7 +367,7 @@ static void __leaf_free_rcu(struct rcu_head *head)
 
 static inline void free_leaf(struct leaf *l)
 {
-       call_rcu_bh(&l->rcu, __leaf_free_rcu);
+       call_rcu(&l->rcu, __leaf_free_rcu);
 }
 
 static inline void free_leaf_info(struct leaf_info *leaf)
index db0cf17c00f7048030d4dcea41e2d8f088391cc1..7f75f21d7b8346e0279364c511117582f3c1f342 100644 (file)
@@ -404,12 +404,15 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
        struct inet_sock *newinet = inet_sk(newsk);
-       struct ip_options_rcu *opt = ireq->opt;
+       struct ip_options_rcu *opt;
        struct net *net = sock_net(sk);
        struct flowi4 *fl4;
        struct rtable *rt;
 
        fl4 = &newinet->cork.fl.u.ip4;
+
+       rcu_read_lock();
+       opt = rcu_dereference(newinet->inet_opt);
        flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
                           RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
                           sk->sk_protocol, inet_sk_flowi_flags(sk),
@@ -421,11 +424,13 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
                goto no_route;
        if (opt && opt->opt.is_strictroute && rt->rt_gateway)
                goto route_err;
+       rcu_read_unlock();
        return &rt->dst;
 
 route_err:
        ip_rt_put(rt);
 no_route:
+       rcu_read_unlock();
        IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
        return NULL;
 }
index ba39a52d18c1966209b02127ad7a4335479fcbdc..c196d749daf23b3823ffe012495ea5d9411be99a 100644 (file)
@@ -197,7 +197,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
        neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
        if (unlikely(!neigh))
                neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
-       if (neigh) {
+       if (!IS_ERR(neigh)) {
                int res = dst_neigh_output(dst, neigh, skb);
 
                rcu_read_unlock_bh();
@@ -1338,10 +1338,10 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
        iph->ihl = 5;
        iph->tos = inet->tos;
        iph->frag_off = df;
-       ip_select_ident(iph, &rt->dst, sk);
        iph->ttl = ttl;
        iph->protocol = sk->sk_protocol;
        ip_copy_addrs(iph, fl4);
+       ip_select_ident(iph, &rt->dst, sk);
 
        if (opt) {
                iph->ihl += opt->optlen>>2;
@@ -1366,9 +1366,8 @@ out:
        return skb;
 }
 
-int ip_send_skb(struct sk_buff *skb)
+int ip_send_skb(struct net *net, struct sk_buff *skb)
 {
-       struct net *net = sock_net(skb->sk);
        int err;
 
        err = ip_local_out(skb);
@@ -1391,7 +1390,7 @@ int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4)
                return 0;
 
        /* Netfilter gets whole the not fragmented skb. */
-       return ip_send_skb(skb);
+       return ip_send_skb(sock_net(sk), skb);
 }
 
 /*
@@ -1536,6 +1535,7 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
                          arg->csumoffset) = csum_fold(csum_add(nskb->csum,
                                                                arg->csum));
                nskb->ip_summed = CHECKSUM_NONE;
+               skb_orphan(nskb);
                skb_set_queue_mapping(nskb, skb_get_queue_mapping(skb));
                ip_push_pending_frames(sk, &fl4);
        }
index ea4a23813d26e66bf3c5e1513dbdb247b53a06dd..4ad9cf1739922cfb4b13d3135d01381dd70bf0be 100644 (file)
@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
        if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
                                    hdr, NULL, &matchoff, &matchlen,
                                    &addr, &port) > 0) {
-               unsigned int matchend, poff, plen, buflen, n;
+               unsigned int olen, matchend, poff, plen, buflen, n;
                char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
 
                /* We're only interested in headers related to this
@@ -163,17 +163,18 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
                                goto next;
                }
 
+               olen = *datalen;
                if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
                              &addr, port))
                        return NF_DROP;
 
-               matchend = matchoff + matchlen;
+               matchend = matchoff + matchlen + *datalen - olen;
 
                /* The maddr= parameter (RFC 2361) specifies where to send
                 * the reply. */
                if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
                                               "maddr=", &poff, &plen,
-                                              &addr) > 0 &&
+                                              &addr, true) > 0 &&
                    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
                    addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
                        buflen = sprintf(buffer, "%pI4",
@@ -187,7 +188,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
                 * from which the server received the request. */
                if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
                                               "received=", &poff, &plen,
-                                              &addr) > 0 &&
+                                              &addr, false) > 0 &&
                    addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
                    addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
                        buflen = sprintf(buffer, "%pI4",
index c035251beb070bb7f4220324a90e0ffeee8e103c..fd9ecb52c66bf8815c09e678c452017e9a7e2122 100644 (file)
@@ -70,7 +70,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/bootmem.h>
 #include <linux/string.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
@@ -80,7 +79,6 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
-#include <linux/workqueue.h>
 #include <linux/skbuff.h>
 #include <linux/inetdevice.h>
 #include <linux/igmp.h>
 #include <linux/mroute.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/random.h>
-#include <linux/jhash.h>
 #include <linux/rcupdate.h>
 #include <linux/times.h>
 #include <linux/slab.h>
-#include <linux/prefetch.h>
 #include <net/dst.h>
 #include <net/net_namespace.h>
 #include <net/protocol.h>
@@ -2032,7 +2028,6 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                }
                dev_out = net->loopback_dev;
                fl4->flowi4_oif = dev_out->ifindex;
-               res.fi = NULL;
                flags |= RTCF_LOCAL;
                goto make_route;
        }
index e7e6eeae49c0123d392fa16c7687c333b30b79b8..2109ff4a1dafd489fbe0e2240075432df4517374 100644 (file)
@@ -811,7 +811,9 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
                           old_size_goal + mss_now > xmit_size_goal)) {
                        xmit_size_goal = old_size_goal;
                } else {
-                       tp->xmit_size_goal_segs = xmit_size_goal / mss_now;
+                       tp->xmit_size_goal_segs =
+                               min_t(u16, xmit_size_goal / mss_now,
+                                     sk->sk_gso_max_segs);
                        xmit_size_goal = tp->xmit_size_goal_segs * mss_now;
                }
        }
index 4d4db16e336ea63c2b581079e5295a4a74924aab..1432cdb0644c2b16f893de842bcd3b9fdd3c5538 100644 (file)
@@ -291,7 +291,8 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
        left = tp->snd_cwnd - in_flight;
        if (sk_can_gso(sk) &&
            left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
-           left * tp->mss_cache < sk->sk_gso_max_size)
+           left * tp->mss_cache < sk->sk_gso_max_size &&
+           left < sk->sk_gso_max_segs)
                return true;
        return left <= tcp_max_tso_deferred_mss(tp);
 }
index 2fd2bc9e3c644d650282ea8c66a41fab9683167f..85308b90df80a844119a8cc773783f78aab5de04 100644 (file)
@@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
+       if (unlikely(sk->sk_rx_dst == NULL))
+               inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
        /*
         *      Header prediction.
         *      The code loosely follows the one in the famous
@@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
        tcp_set_state(sk, TCP_ESTABLISHED);
 
        if (skb != NULL) {
-               inet_sk_rx_dst_set(sk, skb);
+               icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
                security_inet_conn_established(sk, skb);
        }
 
index 42b2a6a73092a9a75bd96239af003269575328f5..00a748d14062d5f0410568be79aa6dc609a201be 100644 (file)
@@ -417,10 +417,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
 
                if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
                        tp->mtu_info = info;
-                       if (!sock_owned_by_user(sk))
+                       if (!sock_owned_by_user(sk)) {
                                tcp_v4_mtu_reduced(sk);
-                       else
-                               set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags);
+                       } else {
+                               if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags))
+                                       sock_hold(sk);
+                       }
                        goto out;
                }
 
@@ -1462,6 +1464,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                goto exit_nonewsk;
 
        newsk->sk_gso_type = SKB_GSO_TCPV4;
+       inet_sk_rx_dst_set(newsk, skb);
 
        newtp                 = tcp_sk(newsk);
        newinet               = inet_sk(newsk);
@@ -1627,9 +1630,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                                sk->sk_rx_dst = NULL;
                        }
                }
-               if (unlikely(sk->sk_rx_dst == NULL))
-                       inet_sk_rx_dst_set(sk, skb);
-
                if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
                        rsk = sk;
                        goto reset;
@@ -1872,10 +1872,21 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
        .twsk_destructor= tcp_twsk_destructor,
 };
 
+void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+
+       dst_hold(dst);
+       sk->sk_rx_dst = dst;
+       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+}
+EXPORT_SYMBOL(inet_sk_rx_dst_set);
+
 const struct inet_connection_sock_af_ops ipv4_specific = {
        .queue_xmit        = ip_queue_xmit,
        .send_check        = tcp_v4_send_check,
        .rebuild_header    = inet_sk_rebuild_header,
+       .sk_rx_dst_set     = inet_sk_rx_dst_set,
        .conn_request      = tcp_v4_conn_request,
        .syn_recv_sock     = tcp_v4_syn_recv_sock,
        .net_header_len    = sizeof(struct iphdr),
index 2288a6399e1e4fee43beebdc2817d38bea140bfb..0abe67bb4d3a3adb0d9df820b1fe64b6ef9da591 100644 (file)
@@ -731,6 +731,18 @@ static int __net_init tcp_net_metrics_init(struct net *net)
 
 static void __net_exit tcp_net_metrics_exit(struct net *net)
 {
+       unsigned int i;
+
+       for (i = 0; i < (1U << net->ipv4.tcp_metrics_hash_log) ; i++) {
+               struct tcp_metrics_block *tm, *next;
+
+               tm = rcu_dereference_protected(net->ipv4.tcp_metrics_hash[i].chain, 1);
+               while (tm) {
+                       next = rcu_dereference_protected(tm->tcpm_next, 1);
+                       kfree(tm);
+                       tm = next;
+               }
+       }
        kfree(net->ipv4.tcp_metrics_hash);
 }
 
index 232a90c3ec8695dfa740fe141ba113074f99a289..6ff7f10dce9d56c2f99f0cb13dab38f69eec4619 100644 (file)
@@ -387,8 +387,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                struct tcp_sock *oldtp = tcp_sk(sk);
                struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
 
-               inet_sk_rx_dst_set(newsk, skb);
-
                /* TCP Cookie Transactions require space for the cookie pair,
                 * as it differs for each connection.  There is no need to
                 * copy any s_data_payload stored at the original socket.
index 3f1bcff0b10b5d2daa0307de4ff29f0ba6ddb5cc..d04632673a9e5f27725731e420d0997d91259aef 100644 (file)
@@ -910,14 +910,18 @@ void tcp_release_cb(struct sock *sk)
        if (flags & (1UL << TCP_TSQ_DEFERRED))
                tcp_tsq_handler(sk);
 
-       if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED))
+       if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
                tcp_write_timer_handler(sk);
-
-       if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED))
+               __sock_put(sk);
+       }
+       if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED)) {
                tcp_delack_timer_handler(sk);
-
-       if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED))
+               __sock_put(sk);
+       }
+       if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) {
                sk->sk_prot->mtu_reduced(sk);
+               __sock_put(sk);
+       }
 }
 EXPORT_SYMBOL(tcp_release_cb);
 
@@ -940,7 +944,7 @@ void __init tcp_tasklet_init(void)
  * We cant xmit new skbs from this context, as we might already
  * hold qdisc lock.
  */
-void tcp_wfree(struct sk_buff *skb)
+static void tcp_wfree(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
        struct tcp_sock *tp = tcp_sk(sk);
@@ -1522,21 +1526,21 @@ static void tcp_cwnd_validate(struct sock *sk)
  * when we would be allowed to send the split-due-to-Nagle skb fully.
  */
 static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb,
-                                       unsigned int mss_now, unsigned int cwnd)
+                                       unsigned int mss_now, unsigned int max_segs)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
-       u32 needed, window, cwnd_len;
+       u32 needed, window, max_len;
 
        window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
-       cwnd_len = mss_now * cwnd;
+       max_len = mss_now * max_segs;
 
-       if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk)))
-               return cwnd_len;
+       if (likely(max_len <= window && skb != tcp_write_queue_tail(sk)))
+               return max_len;
 
        needed = min(skb->len, window);
 
-       if (cwnd_len <= needed)
-               return cwnd_len;
+       if (max_len <= needed)
+               return max_len;
 
        return needed - needed % mss_now;
 }
@@ -1765,7 +1769,8 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
        limit = min(send_win, cong_win);
 
        /* If a full-sized TSO skb can be sent, do it. */
-       if (limit >= sk->sk_gso_max_size)
+       if (limit >= min_t(unsigned int, sk->sk_gso_max_size,
+                          sk->sk_gso_max_segs * tp->mss_cache))
                goto send_now;
 
        /* Middle in queue won't get any more data, full sendable already? */
@@ -1999,7 +2004,9 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                limit = mss_now;
                if (tso_segs > 1 && !tcp_urg_mode(tp))
                        limit = tcp_mss_split_point(sk, skb, mss_now,
-                                                   cwnd_quota);
+                                                   min_t(unsigned int,
+                                                         cwnd_quota,
+                                                         sk->sk_gso_max_segs));
 
                if (skb->len > limit &&
                    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
index 6df36ad55a38714bb9def423661066bd798cf7b4..b774a03bd1dcc1ccafa245a892ac0b312511a900 100644 (file)
@@ -252,7 +252,8 @@ static void tcp_delack_timer(unsigned long data)
                inet_csk(sk)->icsk_ack.blocked = 1;
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
                /* deleguate our work to tcp_release_cb() */
-               set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags);
+               if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags))
+                       sock_hold(sk);
        }
        bh_unlock_sock(sk);
        sock_put(sk);
@@ -481,7 +482,8 @@ static void tcp_write_timer(unsigned long data)
                tcp_write_timer_handler(sk);
        } else {
                /* deleguate our work to tcp_release_cb() */
-               set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags);
+               if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags))
+                       sock_hold(sk);
        }
        bh_unlock_sock(sk);
        sock_put(sk);
index b4c3582a991f94db7f6047d5b514b062ccf7e43d..6f6d1aca3c3de0e21036c075c0a13c429ef4f8ae 100644 (file)
@@ -758,7 +758,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
                uh->check = CSUM_MANGLED_0;
 
 send:
-       err = ip_send_skb(skb);
+       err = ip_send_skb(sock_net(sk), skb);
        if (err) {
                if (err == -ENOBUFS && !inet->recverr) {
                        UDP_INC_STATS_USER(sock_net(sk),
index 79181819a24fa7d3ed67b5a4c22d44e51945da63..6bc85f7c31e3c58a01a6d1aa351cd827584fad24 100644 (file)
@@ -494,8 +494,7 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
        struct net_device *dev;
        struct inet6_dev *idev;
 
-       rcu_read_lock();
-       for_each_netdev_rcu(net, dev) {
+       for_each_netdev(net, dev) {
                idev = __in6_dev_get(dev);
                if (idev) {
                        int changed = (!idev->cnf.forwarding) ^ (!newf);
@@ -504,7 +503,6 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
                                dev_forward_change(idev);
                }
        }
-       rcu_read_unlock();
 }
 
 static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
index da2e92d05c15a5052ea2cc19ba9bfc5751c23cf6..745a32042950127f3509781b6247b6434743d1d7 100644 (file)
@@ -307,10 +307,10 @@ static int __net_init ipv6_proc_init_net(struct net *net)
                goto proc_dev_snmp6_fail;
        return 0;
 
+proc_dev_snmp6_fail:
+       proc_net_remove(net, "snmp6");
 proc_snmp6_fail:
        proc_net_remove(net, "sockstat6");
-proc_dev_snmp6_fail:
-       proc_net_remove(net, "dev_snmp6");
        return -ENOMEM;
 }
 
index c66b90f71c9b9610b5dec49c038b80dffd836058..a3e60cc04a8a17e229afb44f38643ed86ac0c63e 100644 (file)
@@ -94,6 +94,18 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
 }
 #endif
 
+static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+       const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+       dst_hold(dst);
+       sk->sk_rx_dst = dst;
+       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+       if (rt->rt6i_node)
+               inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+}
+
 static void tcp_v6_hash(struct sock *sk)
 {
        if (sk->sk_state != TCP_CLOSE) {
@@ -1270,6 +1282,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        newsk->sk_gso_type = SKB_GSO_TCPV6;
        __ip6_dst_store(newsk, dst, NULL, NULL);
+       inet6_sk_rx_dst_set(newsk, skb);
 
        newtcp6sk = (struct tcp6_sock *)newsk;
        inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
@@ -1447,7 +1460,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
 
        if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+               struct dst_entry *dst = sk->sk_rx_dst;
+
                sock_rps_save_rxhash(sk, skb);
+               if (dst) {
+                       if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
+                           dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
+                               dst_release(dst);
+                               sk->sk_rx_dst = NULL;
+                       }
+               }
+
                if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
                        goto reset;
                if (opt_skb)
@@ -1705,9 +1728,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
                        struct dst_entry *dst = sk->sk_rx_dst;
                        struct inet_sock *icsk = inet_sk(sk);
                        if (dst)
-                               dst = dst_check(dst, 0);
+                               dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
                        if (dst &&
-                           icsk->rx_dst_ifindex == inet6_iif(skb))
+                           icsk->rx_dst_ifindex == skb->skb_iif)
                                skb_dst_set_noref(skb, dst);
                }
        }
@@ -1723,6 +1746,7 @@ static const struct inet_connection_sock_af_ops ipv6_specific = {
        .queue_xmit        = inet6_csk_xmit,
        .send_check        = tcp_v6_send_check,
        .rebuild_header    = inet6_sk_rebuild_header,
+       .sk_rx_dst_set     = inet6_sk_rx_dst_set,
        .conn_request      = tcp_v6_conn_request,
        .syn_recv_sock     = tcp_v6_syn_recv_sock,
        .net_header_len    = sizeof(struct ipv6hdr),
@@ -1754,6 +1778,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = {
        .queue_xmit        = ip_queue_xmit,
        .send_check        = tcp_v4_send_check,
        .rebuild_header    = inet_sk_rebuild_header,
+       .sk_rx_dst_set     = inet_sk_rx_dst_set,
        .conn_request      = tcp_v6_conn_request,
        .syn_recv_sock     = tcp_v6_syn_recv_sock,
        .net_header_len    = sizeof(struct iphdr),
index ef39812107b17c2c90c38e24df363e76008dd745..f8c4c08ffb609d2840adb721e395fcbe99a636d7 100644 (file)
@@ -73,6 +73,13 @@ static int xfrm6_get_tos(const struct flowi *fl)
        return 0;
 }
 
+static void xfrm6_init_dst(struct net *net, struct xfrm_dst *xdst)
+{
+       struct rt6_info *rt = (struct rt6_info *)xdst;
+
+       rt6_init_peer(rt, net->ipv6.peers);
+}
+
 static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
                           int nfheader_len)
 {
@@ -286,6 +293,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
        .get_saddr =            xfrm6_get_saddr,
        .decode_session =       _decode_session6,
        .get_tos =              xfrm6_get_tos,
+       .init_dst =             xfrm6_init_dst,
        .init_path =            xfrm6_init_path,
        .fill_dst =             xfrm6_fill_dst,
        .blackhole_route =      ip6_blackhole_route,
index 35e1e4bde58730d8395e2870d552230bca3a9c3d..927547171bc7119f57a7b8afecf453ec5eeabf61 100644 (file)
@@ -410,6 +410,7 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
        lsa->l2tp_family = AF_INET6;
        lsa->l2tp_flowinfo = 0;
        lsa->l2tp_scope_id = 0;
+       lsa->l2tp_unused = 0;
        if (peer) {
                if (!lsk->peer_conn_id)
                        return -ENOTCONN;
index f6fe4d400502df780e1f57e574e5b4a1574b7f8d..c2190005a11410e2f95141fb841dadc051157a8b 100644 (file)
@@ -969,14 +969,13 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
        struct sockaddr_llc sllc;
        struct sock *sk = sock->sk;
        struct llc_sock *llc = llc_sk(sk);
-       int rc = 0;
+       int rc = -EBADF;
 
        memset(&sllc, 0, sizeof(sllc));
        lock_sock(sk);
        if (sock_flag(sk, SOCK_ZAPPED))
                goto out;
        *uaddrlen = sizeof(sllc);
-       memset(uaddr, 0, *uaddrlen);
        if (peer) {
                rc = -ENOTCONN;
                if (sk->sk_state != TCP_ESTABLISHED)
@@ -1206,7 +1205,7 @@ static int __init llc2_init(void)
        rc = llc_proc_init();
        if (rc != 0) {
                printk(llc_proc_err_msg);
-               goto out_unregister_llc_proto;
+               goto out_station;
        }
        rc = llc_sysctl_init();
        if (rc) {
@@ -1226,7 +1225,8 @@ out_sysctl:
        llc_sysctl_exit();
 out_proc:
        llc_proc_exit();
-out_unregister_llc_proto:
+out_station:
+       llc_station_exit();
        proto_unregister(&llc_proto);
        goto out;
 }
index e32cab44ea959d8f49781d46580b4204afb7e3cb..dd3e83328ad544d3183233da61fa40289975de51 100644 (file)
@@ -42,6 +42,7 @@ static void (*llc_type_handlers[2])(struct llc_sap *sap,
 void llc_add_pack(int type, void (*handler)(struct llc_sap *sap,
                                            struct sk_buff *skb))
 {
+       smp_wmb(); /* ensure initialisation is complete before it's called */
        if (type == LLC_DEST_SAP || type == LLC_DEST_CONN)
                llc_type_handlers[type - 1] = handler;
 }
@@ -50,11 +51,19 @@ void llc_remove_pack(int type)
 {
        if (type == LLC_DEST_SAP || type == LLC_DEST_CONN)
                llc_type_handlers[type - 1] = NULL;
+       synchronize_net();
 }
 
 void llc_set_station_handler(void (*handler)(struct sk_buff *skb))
 {
+       /* Ensure initialisation is complete before it's called */
+       if (handler)
+               smp_wmb();
+
        llc_station_handler = handler;
+
+       if (!handler)
+               synchronize_net();
 }
 
 /**
@@ -150,6 +159,8 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
        int dest;
        int (*rcv)(struct sk_buff *, struct net_device *,
                   struct packet_type *, struct net_device *);
+       void (*sta_handler)(struct sk_buff *skb);
+       void (*sap_handler)(struct llc_sap *sap, struct sk_buff *skb);
 
        if (!net_eq(dev_net(dev), &init_net))
                goto drop;
@@ -182,7 +193,8 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
         */
        rcv = rcu_dereference(sap->rcv_func);
        dest = llc_pdu_type(skb);
-       if (unlikely(!dest || !llc_type_handlers[dest - 1])) {
+       sap_handler = dest ? ACCESS_ONCE(llc_type_handlers[dest - 1]) : NULL;
+       if (unlikely(!sap_handler)) {
                if (rcv)
                        rcv(skb, dev, pt, orig_dev);
                else
@@ -193,7 +205,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
                        if (cskb)
                                rcv(cskb, dev, pt, orig_dev);
                }
-               llc_type_handlers[dest - 1](sap, skb);
+               sap_handler(sap, skb);
        }
        llc_sap_put(sap);
 out:
@@ -202,9 +214,10 @@ drop:
        kfree_skb(skb);
        goto out;
 handle_station:
-       if (!llc_station_handler)
+       sta_handler = ACCESS_ONCE(llc_station_handler);
+       if (!sta_handler)
                goto drop;
-       llc_station_handler(skb);
+       sta_handler(skb);
        goto out;
 }
 
index 39a8d8924b9c989747502774a4360b78e98d6ba4..b2f2bac2c2a2397b5fd6f6b79659996270b96377 100644 (file)
@@ -268,7 +268,7 @@ static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb)
 out:
        return rc;
 free:
-       kfree_skb(skb);
+       kfree_skb(nskb);
        goto out;
 }
 
@@ -293,7 +293,7 @@ static int llc_station_ac_send_xid_r(struct sk_buff *skb)
 out:
        return rc;
 free:
-       kfree_skb(skb);
+       kfree_skb(nskb);
        goto out;
 }
 
@@ -322,7 +322,7 @@ static int llc_station_ac_send_test_r(struct sk_buff *skb)
 out:
        return rc;
 free:
-       kfree_skb(skb);
+       kfree_skb(nskb);
        goto out;
 }
 
@@ -687,12 +687,8 @@ static void llc_station_rcv(struct sk_buff *skb)
        llc_station_state_process(skb);
 }
 
-int __init llc_station_init(void)
+void __init llc_station_init(void)
 {
-       int rc = -ENOBUFS;
-       struct sk_buff *skb;
-       struct llc_station_state_ev *ev;
-
        skb_queue_head_init(&llc_main_station.mac_pdu_q);
        skb_queue_head_init(&llc_main_station.ev_q.list);
        spin_lock_init(&llc_main_station.ev_q.lock);
@@ -700,23 +696,12 @@ int __init llc_station_init(void)
                        (unsigned long)&llc_main_station);
        llc_main_station.ack_timer.expires  = jiffies +
                                                sysctl_llc_station_ack_timeout;
-       skb = alloc_skb(0, GFP_ATOMIC);
-       if (!skb)
-               goto out;
-       rc = 0;
-       llc_set_station_handler(llc_station_rcv);
-       ev = llc_station_ev(skb);
-       memset(ev, 0, sizeof(*ev));
        llc_main_station.maximum_retry  = 1;
-       llc_main_station.state          = LLC_STATION_STATE_DOWN;
-       ev->type        = LLC_STATION_EV_TYPE_SIMPLE;
-       ev->prim_type   = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
-       rc = llc_station_next_state(skb);
-out:
-       return rc;
+       llc_main_station.state          = LLC_STATION_STATE_UP;
+       llc_set_station_handler(llc_station_rcv);
 }
 
-void __exit llc_station_exit(void)
+void llc_station_exit(void)
 {
        llc_set_station_handler(NULL);
 }
index 6fac18c0423ff391213de03242299ff3b1e4b965..85572353a7e37d59b64ced140d75f7a9b8d3fb81 100644 (file)
@@ -622,6 +622,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 
        del_timer_sync(&sdata->u.mesh.housekeeping_timer);
        del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
+       del_timer_sync(&sdata->u.mesh.mesh_path_timer);
        /*
         * If the timer fired while we waited for it, it will have
         * requeued the work. Now the work will be running again
@@ -634,6 +635,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        local->fif_other_bss--;
        atomic_dec(&local->iff_allmultis);
        ieee80211_configure_filter(local);
+
+       sdata->u.mesh.timers_running = 0;
 }
 
 static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
index cef0c9e79aba5ff4657938478dea6e829e10b164..a4a5acdbaa4dd3ac5e2fb8c5f0ff1d1b97553d6a 100644 (file)
@@ -1430,6 +1430,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
        del_timer_sync(&sdata->u.mgd.timer);
        del_timer_sync(&sdata->u.mgd.chswitch_timer);
+
+       sdata->u.mgd.timers_running = 0;
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
index bcaee5d1283915efdbc8c63f4365c7ed42d486dc..839dd9737989ec78bbb979c814953b1bdd0187a8 100644 (file)
@@ -299,7 +299,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        if (local->scan_req != local->int_scan_req)
                cfg80211_scan_done(local->scan_req, aborted);
        local->scan_req = NULL;
-       local->scan_sdata = NULL;
+       rcu_assign_pointer(local->scan_sdata, NULL);
 
        local->scanning = 0;
        local->scan_channel = NULL;
@@ -984,7 +984,6 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
                        kfree(local->sched_scan_ies.ie[i]);
 
                drv_sched_scan_stop(local, sdata);
-               rcu_assign_pointer(local->sched_scan_sdata, NULL);
        }
 out:
        mutex_unlock(&local->mtx);
index 84444dda194b61806efaeadde4c2458f502d8283..72bf32a84874718927a4bcbdc2e26395be00bdd8 100644 (file)
@@ -2759,6 +2759,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        {
                struct ip_vs_timeout_user t;
 
+               memset(&t, 0, sizeof(t));
                __ip_vs_get_timeouts(net, &t);
                if (copy_to_user(user, &t, sizeof(t)) != 0)
                        ret = -EFAULT;
index 45cf602a76bc1f030f1a1870679ec07d62250eee..527651a53a45ded66c97162f4e072ca55a7d1efa 100644 (file)
@@ -361,23 +361,6 @@ static void evict_oldest_expect(struct nf_conn *master,
        }
 }
 
-static inline int refresh_timer(struct nf_conntrack_expect *i)
-{
-       struct nf_conn_help *master_help = nfct_help(i->master);
-       const struct nf_conntrack_expect_policy *p;
-
-       if (!del_timer(&i->timeout))
-               return 0;
-
-       p = &rcu_dereference_protected(
-               master_help->helper,
-               lockdep_is_held(&nf_conntrack_lock)
-               )->expect_policy[i->class];
-       i->timeout.expires = jiffies + p->timeout * HZ;
-       add_timer(&i->timeout);
-       return 1;
-}
-
 static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
 {
        const struct nf_conntrack_expect_policy *p;
@@ -386,7 +369,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        struct nf_conn_help *master_help = nfct_help(master);
        struct nf_conntrack_helper *helper;
        struct net *net = nf_ct_exp_net(expect);
-       struct hlist_node *n;
+       struct hlist_node *n, *next;
        unsigned int h;
        int ret = 1;
 
@@ -395,12 +378,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
                goto out;
        }
        h = nf_ct_expect_dst_hash(&expect->tuple);
-       hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
+       hlist_for_each_entry_safe(i, n, next, &net->ct.expect_hash[h], hnode) {
                if (expect_matches(i, expect)) {
-                       /* Refresh timer: if it's dying, ignore.. */
-                       if (refresh_timer(i)) {
-                               ret = 0;
-                               goto out;
+                       if (del_timer(&i->timeout)) {
+                               nf_ct_unlink_expect(i);
+                               nf_ct_expect_put(i);
+                               break;
                        }
                } else if (expect_clash(i, expect)) {
                        ret = -EBUSY;
index 14f67a2cbcb5f065e2b4eab61a59c2447c6826d7..da4fc37a8578b6ef4590cbd0abf6e04241ebb8fc 100644 (file)
@@ -1896,10 +1896,15 @@ static int
 ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
 {
        struct nlattr *cda[CTA_MAX+1];
+       int ret;
 
        nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
 
-       return ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
+       spin_lock_bh(&nf_conntrack_lock);
+       ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
+       spin_unlock_bh(&nf_conntrack_lock);
+
+       return ret;
 }
 
 static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
index 758a1bacc126468a4a495748eb034ac80ed65d01..5c0a112aeee6adc580f0303b50e6821d12e8839e 100644 (file)
@@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr,
        return len + digits_len(ct, dptr, limit, shift);
 }
 
-static int parse_addr(const struct nf_conn *ct, const char *cp,
-                      const char **endp, union nf_inet_addr *addr,
-                      const char *limit)
+static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
+                         const char **endp, union nf_inet_addr *addr,
+                         const char *limit, bool delim)
 {
        const char *end;
-       int ret = 0;
+       int ret;
 
        if (!ct)
                return 0;
@@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp,
        switch (nf_ct_l3num(ct)) {
        case AF_INET:
                ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
+               if (ret == 0)
+                       return 0;
                break;
        case AF_INET6:
+               if (cp < limit && *cp == '[')
+                       cp++;
+               else if (delim)
+                       return 0;
+
                ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
+               if (ret == 0)
+                       return 0;
+
+               if (end < limit && *end == ']')
+                       end++;
+               else if (delim)
+                       return 0;
                break;
        default:
                BUG();
        }
 
-       if (ret == 0 || end == cp)
-               return 0;
        if (endp)
                *endp = end;
        return 1;
@@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
        union nf_inet_addr addr;
        const char *aux = dptr;
 
-       if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
+       if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) {
                pr_debug("ip: %s parse failed.!\n", dptr);
                return 0;
        }
@@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct,
                return 0;
        dptr += shift;
 
-       if (!parse_addr(ct, dptr, &end, addr, limit))
+       if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
                return -1;
        if (end < limit && *end == ':') {
                end++;
@@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
        if (ret == 0)
                return ret;
 
-       if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
+       if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
                return -1;
        if (*c == ':') {
                c++;
@@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
                               unsigned int dataoff, unsigned int datalen,
                               const char *name,
                               unsigned int *matchoff, unsigned int *matchlen,
-                              union nf_inet_addr *addr)
+                              union nf_inet_addr *addr, bool delim)
 {
        const char *limit = dptr + datalen;
        const char *start, *end;
@@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
                return 0;
 
        start += strlen(name);
-       if (!parse_addr(ct, start, &end, addr, limit))
+       if (!sip_parse_addr(ct, start, &end, addr, limit, delim))
                return 0;
        *matchoff = start - dptr;
        *matchlen = end - start;
@@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
        return 1;
 }
 
+static int sdp_parse_addr(const struct nf_conn *ct, const char *cp,
+                         const char **endp, union nf_inet_addr *addr,
+                         const char *limit)
+{
+       const char *end;
+       int ret;
+
+       memset(addr, 0, sizeof(*addr));
+       switch (nf_ct_l3num(ct)) {
+       case AF_INET:
+               ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
+               break;
+       case AF_INET6:
+               ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
+               break;
+       default:
+               BUG();
+       }
+
+       if (ret == 0)
+               return 0;
+       if (endp)
+               *endp = end;
+       return 1;
+}
+
+/* skip ip address. returns its length. */
+static int sdp_addr_len(const struct nf_conn *ct, const char *dptr,
+                       const char *limit, int *shift)
+{
+       union nf_inet_addr addr;
+       const char *aux = dptr;
+
+       if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) {
+               pr_debug("ip: %s parse failed.!\n", dptr);
+               return 0;
+       }
+
+       return dptr - aux;
+}
+
 /* SDP header parsing: a SDP session description contains an ordered set of
  * headers, starting with a section containing general session parameters,
  * optionally followed by multiple media descriptions.
@@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
  */
 static const struct sip_header ct_sdp_hdrs[] = {
        [SDP_HDR_VERSION]               = SDP_HDR("v=", NULL, digits_len),
-       [SDP_HDR_OWNER_IP4]             = SDP_HDR("o=", "IN IP4 ", epaddr_len),
-       [SDP_HDR_CONNECTION_IP4]        = SDP_HDR("c=", "IN IP4 ", epaddr_len),
-       [SDP_HDR_OWNER_IP6]             = SDP_HDR("o=", "IN IP6 ", epaddr_len),
-       [SDP_HDR_CONNECTION_IP6]        = SDP_HDR("c=", "IN IP6 ", epaddr_len),
+       [SDP_HDR_OWNER_IP4]             = SDP_HDR("o=", "IN IP4 ", sdp_addr_len),
+       [SDP_HDR_CONNECTION_IP4]        = SDP_HDR("c=", "IN IP4 ", sdp_addr_len),
+       [SDP_HDR_OWNER_IP6]             = SDP_HDR("o=", "IN IP6 ", sdp_addr_len),
+       [SDP_HDR_CONNECTION_IP6]        = SDP_HDR("c=", "IN IP6 ", sdp_addr_len),
        [SDP_HDR_MEDIA]                 = SDP_HDR("m=", NULL, media_len),
 };
 
@@ -775,8 +828,8 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr,
        if (ret <= 0)
                return ret;
 
-       if (!parse_addr(ct, dptr + *matchoff, NULL, addr,
-                       dptr + *matchoff + *matchlen))
+       if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr,
+                           dptr + *matchoff + *matchlen))
                return -1;
        return 1;
 }
@@ -1515,7 +1568,6 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff,
 }
 
 static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly;
-static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly;
 
 static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
        [SIP_EXPECT_SIGNALLING] = {
@@ -1585,9 +1637,9 @@ static int __init nf_conntrack_sip_init(void)
                        sip[i][j].me = THIS_MODULE;
 
                        if (ports[i] == SIP_PORT)
-                               sprintf(sip_names[i][j], "sip");
+                               sprintf(sip[i][j].name, "sip");
                        else
-                               sprintf(sip_names[i][j], "sip-%u", i);
+                               sprintf(sip[i][j].name, "sip-%u", i);
 
                        pr_debug("port #%u: %u\n", i, ports[i]);
 
index 5463969da45b9a30dbbb1802624b0e9e8bf92a29..1445d73533ed13ac9aa43dd85d6f58b4a006c130 100644 (file)
@@ -1362,7 +1362,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
        if (NULL == siocb->scm)
                siocb->scm = &scm;
 
-       err = scm_send(sock, msg, siocb->scm);
+       err = scm_send(sock, msg, siocb->scm, true);
        if (err < 0)
                return err;
 
index ceaca7c134a011b659bc439dff6de58269b532b4..aee7196aac36c990eedfc7b494a04351c29bb167 100644 (file)
@@ -1079,7 +1079,7 @@ static void *packet_current_rx_frame(struct packet_sock *po,
        default:
                WARN(1, "TPACKET version not supported\n");
                BUG();
-               return 0;
+               return NULL;
        }
 }
 
@@ -1273,6 +1273,14 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
        spin_unlock(&f->lock);
 }
 
+bool match_fanout_group(struct packet_type *ptype, struct sock * sk)
+{
+       if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout)
+               return true;
+
+       return false;
+}
+
 static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
 {
        struct packet_sock *po = pkt_sk(sk);
@@ -1325,6 +1333,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
                match->prot_hook.dev = po->prot_hook.dev;
                match->prot_hook.func = packet_rcv_fanout;
                match->prot_hook.af_packet_priv = match;
+               match->prot_hook.id_match = match_fanout_group;
                dev_add_pack(&match->prot_hook);
                list_add(&match->list, &fanout_list);
        }
@@ -1936,7 +1945,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
 
        if (likely(po->tx_ring.pg_vec)) {
                ph = skb_shinfo(skb)->destructor_arg;
-               BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING);
                BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
                atomic_dec(&po->tx_ring.pending);
                __packet_set_status(po, ph, TP_STATUS_AVAILABLE);
index f10fb8256442014afbba6b85a23a3544ee0ec9e4..05d60859d8e3d1c2eb700ff7d1d63d81d9f98894 100644 (file)
@@ -67,6 +67,9 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
        struct tcf_common *pc;
        int ret = 0;
        int err;
+#ifdef CONFIG_GACT_PROB
+       struct tc_gact_p *p_parm = NULL;
+#endif
 
        if (nla == NULL)
                return -EINVAL;
@@ -82,6 +85,12 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
 #ifndef CONFIG_GACT_PROB
        if (tb[TCA_GACT_PROB] != NULL)
                return -EOPNOTSUPP;
+#else
+       if (tb[TCA_GACT_PROB]) {
+               p_parm = nla_data(tb[TCA_GACT_PROB]);
+               if (p_parm->ptype >= MAX_RAND)
+                       return -EINVAL;
+       }
 #endif
 
        pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
@@ -103,8 +112,7 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
        spin_lock_bh(&gact->tcf_lock);
        gact->tcf_action = parm->action;
 #ifdef CONFIG_GACT_PROB
-       if (tb[TCA_GACT_PROB] != NULL) {
-               struct tc_gact_p *p_parm = nla_data(tb[TCA_GACT_PROB]);
+       if (p_parm) {
                gact->tcfg_paction = p_parm->paction;
                gact->tcfg_pval    = p_parm->pval;
                gact->tcfg_ptype   = p_parm->ptype;
@@ -133,7 +141,7 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a,
 
        spin_lock(&gact->tcf_lock);
 #ifdef CONFIG_GACT_PROB
-       if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL)
+       if (gact->tcfg_ptype)
                action = gact_rand[gact->tcfg_ptype](gact);
        else
                action = gact->tcf_action;
index 60e281ad0f07292d5b60b0501e465c1316df433a..58fb3c7aab9eea8a0e65851948dd3d81da4fe3b8 100644 (file)
@@ -185,7 +185,12 @@ err3:
 err2:
        kfree(tname);
 err1:
-       kfree(pc);
+       if (ret == ACT_P_CREATED) {
+               if (est)
+                       gen_kill_estimator(&pc->tcfc_bstats,
+                                          &pc->tcfc_rate_est);
+               kfree_rcu(pc, tcfc_rcu);
+       }
        return err;
 }
 
index fe81cc18e9e0dd20624aa4a6e7aa5aa098f737fc..9c0fd0c788145c0b6fa877463022f5ec90a707e2 100644 (file)
@@ -200,13 +200,12 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
 out:
        if (err) {
                m->tcf_qstats.overlimits++;
-               /* should we be asking for packet to be dropped?
-                * may make sense for redirect case only
-                */
-               retval = TC_ACT_SHOT;
-       } else {
+               if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
+                       retval = TC_ACT_SHOT;
+               else
+                       retval = m->tcf_action;
+       } else
                retval = m->tcf_action;
-       }
        spin_unlock(&m->tcf_lock);
 
        return retval;
index 26aa2f6ce257c5b39541df44db40c950fcd67045..45c53ab067a63240357a970e15ab2633802211d6 100644 (file)
@@ -74,7 +74,10 @@ static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est,
                p = to_pedit(pc);
                keys = kmalloc(ksize, GFP_KERNEL);
                if (keys == NULL) {
-                       kfree(pc);
+                       if (est)
+                               gen_kill_estimator(&pc->tcfc_bstats,
+                                                  &pc->tcfc_rate_est);
+                       kfree_rcu(pc, tcfc_rcu);
                        return -ENOMEM;
                }
                ret = ACT_P_CREATED;
index 3922f2a2821b83cf3f9db318980a7cad06111e1f..3714f60f0b3c5869725e449de8456ec9bd6b20fe 100644 (file)
@@ -131,7 +131,10 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
                d = to_defact(pc);
                ret = alloc_defdata(d, defdata);
                if (ret < 0) {
-                       kfree(pc);
+                       if (est)
+                               gen_kill_estimator(&pc->tcfc_bstats,
+                                                  &pc->tcfc_rate_est);
+                       kfree_rcu(pc, tcfc_rcu);
                        return ret;
                }
                d->tcf_action = parm->action;
index 9af01f3df18c66b6325c8afe628758b56e306952..e4723d31fdd56d6a46b2519afd19d612c7336749 100644 (file)
@@ -203,6 +203,34 @@ out:
        return index;
 }
 
+/* Length of the next packet (0 if the queue is empty). */
+static unsigned int qdisc_peek_len(struct Qdisc *sch)
+{
+       struct sk_buff *skb;
+
+       skb = sch->ops->peek(sch);
+       return skb ? qdisc_pkt_len(skb) : 0;
+}
+
+static void qfq_deactivate_class(struct qfq_sched *, struct qfq_class *);
+static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl,
+                              unsigned int len);
+
+static void qfq_update_class_params(struct qfq_sched *q, struct qfq_class *cl,
+                                   u32 lmax, u32 inv_w, int delta_w)
+{
+       int i;
+
+       /* update qfq-specific data */
+       cl->lmax = lmax;
+       cl->inv_w = inv_w;
+       i = qfq_calc_index(cl->inv_w, cl->lmax);
+
+       cl->grp = &q->groups[i];
+
+       q->wsum += delta_w;
+}
+
 static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                            struct nlattr **tca, unsigned long *arg)
 {
@@ -250,6 +278,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                lmax = 1UL << QFQ_MTU_SHIFT;
 
        if (cl != NULL) {
+               bool need_reactivation = false;
+
                if (tca[TCA_RATE]) {
                        err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
                                                    qdisc_root_sleeping_lock(sch),
@@ -258,12 +288,29 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                                return err;
                }
 
-               if (inv_w != cl->inv_w) {
-                       sch_tree_lock(sch);
-                       q->wsum += delta_w;
-                       cl->inv_w = inv_w;
-                       sch_tree_unlock(sch);
+               if (lmax == cl->lmax && inv_w == cl->inv_w)
+                       return 0; /* nothing to update */
+
+               i = qfq_calc_index(inv_w, lmax);
+               sch_tree_lock(sch);
+               if (&q->groups[i] != cl->grp && cl->qdisc->q.qlen > 0) {
+                       /*
+                        * shift cl->F back, to not charge the
+                        * class for the not-yet-served head
+                        * packet
+                        */
+                       cl->F = cl->S;
+                       /* remove class from its slot in the old group */
+                       qfq_deactivate_class(q, cl);
+                       need_reactivation = true;
                }
+
+               qfq_update_class_params(q, cl, lmax, inv_w, delta_w);
+
+               if (need_reactivation) /* activate in new group */
+                       qfq_activate_class(q, cl, qdisc_peek_len(cl->qdisc));
+               sch_tree_unlock(sch);
+
                return 0;
        }
 
@@ -273,11 +320,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 
        cl->refcnt = 1;
        cl->common.classid = classid;
-       cl->lmax = lmax;
-       cl->inv_w = inv_w;
-       i = qfq_calc_index(cl->inv_w, cl->lmax);
 
-       cl->grp = &q->groups[i];
+       qfq_update_class_params(q, cl, lmax, inv_w, delta_w);
 
        cl->qdisc = qdisc_create_dflt(sch->dev_queue,
                                      &pfifo_qdisc_ops, classid);
@@ -294,7 +338,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                        return err;
                }
        }
-       q->wsum += weight;
 
        sch_tree_lock(sch);
        qdisc_class_hash_insert(&q->clhash, &cl->common);
@@ -711,15 +754,6 @@ static void qfq_update_eligible(struct qfq_sched *q, u64 old_V)
        }
 }
 
-/* What is length of next packet in queue (0 if queue is empty) */
-static unsigned int qdisc_peek_len(struct Qdisc *sch)
-{
-       struct sk_buff *skb;
-
-       skb = sch->ops->peek(sch);
-       return skb ? qdisc_pkt_len(skb) : 0;
-}
-
 /*
  * Updates the class, returns true if also the group needs to be updated.
  */
@@ -843,11 +877,8 @@ static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl)
 static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct qfq_sched *q = qdisc_priv(sch);
-       struct qfq_group *grp;
        struct qfq_class *cl;
        int err;
-       u64 roundedS;
-       int s;
 
        cl = qfq_classify(skb, sch, &err);
        if (cl == NULL) {
@@ -876,11 +907,25 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
 
        /* If reach this point, queue q was idle */
-       grp = cl->grp;
+       qfq_activate_class(q, cl, qdisc_pkt_len(skb));
+
+       return err;
+}
+
+/*
+ * Handle class switch from idle to backlogged.
+ */
+static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl,
+                              unsigned int pkt_len)
+{
+       struct qfq_group *grp = cl->grp;
+       u64 roundedS;
+       int s;
+
        qfq_update_start(q, cl);
 
        /* compute new finish time and rounded start. */
-       cl->F = cl->S + (u64)qdisc_pkt_len(skb) * cl->inv_w;
+       cl->F = cl->S + (u64)pkt_len * cl->inv_w;
        roundedS = qfq_round_down(cl->S, grp->slot_shift);
 
        /*
@@ -917,8 +962,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
 skip_update:
        qfq_slot_insert(grp, cl, roundedS);
-
-       return err;
 }
 
 
index dfe5b66c97e0bc836efed43ad080dec620301306..a5471f804d994ece8c31df6be0e04d5076b6dfd0 100644 (file)
@@ -2657,6 +2657,7 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
        if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
                return -EFAULT;
 
+       memset(&ifc, 0, sizeof(ifc));
        if (ifc32.ifcbuf == 0) {
                ifc32.ifc_len = 0;
                ifc.ifc_len = 0;
index e4768c180da237c176e2e9491091a94420f4febe..c5ee4ff613641b3f8439f1c9cb6b22d55a1ff7f2 100644 (file)
@@ -1450,7 +1450,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
        wait_for_unix_gc();
-       err = scm_send(sock, msg, siocb->scm);
+       err = scm_send(sock, msg, siocb->scm, false);
        if (err < 0)
                return err;
 
@@ -1619,7 +1619,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
        wait_for_unix_gc();
-       err = scm_send(sock, msg, siocb->scm);
+       err = scm_send(sock, msg, siocb->scm, false);
        if (err < 0)
                return err;
 
index 31b40cc4a9c3c59bac7986e3c5c8725153381179..dcd64d5b07aadfba26a799506452a9b04fe8e7d3 100644 (file)
@@ -952,6 +952,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                 */
                synchronize_rcu();
                INIT_LIST_HEAD(&wdev->list);
+               /*
+                * Ensure that all events have been processed and
+                * freed.
+                */
+               cfg80211_process_wdev_events(wdev);
                break;
        case NETDEV_PRE_UP:
                if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
index 5206c6844fd735b5aac540a3afe7337ce79963d7..bc7430b54771af18e903ee1d263ede3b4eb1b78f 100644 (file)
@@ -426,6 +426,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                          struct net_device *dev, enum nl80211_iftype ntype,
                          u32 *flags, struct vif_params *params);
 void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
+void cfg80211_process_wdev_events(struct wireless_dev *wdev);
 
 int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
index 2303ee73b50ad2fc40dc136c9250861e9bb890ee..2ded3c7fad063a067151595c774b9bddd14bdc9a 100644 (file)
@@ -680,6 +680,8 @@ static u32 map_regdom_flags(u32 rd_flags)
                channel_flags |= IEEE80211_CHAN_NO_IBSS;
        if (rd_flags & NL80211_RRF_DFS)
                channel_flags |= IEEE80211_CHAN_RADAR;
+       if (rd_flags & NL80211_RRF_NO_OFDM)
+               channel_flags |= IEEE80211_CHAN_NO_OFDM;
        return channel_flags;
 }
 
@@ -901,7 +903,21 @@ static void handle_channel(struct wiphy *wiphy,
        chan->max_antenna_gain = min(chan->orig_mag,
                (int) MBI_TO_DBI(power_rule->max_antenna_gain));
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
-       chan->max_power = min(chan->max_power, chan->max_reg_power);
+       if (chan->orig_mpwr) {
+               /*
+                * Devices that have their own custom regulatory domain
+                * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the
+                * passed country IE power settings.
+                */
+               if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
+                   wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+                       chan->max_power = chan->max_reg_power;
+               else
+                       chan->max_power = min(chan->orig_mpwr,
+                                             chan->max_reg_power);
+       } else
+               chan->max_power = chan->max_reg_power;
 }
 
 static void handle_band(struct wiphy *wiphy,
@@ -1885,6 +1901,7 @@ static void restore_custom_reg_settings(struct wiphy *wiphy)
                        chan->flags = chan->orig_flags;
                        chan->max_antenna_gain = chan->orig_mag;
                        chan->max_power = chan->orig_mpwr;
+                       chan->beacon_found = false;
                }
        }
 }
index 26f8cd30f712dc190d9e207e4dff989a75106c66..994e2f0cc7a8a12fc34cbe61fdee97afde3df10b 100644 (file)
@@ -735,7 +735,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
        wdev->connect_keys = NULL;
 }
 
-static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
+void cfg80211_process_wdev_events(struct wireless_dev *wdev)
 {
        struct cfg80211_event *ev;
        unsigned long flags;
index c5a5165a5927a185043bdc83e8c9c4e25f549753..5a2aa17e4d3c4a3667783266ddbb8992a3eff6bd 100644 (file)
@@ -1357,6 +1357,8 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
 
                memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst));
                xdst->flo.ops = &xfrm_bundle_fc_ops;
+               if (afinfo->init_dst)
+                       afinfo->init_dst(net, xdst);
        } else
                xdst = ERR_PTR(-ENOBUFS);
 
index 5b228f97d4b3308a950ae857828e04e90df86848..87cd0e4d42829a19797ae3e2371c47723fd40fb7 100644 (file)
@@ -415,8 +415,17 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
        if (x->lft.hard_add_expires_seconds) {
                long tmo = x->lft.hard_add_expires_seconds +
                        x->curlft.add_time - now;
-               if (tmo <= 0)
-                       goto expired;
+               if (tmo <= 0) {
+                       if (x->xflags & XFRM_SOFT_EXPIRE) {
+                               /* enter hard expire without soft expire first?!
+                                * setting a new date could trigger this.
+                                * workarbound: fix x->curflt.add_time by below:
+                                */
+                               x->curlft.add_time = now - x->saved_tmo - 1;
+                               tmo = x->lft.hard_add_expires_seconds - x->saved_tmo;
+                       } else
+                               goto expired;
+               }
                if (tmo < next)
                        next = tmo;
        }
@@ -433,10 +442,14 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
        if (x->lft.soft_add_expires_seconds) {
                long tmo = x->lft.soft_add_expires_seconds +
                        x->curlft.add_time - now;
-               if (tmo <= 0)
+               if (tmo <= 0) {
                        warn = 1;
-               else if (tmo < next)
+                       x->xflags &= ~XFRM_SOFT_EXPIRE;
+               } else if (tmo < next) {
                        next = tmo;
+                       x->xflags |= XFRM_SOFT_EXPIRE;
+                       x->saved_tmo = tmo;
+               }
        }
        if (x->lft.soft_use_expires_seconds) {
                long tmo = x->lft.soft_use_expires_seconds +
index 913d6bdfdda3ecb44f521af79980019d5a531399..ca05ba217f5fd4038bcc511adff8a5b95823fb3e 100755 (executable)
@@ -3016,7 +3016,8 @@ sub process {
                                        $herectx .= raw_line($linenr, $n) . "\n";
                                }
 
-                               if (($stmts =~ tr/;/;/) == 1) {
+                               if (($stmts =~ tr/;/;/) == 1 &&
+                                   $stmts !~ /^\s*(if|while|for|switch)\b/) {
                                        WARN("SINGLE_STATEMENT_DO_WHILE_MACRO",
                                             "Single statement macros should not use a do {} while (0) loop\n" . "$herectx");
                                }
index 18ba881c34159a8bcdc3b8b582bd3f0617f90e8a..4f8248d5a11f2e74712b77d4c3521870652dcddd 100755 (executable)
@@ -89,7 +89,7 @@ echo $code >> $T.s
 disas $T
 cat $T.dis >> $T.aa
 
-faultline=`cat $T.dis | head -1 | cut -d":" -f2`
+faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
 faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
 
 cat $T.oo | sed -e "s/\($faultline\)/\*\1     <-- trapping instruction/g"
index 9b0c0b8b4ab4cd483158cfb606aaba038fbbabb5..8fd107a3fac49e32a0879549e88546d7f7f594dd 100755 (executable)
@@ -1786,6 +1786,7 @@ sub dump_function($$) {
     $prototype =~ s/__init +//;
     $prototype =~ s/__init_or_module +//;
     $prototype =~ s/__must_check +//;
+    $prototype =~ s/__weak +//;
     $prototype =~ s/^#\s*define\s+//; #ak added
     $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//;
 
index 83554ee8a587fbf27bdc7095fa8a600b82aada57..0cc99a3ea42d65c81188c302626681fae6044473 100644 (file)
@@ -279,12 +279,46 @@ static int yama_ptrace_access_check(struct task_struct *child,
        }
 
        if (rc) {
-               char name[sizeof(current->comm)];
                printk_ratelimited(KERN_NOTICE
                        "ptrace of pid %d was attempted by: %s (pid %d)\n",
-                       child->pid,
-                       get_task_comm(name, current),
-                       current->pid);
+                       child->pid, current->comm, current->pid);
+       }
+
+       return rc;
+}
+
+/**
+ * yama_ptrace_traceme - validate PTRACE_TRACEME calls
+ * @parent: task that will become the ptracer of the current task
+ *
+ * Returns 0 if following the ptrace is allowed, -ve on error.
+ */
+static int yama_ptrace_traceme(struct task_struct *parent)
+{
+       int rc;
+
+       /* If standard caps disallows it, so does Yama.  We should
+        * only tighten restrictions further.
+        */
+       rc = cap_ptrace_traceme(parent);
+       if (rc)
+               return rc;
+
+       /* Only disallow PTRACE_TRACEME on more aggressive settings. */
+       switch (ptrace_scope) {
+       case YAMA_SCOPE_CAPABILITY:
+               if (!ns_capable(task_user_ns(parent), CAP_SYS_PTRACE))
+                       rc = -EPERM;
+               break;
+       case YAMA_SCOPE_NO_ATTACH:
+               rc = -EPERM;
+               break;
+       }
+
+       if (rc) {
+               printk_ratelimited(KERN_NOTICE
+                       "ptraceme of pid %d was attempted by: %s (pid %d)\n",
+                       current->pid, parent->comm, parent->pid);
        }
 
        return rc;
@@ -294,6 +328,7 @@ static struct security_operations yama_ops = {
        .name =                 "yama",
 
        .ptrace_access_check =  yama_ptrace_access_check,
+       .ptrace_traceme =       yama_ptrace_traceme,
        .task_prctl =           yama_task_prctl,
        .task_free =            yama_task_free,
 };
index 0d7b25e816437064775a1f81ab8753a0f619ccab..4e1fda75c1c9fbc335b6b45fd34871e8ce0a1898 100644 (file)
@@ -106,7 +106,7 @@ static struct pxa2xx_pcm_client pxa2xx_ac97_pcm_client = {
        .prepare                = pxa2xx_ac97_pcm_prepare,
 };
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int pxa2xx_ac97_do_suspend(struct snd_card *card)
 {
@@ -243,7 +243,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
        .driver         = {
                .name   = "pxa2xx-ac97",
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                .pm     = &pxa2xx_ac97_pm_ops,
 #endif
        },
index eb4ceb71123e1aa91f9063fa57653befc5a7ef09..277ebce23a452be6cb027590eb997c278971eba8 100644 (file)
@@ -452,6 +452,7 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev)
        dac->regs = ioremap(regs->start, resource_size(regs));
        if (!dac->regs) {
                dev_dbg(&pdev->dev, "could not remap register memory\n");
+               retval = -ENOMEM;
                goto out_free_card;
        }
 
@@ -534,7 +535,7 @@ out_put_pclk:
        return retval;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmel_abdac_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index bf47025bdf45776ce020e738f04af62752ea025c..9052aff37f6460fcdaba020f0b44d85484243c96 100644 (file)
@@ -278,14 +278,9 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
        if (retval < 0)
                return retval;
        /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-       if (cpu_is_at32ap7000()) {
-               if (retval < 0)
-                       return retval;
-               /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-               if (retval == 1)
-                       if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
-                               dw_dma_cyclic_free(chip->dma.rx_chan);
-       }
+       if (cpu_is_at32ap7000() && retval == 1)
+               if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+                       dw_dma_cyclic_free(chip->dma.rx_chan);
 
        /* Set restrictions to params. */
        mutex_lock(&opened_mutex);
@@ -980,6 +975,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
 
        if (!chip->regs) {
                dev_dbg(&pdev->dev, "could not remap register memory\n");
+               retval = -ENOMEM;
                goto err_ioremap;
        }
 
@@ -1134,7 +1130,7 @@ err_snd_card_new:
        return retval;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmel_ac97c_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index 4e7ec2b498738b6e2ebca47511be93b590af2aa8..d0f00356fc115a32db23bc8475f08a6aad178c47 100644 (file)
@@ -101,7 +101,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
                if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
                                                 chunk, &tmpb) < 0) {
                        if (!sgbuf->pages)
-                               return NULL;
+                               goto _failed;
                        if (!res_size)
                                goto _failed;
                        size = sgbuf->pages * PAGE_SIZE;
index 1128b35b2b05f47fc2c5783a16a10e9e26b9de29..5a34355e78e8f83295496e1feb836a99f7ff7b44 100644 (file)
@@ -1176,7 +1176,7 @@ static int __devexit loopback_remove(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int loopback_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index f7d3bfc6bca83ed296a59fb059cd79ea364c6879..54bb6644a598a8177e3fbec4220df2966abd6131 100644 (file)
@@ -1064,7 +1064,7 @@ static int __devexit snd_dummy_remove(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_dummy_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index 6ca59fc6dcb9c0faf3e5fe07890fd237568a5d79..ef171295f6d46b3684667dfac434196f5a9ccd3f 100644 (file)
@@ -199,7 +199,7 @@ static void pcsp_stop_beep(struct snd_pcsp *chip)
        pcspkr_stop_sound();
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int pcsp_suspend(struct device *dev)
 {
        struct snd_pcsp *chip = dev_get_drvdata(dev);
@@ -212,7 +212,7 @@ static SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
 #define PCSP_PM_OPS    &pcsp_pm
 #else
 #define PCSP_PM_OPS    NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static void pcsp_shutdown(struct platform_device *dev)
 {
index 2d67c78c9f4bc16e01bf7d869d2163f8122f5616..f7cdaf51512d05d26ca93baf8ce2627375a8af43 100644 (file)
@@ -233,7 +233,7 @@ static int __devinit snd_card_als100_probe(int dev,
                        irq[dev], dma8[dev], dma16[dev]);
        }
 
-       if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
+       if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) {
                snd_card_free(card);
                return error;
        }
index 733b014ec7d1637a50954b46ff64b6bd662241e3..b2b3c014221afd4d6b2079c6a3627f64fcfe9480 100644 (file)
@@ -575,13 +575,15 @@ static int jazz16_audio_set_speed(int dev, int speed)
        if (speed > 0)
        {
                int tmp;
-               int s = speed * devc->channels;
+               int s;
 
                if (speed < 5000)
                        speed = 5000;
                if (speed > 44100)
                        speed = 44100;
 
+               s = speed * devc->channels;
+
                devc->tconst = (256 - ((1000000 + s / 2) / s)) & 0xff;
 
                tmp = 256 - devc->tconst;
index f75f5ffdfdfb60724db8a90dbac5ca05447f3816..a71d1c14a0f6b9efa06bc91d2970bb304ebaa872 100644 (file)
@@ -94,7 +94,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
 
        if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
                       codec_index != CS46XX_SECONDARY_CODEC_INDEX))
-               return -EINVAL;
+               return 0xffff;
 
        chip->active_ctrl(chip, 1);
 
index 8e40262d4117cf923c9972711177ab5b8b445dcd..2f6e9c762d3fd184dd995b17a9485faf050dffeb 100644 (file)
@@ -1725,8 +1725,10 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        atc_connect_resources(atc);
 
        atc->timer = ct_timer_new(atc);
-       if (!atc->timer)
+       if (!atc->timer) {
+               err = -ENOMEM;
                goto error1;
+       }
 
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
        if (err < 0)
index 4f502a2bdc3c51759ef26a4c4f80c858cc6192f9..0a436626182b9cc358def5a31f7a7daabf43c484 100644 (file)
@@ -326,7 +326,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
        for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
                unsigned long ofs = idx << PAGE_SHIFT;
                dma_addr_t addr;
-               addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+               if (ofs >= runtime->dma_bytes)
+                       addr = emu->silent_page.addr;
+               else
+                       addr = snd_pcm_sgbuf_get_addr(substream, ofs);
                if (! is_valid_page(emu, addr)) {
                        printk(KERN_ERR "emu: failure page = %d\n", idx);
                        mutex_unlock(&hdr->block_mutex);
index 647218d69f6890862b5fcfd690dc9e09d29bc3ea..4f7d2dfcef7b16357ead4185b7b62e3463d5f1a5 100644 (file)
@@ -332,13 +332,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        if (cfg->dig_outs)
                snd_printd("   dig-out=0x%x/0x%x\n",
                           cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-       snd_printd("   inputs:");
+       snd_printd("   inputs:\n");
        for (i = 0; i < cfg->num_inputs; i++) {
-               snd_printd(" %s=0x%x",
+               snd_printd("     %s=0x%x\n",
                            hda_get_autocfg_input_label(codec, cfg, i),
                            cfg->inputs[i].pin);
        }
-       snd_printd("\n");
        if (cfg->dig_in_pin)
                snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
index 0bc2315b181dad0ec6ed7a33af9e0a0a636c3608..0849aac449f2043fe1df237c48773436b5aefe7d 100644 (file)
@@ -231,16 +231,22 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
 
+static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       return query_amp_caps(codec, get_amp_nid(kcontrol),
+                             get_amp_direction(kcontrol)) & AC_AMPCAP_MUTE;
+}
+
 /* get/put callbacks for beep mute mixer switches */
 int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_beep *beep = codec->beep;
-       if (beep) {
+       if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) {
                ucontrol->value.integer.value[0] =
-                       ucontrol->value.integer.value[1] =
-                       beep->enabled;
+                       ucontrol->value.integer.value[1] = beep->enabled;
                return 0;
        }
        return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
@@ -252,9 +258,20 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_beep *beep = codec->beep;
-       if (beep)
-               snd_hda_enable_beep_device(codec,
-                                          *ucontrol->value.integer.value);
+       if (beep) {
+               u8 chs = get_amp_channels(kcontrol);
+               int enable = 0;
+               long *valp = ucontrol->value.integer.value;
+               if (chs & 1) {
+                       enable |= *valp;
+                       valp++;
+               }
+               if (chs & 2)
+                       enable |= *valp;
+               snd_hda_enable_beep_device(codec, enable);
+       }
+       if (!ctl_has_mute(kcontrol))
+               return 0;
        return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep);
index 88a9c20eb7a29cbff43745f5a64afefefb52b76e..f560051a949e943e10efb844364d5a978a587fcd 100644 (file)
@@ -1386,6 +1386,44 @@ int snd_hda_codec_configure(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
 
+/* update the stream-id if changed */
+static void update_pcm_stream_id(struct hda_codec *codec,
+                                struct hda_cvt_setup *p, hda_nid_t nid,
+                                u32 stream_tag, int channel_id)
+{
+       unsigned int oldval, newval;
+
+       if (p->stream_tag != stream_tag || p->channel_id != channel_id) {
+               oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+               newval = (stream_tag << 4) | channel_id;
+               if (oldval != newval)
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_CHANNEL_STREAMID,
+                                           newval);
+               p->stream_tag = stream_tag;
+               p->channel_id = channel_id;
+       }
+}
+
+/* update the format-id if changed */
+static void update_pcm_format(struct hda_codec *codec, struct hda_cvt_setup *p,
+                             hda_nid_t nid, int format)
+{
+       unsigned int oldval;
+
+       if (p->format_id != format) {
+               oldval = snd_hda_codec_read(codec, nid, 0,
+                                           AC_VERB_GET_STREAM_FORMAT, 0);
+               if (oldval != format) {
+                       msleep(1);
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_STREAM_FORMAT,
+                                           format);
+               }
+               p->format_id = format;
+       }
+}
+
 /**
  * snd_hda_codec_setup_stream - set up the codec for streaming
  * @codec: the CODEC to set up
@@ -1400,7 +1438,6 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 {
        struct hda_codec *c;
        struct hda_cvt_setup *p;
-       unsigned int oldval, newval;
        int type;
        int i;
 
@@ -1413,29 +1450,13 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        p = get_hda_cvt_setup(codec, nid);
        if (!p)
                return;
-       /* update the stream-id if changed */
-       if (p->stream_tag != stream_tag || p->channel_id != channel_id) {
-               oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-               newval = (stream_tag << 4) | channel_id;
-               if (oldval != newval)
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_CHANNEL_STREAMID,
-                                           newval);
-               p->stream_tag = stream_tag;
-               p->channel_id = channel_id;
-       }
-       /* update the format-id if changed */
-       if (p->format_id != format) {
-               oldval = snd_hda_codec_read(codec, nid, 0,
-                                           AC_VERB_GET_STREAM_FORMAT, 0);
-               if (oldval != format) {
-                       msleep(1);
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_STREAM_FORMAT,
-                                           format);
-               }
-               p->format_id = format;
-       }
+
+       if (codec->pcm_format_first)
+               update_pcm_format(codec, p, nid, format);
+       update_pcm_stream_id(codec, p, nid, stream_tag, channel_id);
+       if (!codec->pcm_format_first)
+               update_pcm_format(codec, p, nid, format);
+
        p->active = 1;
        p->dirty = 0;
 
@@ -3497,7 +3518,7 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg
 {
        int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE);
 
-       if (sup < 0)
+       if (sup == -1)
                return false;
        if (sup & power_state)
                return true;
@@ -4433,6 +4454,8 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
         * then there is no need to go through power up here.
         */
        if (codec->power_on) {
+               if (codec->power_transition < 0)
+                       codec->power_transition = 0;
                spin_unlock(&codec->power_lock);
                return;
        }
index c422d330ca54fe018379e5b14b24dcd03a4e208e..7fbc1bcaf1a9593b6e0ec71b8b5ac2bb5262e336 100644 (file)
@@ -861,6 +861,7 @@ struct hda_codec {
        unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
        unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
        unsigned int no_jack_detect:1;  /* Machine has no jack-detection */
+       unsigned int pcm_format_first:1; /* PCM format must be set first */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        unsigned int power_on :1;       /* current (global) power-state */
        int power_transition;   /* power-state in transition */
index c8aced182fd15738cf165505d532e24e89bcd906..60882c62f18006a3b2339d354b58550fdcd30718 100644 (file)
@@ -151,6 +151,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, CPT},"
                         "{Intel, PPT},"
                         "{Intel, LPT},"
+                        "{Intel, LPT_LP},"
                         "{Intel, HPT},"
                         "{Intel, PBG},"
                         "{Intel, SCH},"
@@ -3270,6 +3271,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
          AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+       /* Lynx Point-LP */
+       { PCI_DEVICE(0x8086, 0x9c20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+       /* Lynx Point-LP */
+       { PCI_DEVICE(0x8086, 0x9c21),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0c0c),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
index 7e46258fc7002e24eeb1159e49b05d157a534995..6894ec66258c5988771b2518071e6e9a603e14f2 100644 (file)
@@ -412,7 +412,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
        if (digi1 & AC_DIG1_EMPHASIS)
                snd_iprintf(buffer, " Preemphasis");
        if (digi1 & AC_DIG1_COPYRIGHT)
-               snd_iprintf(buffer, " Copyright");
+               snd_iprintf(buffer, " Non-Copyright");
        if (digi1 & AC_DIG1_NONAUDIO)
                snd_iprintf(buffer, " Non-Audio");
        if (digi1 & AC_DIG1_PROFESSIONAL)
index d0d3540e39e7746b1c42074257fe8194b928e09b..49750a96d649b5f842412c8a94c116f65f1dcf52 100644 (file)
@@ -246,7 +246,7 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
                                            AC_VERB_SET_AMP_GAIN_MUTE,
                                            AMP_OUT_UNMUTE);
        }
-       if (dac)
+       if (dac && (get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
                snd_hda_codec_write(codec, dac, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
 }
@@ -261,7 +261,7 @@ static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
                                            AC_VERB_SET_AMP_GAIN_MUTE,
                                            AMP_IN_UNMUTE(0));
        }
-       if (adc)
+       if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP))
                snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_UNMUTE(0));
 }
@@ -275,6 +275,10 @@ static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type);
+       if ((query_amp_caps(codec, nid, type) & AC_AMPCAP_MUTE) == 0) {
+               snd_printdd("Skipping '%s %s Switch' (no mute on node 0x%x)\n", pfx, dirstr[dir], nid);
+               return 0;
+       }
        sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
        return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
@@ -286,6 +290,10 @@ static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx,
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type);
+       if ((query_amp_caps(codec, nid, type) & AC_AMPCAP_NUM_STEPS) == 0) {
+               snd_printdd("Skipping '%s %s Volume' (no amp on node 0x%x)\n", pfx, dirstr[dir], nid);
+               return 0;
+       }
        sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]);
        return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
 }
@@ -464,50 +472,17 @@ exit:
 }
 
 /*
- * PCM stuffs
+ * PCM callbacks
  */
-static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
-                                u32 stream_tag,
-                                int channel_id, int format)
+static int ca0132_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
 {
-       unsigned int oldval, newval;
-
-       if (!nid)
-               return;
-
-       snd_printdd("ca0132_setup_stream: "
-               "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
-               nid, stream_tag, channel_id, format);
-
-       /* update the format-id if changed */
-       oldval = snd_hda_codec_read(codec, nid, 0,
-                                   AC_VERB_GET_STREAM_FORMAT,
-                                   0);
-       if (oldval != format) {
-               msleep(20);
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_STREAM_FORMAT,
-                                   format);
-       }
-
-       oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-       newval = (stream_tag << 4) | channel_id;
-       if (oldval != newval) {
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CHANNEL_STREAMID,
-                                   newval);
-       }
-}
-
-static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
-{
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+       struct ca0132_spec *spec = codec->spec;
+       return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+                                            hinfo);
 }
 
-/*
- * PCM callbacks
- */
 static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                        struct hda_codec *codec,
                        unsigned int stream_tag,
@@ -515,10 +490,8 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                        struct snd_pcm_substream *substream)
 {
        struct ca0132_spec *spec = codec->spec;
-
-       ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
-
-       return 0;
+       return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+                                               stream_tag, format, substream);
 }
 
 static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
@@ -526,92 +499,45 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
                        struct snd_pcm_substream *substream)
 {
        struct ca0132_spec *spec = codec->spec;
-
-       ca0132_cleanup_stream(codec, spec->dacs[0]);
-
-       return 0;
+       return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
 }
 
 /*
  * Digital out
  */
-static int ca0132_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       unsigned int stream_tag,
-                       unsigned int format,
-                       struct snd_pcm_substream *substream)
+static int ca0132_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
 {
        struct ca0132_spec *spec = codec->spec;
-
-       ca0132_setup_stream(codec, spec->dig_out, stream_tag, 0, format);
-
-       return 0;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
-static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       ca0132_cleanup_stream(codec, spec->dig_out);
-
-       return 0;
-}
-
-/*
- * Analog capture
- */
-static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int ca0132_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                        struct hda_codec *codec,
                        unsigned int stream_tag,
                        unsigned int format,
                        struct snd_pcm_substream *substream)
 {
        struct ca0132_spec *spec = codec->spec;
-
-       ca0132_setup_stream(codec, spec->adcs[substream->number],
-                            stream_tag, 0, format);
-
-       return 0;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
 }
 
-static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
                        struct hda_codec *codec,
                        struct snd_pcm_substream *substream)
 {
        struct ca0132_spec *spec = codec->spec;
-
-       ca0132_cleanup_stream(codec, spec->adcs[substream->number]);
-
-       return 0;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
 }
 
-/*
- * Digital capture
- */
-static int ca0132_dig_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       unsigned int stream_tag,
-                       unsigned int format,
-                       struct snd_pcm_substream *substream)
+static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                        struct hda_codec *codec,
+                                        struct snd_pcm_substream *substream)
 {
        struct ca0132_spec *spec = codec->spec;
-
-       ca0132_setup_stream(codec, spec->dig_in, stream_tag, 0, format);
-
-       return 0;
-}
-
-static int ca0132_dig_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       ca0132_cleanup_stream(codec, spec->dig_in);
-
-       return 0;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
 }
 
 /*
@@ -621,6 +547,7 @@ static struct hda_pcm_stream ca0132_pcm_analog_playback = {
        .channels_min = 2,
        .channels_max = 2,
        .ops = {
+               .open = ca0132_playback_pcm_open,
                .prepare = ca0132_playback_pcm_prepare,
                .cleanup = ca0132_playback_pcm_cleanup
        },
@@ -630,10 +557,6 @@ static struct hda_pcm_stream ca0132_pcm_analog_capture = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
-       .ops = {
-               .prepare = ca0132_capture_pcm_prepare,
-               .cleanup = ca0132_capture_pcm_cleanup
-       },
 };
 
 static struct hda_pcm_stream ca0132_pcm_digital_playback = {
@@ -641,6 +564,8 @@ static struct hda_pcm_stream ca0132_pcm_digital_playback = {
        .channels_min = 2,
        .channels_max = 2,
        .ops = {
+               .open = ca0132_dig_playback_pcm_open,
+               .close = ca0132_dig_playback_pcm_close,
                .prepare = ca0132_dig_playback_pcm_prepare,
                .cleanup = ca0132_dig_playback_pcm_cleanup
        },
@@ -650,10 +575,6 @@ static struct hda_pcm_stream ca0132_pcm_digital_capture = {
        .substreams = 1,
        .channels_min = 2,
        .channels_max = 2,
-       .ops = {
-               .prepare = ca0132_dig_capture_pcm_prepare,
-               .cleanup = ca0132_dig_capture_pcm_cleanup
-       },
 };
 
 static int ca0132_build_pcms(struct hda_codec *codec)
@@ -928,18 +849,16 @@ static int ca0132_build_controls(struct hda_codec *codec)
                                                    spec->dig_out);
                if (err < 0)
                        return err;
-               err = add_out_volume(codec, spec->dig_out, "IEC958");
+               err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
                if (err < 0)
                        return err;
+               /* spec->multiout.share_spdif = 1; */
        }
 
        if (spec->dig_in) {
                err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
                if (err < 0)
                        return err;
-               err = add_in_volume(codec, spec->dig_in, "IEC958");
-               if (err < 0)
-                       return err;
        }
        return 0;
 }
@@ -961,6 +880,9 @@ static void ca0132_config(struct hda_codec *codec)
        struct ca0132_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
 
+       codec->pcm_format_first = 1;
+       codec->no_sticky_stream = 1;
+
        /* line-outs */
        cfg->line_outs = 1;
        cfg->line_out_pins[0] = 0x0b; /* front */
@@ -988,14 +910,24 @@ static void ca0132_config(struct hda_codec *codec)
 
        /* Mic-in */
        spec->input_pins[0] = 0x12;
-       spec->input_labels[0] = "Mic-In";
+       spec->input_labels[0] = "Mic";
        spec->adcs[0] = 0x07;
 
        /* Line-In */
        spec->input_pins[1] = 0x11;
-       spec->input_labels[1] = "Line-In";
+       spec->input_labels[1] = "Line";
        spec->adcs[1] = 0x08;
        spec->num_inputs = 2;
+
+       /* SPDIF I/O */
+       spec->dig_out = 0x05;
+       spec->multiout.dig_out_nid = spec->dig_out;
+       cfg->dig_out_pins[0] = 0x0c;
+       cfg->dig_outs = 1;
+       cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF;
+       spec->dig_in = 0x09;
+       cfg->dig_in_pin = 0x0e;
+       cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
 }
 
 static void ca0132_init_chip(struct hda_codec *codec)
index 14361184ae1e0e17ac2483dcac3c525289369f1f..5e22a8f43d2eebc288083142b355feffb61ffedb 100644 (file)
@@ -2967,12 +2967,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = {
 };
 
 static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT5066_AUTO),
        SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
-       SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD),
@@ -2988,14 +2986,10 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
-       SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T510", CXT5066_AUTO),
-       SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO),
        SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
-       SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
-       SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO),
        {}
 };
 
index 69b928449789e22afcaef39a67dea3323bc5e5e7..8f23374fa6427198735f91b987656986052a8773 100644 (file)
@@ -877,8 +877,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        struct hdmi_eld *eld;
        struct hdmi_spec_per_cvt *per_cvt = NULL;
 
-       hinfo->nid = 0; /* clear the leftover value */
-
        /* Validate hinfo */
        pin_idx = hinfo_to_pin_index(spec, hinfo);
        if (snd_BUG_ON(pin_idx < 0))
@@ -1163,6 +1161,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
 
+static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                            struct hda_codec *codec,
+                                            struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       return 0;
+}
+
 static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                          struct hda_codec *codec,
                          struct snd_pcm_substream *substream)
@@ -1202,6 +1208,7 @@ static const struct hda_pcm_ops generic_ops = {
        .open = hdmi_pcm_open,
        .close = hdmi_pcm_close,
        .prepare = generic_hdmi_playback_pcm_prepare,
+       .cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
@@ -1220,7 +1227,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
                pstr->substreams = 1;
                pstr->ops = generic_ops;
-               pstr->nid = 1; /* FIXME: just for avoiding a debug WARNING */
                /* other pstr fields are set in open */
        }
 
index 344b221d2102ffd9d4568961d7a0d2b5f8490e2a..4f81dd44c837e1de6b1de327f457bcb0fcc8f16f 100644 (file)
@@ -6099,6 +6099,8 @@ static const struct alc_fixup alc269_fixups[] = {
        [ALC269_FIXUP_PCM_44K] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc269_fixup_pcm_44k,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_QUANTA_MUTE
        },
        [ALC269_FIXUP_STEREO_DMIC] = {
                .type = ALC_FIXUP_FUNC,
@@ -6206,9 +6208,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 
 #if 0
index 94040ccf8e8fbd954833a6302ed37ab60a34f1ed..ea5775a1a7db292e25dd7956b8ac502d1a9db33e 100644 (file)
@@ -4272,7 +4272,8 @@ static int stac92xx_init(struct hda_codec *codec)
        unsigned int gpio;
        int i;
 
-       snd_hda_sequence_write(codec, spec->init);
+       if (spec->init)
+               snd_hda_sequence_write(codec, spec->init);
 
        /* power down adcs initially */
        if (spec->powerdown_adcs)
@@ -5748,7 +5749,6 @@ again:
                /* fallthru */
        case 0x111d76b4: /* 6 Port without Analog Mixer */
        case 0x111d76b5:
-               spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
@@ -5773,7 +5773,6 @@ again:
                        spec->stream_delay = 40; /* 40 milliseconds */
 
                /* disable VSW */
-               spec->init = stac92hd71bxx_core_init;
                unmute_init++;
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
@@ -5788,7 +5787,6 @@ again:
 
                /* fallthru */
        default:
-               spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
@@ -5796,6 +5794,9 @@ again:
                break;
        }
 
+       if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB)
+               spec->init = stac92hd71bxx_core_init;
+
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
                snd_hda_sequence_write_cache(codec, unmute_init);
 
index 80d90cb42853bd50abfac7349361142e71185a7c..43077177691588ab03590cd0576369c54b55d266 100644 (file)
@@ -1752,6 +1752,14 @@ static int via_suspend(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        vt1708_stop_hp_work(spec);
+
+       if (spec->codec_type == VT1802) {
+               /* Fix pop noise on headphones */
+               int i;
+               for (i = 0; i < spec->autocfg.hp_outs; i++)
+                       snd_hda_set_pin_ctl(codec, spec->autocfg.hp_pins[i], 0);
+       }
+
        return 0;
 }
 #endif
index d1ab43706735fb42d12cc8514b48b9add557b5c2..5579b08bb35b6337c646b6d2cb6be5215f0d01d9 100644 (file)
@@ -851,6 +851,8 @@ static int __devinit lx_pcm_create(struct lx6464es *chip)
        /* hardcoded device name & channel count */
        err = snd_pcm_new(chip->card, (char *)card_name, 0,
                          1, 1, &pcm);
+       if (err < 0)
+               return err;
 
        pcm->private_data = chip;
 
index b8ac8710f47fb200d602bc2917598a153cad6884..b12308b5ba2a01170b56b5cd7b69a9d1d93aa6e3 100644 (file)
@@ -6585,7 +6585,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
                snd_printk(KERN_ERR "HDSPM: "
                                "unable to kmalloc Mixer memory of %d Bytes\n",
                                (int)sizeof(struct hdspm_mixer));
-               return err;
+               return -ENOMEM;
        }
 
        hdspm->port_names_in = NULL;
index 512434efcc31136f1570ab5e17429523a354f187..805ab6e9a78fbb0879c111140deda257c083d30c 100644 (file)
@@ -1377,8 +1377,9 @@ static int __devinit sis_chip_create(struct snd_card *card,
        if (rc)
                goto error_out_cleanup;
 
-       if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME,
-                       sis)) {
+       rc = request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME,
+                        sis);
+       if (rc) {
                dev_err(&pci->dev, "unable to allocate irq %d\n", sis->irq);
                goto error_out_cleanup;
        }
index f5ceb6f282decab0e89e4b8c5637c0520efde7d9..210cafe0489020ea970ac2724a68797a5be23a6e 100644 (file)
@@ -143,7 +143,7 @@ static int __devexit snd_pmac_remove(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_pmac_driver_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
index 1aa52eff526a1d97094caa525681b25ca4c8d4e8..9b18b5243a56a74bc704fc3e2c79901ac8ec0079 100644 (file)
@@ -1040,6 +1040,7 @@ static int __devinit snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
                                   GFP_KERNEL);
        if (!the_card.null_buffer_start_vaddr) {
                pr_info("%s: nullbuffer alloc failed\n", __func__);
+               ret = -ENOMEM;
                goto clean_preallocate;
        }
        pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__,
index 318c5ba5360f6dfb3e9184aa9f169ad0f23aa3a4..dfb744381c42cb2288b7bb7325fdb04b04338b82 100644 (file)
@@ -413,7 +413,14 @@ EXPORT_SYMBOL(sport_create);
 
 void sport_delete(struct sport_device *sport)
 {
+       if (sport->tx_desc)
+               dma_free_coherent(NULL, sport->tx_desc_size,
+                               sport->tx_desc, 0);
+       if (sport->rx_desc)
+               dma_free_coherent(NULL, sport->rx_desc_size,
+                               sport->rx_desc, 0);
        sport_free_resource(sport);
+       kfree(sport);
 }
 EXPORT_SYMBOL(sport_delete);
 
index 3c795921c5f6b840f6654d53907ed44e18435841..23b40186f9b8f48df8be77a29269eddbad88f792 100644 (file)
@@ -2406,6 +2406,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
        /* Setup AB8500 according to board-settings */
        pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
+
+       /* Inform SoC Core that we have our own I/O arrangements. */
+       codec->control_data = (void *)true;
+
        status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
        if (status < 0) {
                pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
index 8c39dddd7d0063d90adcf587c5e6dc19c37f73ad..11b1b714b8b5e106ad7784258ca4caa4a4939e9e 100644 (file)
@@ -186,6 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
+       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
index 6276e352125f0a22e156c388c08f53d229fd543e..8f726c063f42badc9c598de4af670fb78f8937e1 100644 (file)
@@ -581,6 +581,8 @@ static int mc13783_probe(struct snd_soc_codec *codec)
 {
        struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
 
+       codec->control_data = priv->mc13xxx;
+
        mc13xxx_lock(priv->mc13xxx);
 
        /* these are the reset values */
index 8af6a5245b18acbfefe5fa1ca8ecbec8fd9068be..df2f99d1d428940424d419378ce6cf9d82a937bf 100644 (file)
@@ -239,6 +239,7 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
        {"Headphone Mux", "DAC", "DAC"},        /* dac --> hp_mux */
        {"LO", NULL, "DAC"},                    /* dac --> line_out */
 
+       {"LINE_IN", NULL, "VAG_POWER"},
        {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
        {"HP", NULL, "Headphone Mux"},          /* hp_mux --> hp */
 
@@ -1357,8 +1358,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
        if (ret)
                goto err;
 
-       snd_soc_dapm_new_widgets(&codec->dapm);
-
        return 0;
 
 err:
index 982e437799a8e62aa8085a9d5b509fa4d8f8a387..33c0f3d39c87ea0ea6c99ea1752f30e663914766 100644 (file)
@@ -340,6 +340,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
 
+       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
index 6537f16d383e12f459b9f39950c7b28b46d8d7da..e33d327396ad4fe7a0cb72ffd6ddc6d6caabf3f2 100644 (file)
@@ -128,13 +128,9 @@ SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
 
 ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
-ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE),
-ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE),
 
 SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
                   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
-SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5,
-                  ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA),
 
 ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
@@ -236,8 +232,6 @@ ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
 
 ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
-ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE);
-ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE);
 
 ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
@@ -349,10 +343,6 @@ SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
                 NULL, 0),
 SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
                 NULL, 0),
-SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0,
-                NULL, 0),
-SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0,
-                NULL, 0),
 
 SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
                 NULL, 0),
@@ -466,8 +456,6 @@ ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
 
 ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
 ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
-ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"),
-ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"),
 
 ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
 ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
@@ -553,8 +541,6 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
        { name, "EQ4", "EQ4" }, \
        { name, "DRC1L", "DRC1L" }, \
        { name, "DRC1R", "DRC1R" }, \
-       { name, "DRC2L", "DRC2L" }, \
-       { name, "DRC2R", "DRC2R" }, \
        { name, "LHPF1", "LHPF1" }, \
        { name, "LHPF2", "LHPF2" }, \
        { name, "LHPF3", "LHPF3" }, \
@@ -639,6 +625,15 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
 
+       { "IN1L PGA", NULL, "IN1L" },
+       { "IN1R PGA", NULL, "IN1R" },
+
+       { "IN2L PGA", NULL, "IN2L" },
+       { "IN2R PGA", NULL, "IN2R" },
+
+       { "IN3L PGA", NULL, "IN3L" },
+       { "IN3R PGA", NULL, "IN3R" },
+
        ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
        ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
        ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
@@ -675,8 +670,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
 
        ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
        ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
-       ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"),
-       ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"),
 
        ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
        ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
index 8033f70651897215613275901fd432eea6cdb673..01ebbcc5c6a4a55f31b6448c6ede5e92a1f3f2e8 100644 (file)
@@ -681,6 +681,18 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
 
+       { "IN1L PGA", NULL, "IN1L" },
+       { "IN1R PGA", NULL, "IN1R" },
+
+       { "IN2L PGA", NULL, "IN2L" },
+       { "IN2R PGA", NULL, "IN2R" },
+
+       { "IN3L PGA", NULL, "IN3L" },
+       { "IN3R PGA", NULL, "IN3R" },
+
+       { "IN4L PGA", NULL, "IN4L" },
+       { "IN4R PGA", NULL, "IN4R" },
+
        ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
        ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
        ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
index eaf65863ec2190c8e705eaa3d4b5a95ff6378d30..ce6720073798ddd352df483182b1653b121ec096 100644 (file)
@@ -2501,6 +2501,9 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                /* VMID 2*250k */
                snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
                                    WM8962_VMID_SEL_MASK, 0x100);
+
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       msleep(100);
                break;
 
        case SND_SOC_BIAS_OFF:
@@ -3730,21 +3733,6 @@ static int wm8962_runtime_resume(struct device *dev)
 
        regcache_sync(wm8962->regmap);
 
-       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
-                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
-                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
-
-       /* Bias enable at 2*50k for ramp */
-       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
-                          WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA,
-                          WM8962_BIAS_ENA | 0x180);
-
-       msleep(5);
-
-       /* VMID back to 2x250k for standby */
-       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
-                          WM8962_VMID_SEL_MASK, 0x100);
-
        return 0;
 }
 
index bb62f4b3d563d434143f52a6ba70f614a8ed61fd..6c9eeca85b952278f375ff9bb21faee1e33ec06a 100644 (file)
@@ -2649,7 +2649,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       bclk_rate = params_rate(params) * 2;
+       bclk_rate = params_rate(params) * 4;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                bclk_rate *= 16;
@@ -3253,10 +3253,13 @@ static void wm8994_mic_work(struct work_struct *work)
        int ret;
        int report;
 
+       pm_runtime_get_sync(dev);
+
        ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
        if (ret < 0) {
                dev_err(dev, "Failed to read microphone status: %d\n",
                        ret);
+               pm_runtime_put(dev);
                return;
        }
 
@@ -3299,6 +3302,8 @@ static void wm8994_mic_work(struct work_struct *work)
 
        snd_soc_jack_report(priv->micdet[1].jack, report,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+       pm_runtime_put(dev);
 }
 
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
@@ -3421,12 +3426,15 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
        int reg;
        bool present;
 
+       pm_runtime_get_sync(codec->dev);
+
        mutex_lock(&wm8994->accdet_lock);
 
        reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
        if (reg < 0) {
                dev_err(codec->dev, "Failed to read jack status: %d\n", reg);
                mutex_unlock(&wm8994->accdet_lock);
+               pm_runtime_put(codec->dev);
                return IRQ_NONE;
        }
 
@@ -3491,6 +3499,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
                                    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
                                    wm8994->btn_mask);
 
+       pm_runtime_put(codec->dev);
        return IRQ_HANDLED;
 }
 
@@ -3602,6 +3611,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
                return IRQ_HANDLED;
 
+       pm_runtime_get_sync(codec->dev);
+
        /* We may occasionally read a detection without an impedence
         * range being provided - if that happens loop again.
         */
@@ -3612,6 +3623,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                        dev_err(codec->dev,
                                "Failed to read mic detect status: %d\n",
                                reg);
+                       pm_runtime_put(codec->dev);
                        return IRQ_NONE;
                }
 
@@ -3639,6 +3651,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                dev_warn(codec->dev, "Accessory detection with no callback\n");
 
 out:
+       pm_runtime_put(codec->dev);
        return IRQ_HANDLED;
 }
 
@@ -4025,6 +4038,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        case WM8958:
                if (wm8994->revision < 1) {
+                       snd_soc_dapm_add_routes(dapm, wm8994_intercon,
+                                               ARRAY_SIZE(wm8994_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
                                                ARRAY_SIZE(wm8994_revd_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
index 099e6ec321256009a99ba90c73fc66283cece2d4..c6d2076a796bd9aecf510636a0339e76abed2dde 100644 (file)
@@ -148,7 +148,7 @@ SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
 
 SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
-SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
+SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),
 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
 
 SOC_SINGLE_TLV("Mic 1 Volume", AC97_MIC, 8, 31, 1, main_tlv),
@@ -272,7 +272,7 @@ SOC_DAPM_ENUM("Route", wm9712_enum[9]);
 
 /* Mic select */
 static const struct snd_kcontrol_new wm9712_mic_src_controls =
-SOC_DAPM_ENUM("Route", wm9712_enum[7]);
+SOC_DAPM_ENUM("Mic Source Select", wm9712_enum[7]);
 
 /* diff select */
 static const struct snd_kcontrol_new wm9712_diff_sel_controls =
@@ -291,7 +291,9 @@ SND_SOC_DAPM_MUX("Left Capture Select", SND_SOC_NOPM, 0, 0,
        &wm9712_capture_selectl_controls),
 SND_SOC_DAPM_MUX("Right Capture Select", SND_SOC_NOPM, 0, 0,
        &wm9712_capture_selectr_controls),
-SND_SOC_DAPM_MUX("Mic Select Source", SND_SOC_NOPM, 0, 0,
+SND_SOC_DAPM_MUX("Left Mic Select Source", SND_SOC_NOPM, 0, 0,
+       &wm9712_mic_src_controls),
+SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0,
        &wm9712_mic_src_controls),
 SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
        &wm9712_diff_sel_controls),
@@ -319,6 +321,7 @@ SND_SOC_DAPM_PGA("Out 3 PGA", AC97_INT_PAGING, 5, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Line PGA", AC97_INT_PAGING, 2, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Phone PGA", AC97_INT_PAGING, 1, 1, NULL, 0),
 SND_SOC_DAPM_PGA("Mic PGA", AC97_INT_PAGING, 0, 1, NULL, 0),
+SND_SOC_DAPM_PGA("Differential Mic", SND_SOC_NOPM, 0, 0, NULL, 0),
 SND_SOC_DAPM_MICBIAS("Mic Bias", AC97_INT_PAGING, 10, 1),
 SND_SOC_DAPM_OUTPUT("MONOOUT"),
 SND_SOC_DAPM_OUTPUT("HPOUTL"),
@@ -379,6 +382,18 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = {
        {"Mic PGA", NULL, "MIC1"},
        {"Mic PGA", NULL, "MIC2"},
 
+       /* microphones */
+       {"Differential Mic", NULL, "MIC1"},
+       {"Differential Mic", NULL, "MIC2"},
+       {"Left Mic Select Source", "Mic 1", "MIC1"},
+       {"Left Mic Select Source", "Mic 2", "MIC2"},
+       {"Left Mic Select Source", "Stereo", "MIC1"},
+       {"Left Mic Select Source", "Differential", "Differential Mic"},
+       {"Right Mic Select Source", "Mic 1", "MIC1"},
+       {"Right Mic Select Source", "Mic 2", "MIC2"},
+       {"Right Mic Select Source", "Stereo", "MIC2"},
+       {"Right Mic Select Source", "Differential", "Differential Mic"},
+
        /* left capture selector */
        {"Left Capture Select", "Mic", "MIC1"},
        {"Left Capture Select", "Speaker Mixer", "Speaker Mixer"},
@@ -619,6 +634,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
+       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
index 3eb19fb71d17209e0bccc071ed3f481471201276..d0b8a3287a8592af98dad706861fcb3b87460bbc 100644 (file)
@@ -1196,6 +1196,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
        if (wm9713 == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, wm9713);
+       codec->control_data = wm9713;   /* we don't use regmap! */
 
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
index 95441bfc819026071020915d6e4e3c53d2dec593..ce5e5cd254ddc395c6d08e8767228b4a6822668d 100644 (file)
@@ -380,14 +380,20 @@ static void mcasp_start_tx(struct davinci_audio_dev *dev)
 static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
 {
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (dev->txnumevt)      /* enable FIFO */
+               if (dev->txnumevt) {    /* enable FIFO */
+                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                                                               FIFO_ENABLE);
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
                                                                FIFO_ENABLE);
+               }
                mcasp_start_tx(dev);
        } else {
-               if (dev->rxnumevt)      /* enable FIFO */
+               if (dev->rxnumevt) {    /* enable FIFO */
+                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                                                               FIFO_ENABLE);
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
                                                                FIFO_ENABLE);
+               }
                mcasp_start_rx(dev);
        }
 }
index 28dd76c7cb1c08ac308ca7730d9abfc8b02b0903..81d7728cf67fb2d6f4ce1b4287319a0384f0d2d8 100644 (file)
@@ -380,13 +380,14 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 static struct snd_soc_dai_driver imx_ssi_dai = {
        .probe = imx_ssi_dai_probe,
        .playback = {
-               .channels_min = 1,
+               /* The SSI does not support monaural audio. */
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
index 99a997f19bb9d9f76c5fa7a93af992d7dce6b0eb..b6fa77678d97ec542a4585ff152b689c34370fd4 100644 (file)
@@ -10,7 +10,7 @@ menuconfig SND_MXS_SOC
 if SND_MXS_SOC
 
 config SND_SOC_MXS_SGTL5000
-       tristate "SoC Audio support for i.MX boards with sgtl5000"
+       tristate "SoC Audio support for MXS boards with sgtl5000"
        depends on I2C
        select SND_SOC_SGTL5000
        help
index aba71bfa33b15f0813f48a7a236bb61c5b5968b9..b3030718c2288b9942628c9f087694b0568cbbb3 100644 (file)
@@ -394,9 +394,14 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *cpu_dai)
 {
        struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+       struct mxs_saif *master_saif;
        u32 scr, stat;
        int ret;
 
+       master_saif = mxs_saif_get_master(saif);
+       if (!master_saif)
+               return -EINVAL;
+
        /* mclk should already be set */
        if (!saif->mclk && saif->mclk_in_use) {
                dev_err(cpu_dai->dev, "set mclk first\n");
@@ -420,6 +425,25 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+       /* prepare clk in hw_param, enable in trigger */
+       clk_prepare(saif->clk);
+       if (saif != master_saif) {
+               /*
+               * Set an initial clock rate for the saif internal logic to work
+               * properly. This is important when working in EXTMASTER mode
+               * that uses the other saif's BITCLK&LRCLK but it still needs a
+               * basic clock which should be fast enough for the internal
+               * logic.
+               */
+               clk_enable(saif->clk);
+               ret = clk_set_rate(saif->clk, 24000000);
+               clk_disable(saif->clk);
+               if (ret)
+                       return ret;
+
+               clk_prepare(master_saif->clk);
+       }
+
        scr = __raw_readl(saif->base + SAIF_CTRL);
 
        scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
index 34835e8a9160ce16b1d074a1f8495d1124e5eac8..d33c48baaf711054da6e1c3f08f5a2e57d394057 100644 (file)
@@ -745,7 +745,7 @@ int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux)
 {
        const char *signal, *src;
 
-       if (mcbsp->pdata->mux_signal)
+       if (!mcbsp->pdata->mux_signal)
                return -EINVAL;
 
        switch (mux) {
index 1046083e90a079f594b99ef0f88b72bb7e8e5150..acdd3ef14e08c59821d2ae18f7795c0b590e3df0 100644 (file)
@@ -820,3 +820,4 @@ module_platform_driver(asoc_mcbsp_driver);
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-mcbsp");
index 5a649da9122a3e798713999a766885f0f732a5cd..f0feb06615f8ea355711239b4ffbd74516221a3e 100644 (file)
@@ -441,3 +441,4 @@ module_platform_driver(omap_pcm_driver);
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-pcm-audio");
index b7b2a1f9142521d931a94fe65cd5ea9a580869d2..89b064650f1492ffc828367ef34c89cbc82800c7 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/pcm_params.h>
 
 #include <plat/audio.h>
-#include <plat/dma.h>
+#include <mach/dma.h>
 
 #include "dma.h"
 #include "pcm.h"
index f219b2f7ee682c795bcf12ec2bea9b9855506b6f..c501af6d8dbefac0ce233e30d884f02d491594f7 100644 (file)
@@ -826,7 +826,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        }
 
        if (!rtd->cpu_dai) {
-               dev_dbg(card->dev, "CPU DAI %s not registered\n",
+               dev_err(card->dev, "CPU DAI %s not registered\n",
                        dai_link->cpu_dai_name);
                return -EPROBE_DEFER;
        }
@@ -857,14 +857,14 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                }
 
                if (!rtd->codec_dai) {
-                       dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+                       dev_err(card->dev, "CODEC DAI %s not registered\n",
                                dai_link->codec_dai_name);
                        return -EPROBE_DEFER;
                }
        }
 
        if (!rtd->codec) {
-               dev_dbg(card->dev, "CODEC %s not registered\n",
+               dev_err(card->dev, "CODEC %s not registered\n",
                        dai_link->codec_name);
                return -EPROBE_DEFER;
        }
@@ -888,7 +888,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                rtd->platform = platform;
        }
        if (!rtd->platform) {
-               dev_dbg(card->dev, "platform %s not registered\n",
+               dev_err(card->dev, "platform %s not registered\n",
                        dai_link->platform_name);
                return -EPROBE_DEFER;
        }
@@ -1096,7 +1096,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
        }
 
        /* If the driver didn't set I/O up try regmap */
-       if (!codec->control_data)
+       if (!codec->write && dev_get_regmap(codec->dev, NULL))
                snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
 
        if (driver->controls)
@@ -1481,6 +1481,8 @@ static int soc_check_aux_dev(struct snd_soc_card *card, int num)
                        return 0;
        }
 
+       dev_err(card->dev, "%s not registered\n", aux_dev->codec_name);
+
        return -EPROBE_DEFER;
 }
 
index 7f8b3b7428bbf12c60f603fff8fbb8d3989fa254..0c172938b82a09a1d38f790cf07d4e2b48515b2f 100644 (file)
@@ -103,7 +103,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        }
 
        /* Report before the DAPM sync to help users updating micbias status */
-       blocking_notifier_call_chain(&jack->notifier, status, jack);
+       blocking_notifier_call_chain(&jack->notifier, jack->status, jack);
 
        snd_soc_dapm_sync(dapm);
 
index d684df294c0c5c80458b6de591c16965027db14b..e463529b38bbfbfd35cc745bf430f68399bfee91 100644 (file)
@@ -177,7 +177,7 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
        }
 
        alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
-       if (alc5632->gpio_hp_det == -ENODEV)
+       if (alc5632->gpio_hp_det == -EPROBE_DEFER)
                return -EPROBE_DEFER;
 
        ret = snd_soc_of_parse_card_name(card, "nvidia,model");
index 0c5bb33d258e1aeda033924e92598caa5c372d41..d4f14e492341f3751446057b68ee8d61f0c9bfbd 100644 (file)
@@ -284,27 +284,27 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
        } else if (np) {
                pdata->gpio_spkr_en = of_get_named_gpio(np,
                                                "nvidia,spkr-en-gpios", 0);
-               if (pdata->gpio_spkr_en == -ENODEV)
+               if (pdata->gpio_spkr_en == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_hp_mute = of_get_named_gpio(np,
                                                "nvidia,hp-mute-gpios", 0);
-               if (pdata->gpio_hp_mute == -ENODEV)
+               if (pdata->gpio_hp_mute == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_hp_det = of_get_named_gpio(np,
                                                "nvidia,hp-det-gpios", 0);
-               if (pdata->gpio_hp_det == -ENODEV)
+               if (pdata->gpio_hp_det == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_int_mic_en = of_get_named_gpio(np,
                                                "nvidia,int-mic-en-gpios", 0);
-               if (pdata->gpio_int_mic_en == -ENODEV)
+               if (pdata->gpio_int_mic_en == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_ext_mic_en = of_get_named_gpio(np,
                                                "nvidia,ext-mic-en-gpios", 0);
-               if (pdata->gpio_ext_mic_en == -ENODEV)
+               if (pdata->gpio_ext_mic_en == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
        }
 
index 62ac0285bfaffe367f0c3ddfb36bac52cb6113e2..057e28ef770ecbd9582078acb9db8cd7a83f8e4b 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/mfd/dbx500-prcmu.h>
 
 #include <mach/hardware.h>
-#include <mach/board-mop500-msp.h>
+#include <mach/msp.h>
 
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
index ee14d2dac2f53c4e328f622bf6566afbd193c309..5c472f335a64d6e5c11a5ee82e755153312ee40b 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/slab.h>
 
 #include <mach/hardware.h>
-#include <mach/board-mop500-msp.h>
+#include <mach/msp.h>
 
 #include <sound/soc.h>
 
index 7f71b4a0d4bc3b391c0633f8c2d6205d156d1511..2d9136da9865f18548d3ccc23548f286b8a994e4 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/platform_device.h>
 
-#include <mach/board-mop500-msp.h>
+#include <mach/msp.h>
 
 #define MSP_INPUT_FREQ_APB 48000000
 
index 0f647d22cb4ac7bccffe25311011255cf0b33104..c411812026884408afd74f1e580f2e87bbe747fc 100644 (file)
@@ -821,10 +821,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
        if (++ep->use_count != 1)
                return 0;
 
-       /* just to be sure */
-       deactivate_urbs(ep, 0, 1);
-       wait_clear_urbs(ep);
-
        ep->active_mask = 0;
        ep->unlink_mask = 0;
        ep->phase = 0;
index a1298f379428280045bf661f89e5fa59bb0acb48..62ec808ed792503e789ea26eb74837998623915e 100644 (file)
@@ -544,6 +544,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        subs->last_frame_number = 0;
        runtime->delay = 0;
 
+       /* clear the pending deactivation on the target EPs */
+       deactivate_endpoints(subs);
+
        /* for playback, submit the URBs now; otherwise, the first hwptr_done
         * updates for all URBs would happen at the same time when starting */
        if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
index 77f124fe57ad54d8e45858f4e4429f6b63f42273..35655c3a7b7a438dd806b9d5a5fb8baa7102876a 100644 (file)
@@ -319,6 +319,8 @@ LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
 LIB_H += $(TRACE_EVENT_DIR)event-parse.h
 LIB_H += util/target.h
+LIB_H += util/rblist.h
+LIB_H += util/intlist.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -383,6 +385,8 @@ LIB_OBJS += $(OUTPUT)util/xyarray.o
 LIB_OBJS += $(OUTPUT)util/cpumap.o
 LIB_OBJS += $(OUTPUT)util/cgroup.o
 LIB_OBJS += $(OUTPUT)util/target.o
+LIB_OBJS += $(OUTPUT)util/rblist.o
+LIB_OBJS += $(OUTPUT)util/intlist.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 
@@ -983,7 +987,8 @@ clean:
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
        $(MAKE) -C Documentation/ clean
        $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
-       $(RM) $(OUTPUT)util/*-{bison,flex}*
+       $(RM) $(OUTPUT)util/*-bison*
+       $(RM) $(OUTPUT)util/*-flex*
        $(python-clean)
 
 .PHONY: all install clean strip $(LIBTRACEEVENT)
index f5a6452931e6dabaa4f3b4593ab91f30aa7d586b..4db6e1ba54e30bf780d990a8fb1d7b203e89707f 100644 (file)
@@ -313,7 +313,7 @@ try_again:
                }
        }
 
-       perf_session__update_sample_type(session);
+       perf_session__set_id_hdr_size(session);
 }
 
 static int process_buildids(struct perf_record *rec)
@@ -844,8 +844,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        struct perf_record *rec = &record;
        char errbuf[BUFSIZ];
 
-       perf_header__set_cmdline(argc, argv);
-
        evsel_list = perf_evlist__new(NULL, NULL);
        if (evsel_list == NULL)
                return -ENOMEM;
index 69b1c1185159174f070425d15c17afc8d5325f50..7c88a243b5db04308c9faf2e6aaf32d19bf0bb54 100644 (file)
@@ -249,8 +249,9 @@ static int process_read_event(struct perf_tool *tool,
 static int perf_report__setup_sample_type(struct perf_report *rep)
 {
        struct perf_session *self = rep->session;
+       u64 sample_type = perf_evlist__sample_type(self->evlist);
 
-       if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
+       if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        ui__error("Selected --sort parent, but no "
                                    "callchain data. Did you call "
@@ -274,7 +275,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
 
        if (sort__branch_mode == 1) {
                if (!self->fd_pipe &&
-                   !(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
+                   !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
                        ui__error("Selected -b but no branch data. "
                                  "Did you call perf record without -b?\n");
                        return -1;
index d909eb74a0eb74bc46ec8a9e6cb9d8acca5da7f2..1d592f5cbea9776fcc437e012dc20c1911fd7137 100644 (file)
@@ -478,7 +478,6 @@ static int test__basic_mmap(void)
        unsigned int nr_events[nsyscalls],
                     expected_nr_events[nsyscalls], i, j;
        struct perf_evsel *evsels[nsyscalls], *evsel;
-       int sample_size = __perf_evsel__sample_size(attr.sample_type);
 
        for (i = 0; i < nsyscalls; ++i) {
                char name[64];
@@ -563,8 +562,7 @@ static int test__basic_mmap(void)
                        goto out_munmap;
                }
 
-               err = perf_event__parse_sample(event, attr.sample_type, sample_size,
-                                              false, &sample, false);
+               err = perf_evlist__parse_sample(evlist, event, &sample, false);
                if (err) {
                        pr_err("Can't parse sample, err = %d\n", err);
                        goto out_munmap;
@@ -661,12 +659,12 @@ static int test__PERF_RECORD(void)
        const char *cmd = "sleep";
        const char *argv[] = { cmd, "1", NULL, };
        char *bname;
-       u64 sample_type, prev_time = 0;
+       u64 prev_time = 0;
        bool found_cmd_mmap = false,
             found_libc_mmap = false,
             found_vdso_mmap = false,
             found_ld_mmap = false;
-       int err = -1, errs = 0, i, wakeups = 0, sample_size;
+       int err = -1, errs = 0, i, wakeups = 0;
        u32 cpu;
        int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
 
@@ -756,13 +754,6 @@ static int test__PERF_RECORD(void)
                goto out_delete_evlist;
        }
 
-       /*
-        * We'll need these two to parse the PERF_SAMPLE_* fields in each
-        * event.
-        */
-       sample_type = perf_evlist__sample_type(evlist);
-       sample_size = __perf_evsel__sample_size(sample_type);
-
        /*
         * Now that all is properly set up, enable the events, they will
         * count just on workload.pid, which will start...
@@ -788,9 +779,7 @@ static int test__PERF_RECORD(void)
                                if (type < PERF_RECORD_MAX)
                                        nr_events[type]++;
 
-                               err = perf_event__parse_sample(event, sample_type,
-                                                              sample_size, true,
-                                                              &sample, false);
+                               err = perf_evlist__parse_sample(evlist, event, &sample, false);
                                if (err < 0) {
                                        if (verbose)
                                                perf_event__fprintf(event, stderr);
index 35e86c6df713d7af91bc50f98953d55f08cc4162..68cd61ef6ac5440c57579e42a935261d440e20f2 100644 (file)
@@ -38,6 +38,7 @@
 #include "util/cpumap.h"
 #include "util/xyarray.h"
 #include "util/sort.h"
+#include "util/intlist.h"
 
 #include "util/debug.h"
 
@@ -706,8 +707,16 @@ static void perf_event__process_sample(struct perf_tool *tool,
        int err;
 
        if (!machine && perf_guest) {
-               pr_err("Can't find guest [%d]'s kernel information\n",
-                       event->ip.pid);
+               static struct intlist *seen;
+
+               if (!seen)
+                       seen = intlist__new();
+
+               if (!intlist__has_entry(seen, event->ip.pid)) {
+                       pr_err("Can't find guest [%d]'s kernel information\n",
+                               event->ip.pid);
+                       intlist__add(seen, event->ip.pid);
+               }
                return;
        }
 
@@ -811,7 +820,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
        int ret;
 
        while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
-               ret = perf_session__parse_sample(session, event, &sample);
+               ret = perf_evlist__parse_sample(top->evlist, event, &sample, false);
                if (ret) {
                        pr_err("Can't parse sample, err = %d\n", ret);
                        continue;
@@ -943,8 +952,10 @@ try_again:
                         * based cpu-clock-tick sw counter, which
                         * is always available even if no PMU support:
                         */
-                       if (attr->type == PERF_TYPE_HARDWARE &&
-                           attr->config == PERF_COUNT_HW_CPU_CYCLES) {
+                       if ((err == ENOENT || err == ENXIO) &&
+                           (attr->type == PERF_TYPE_HARDWARE) &&
+                           (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
+
                                if (verbose)
                                        ui__warning("Cycles event not supported,\n"
                                                    "trying to fall back to cpu-clock-ticks\n");
@@ -1032,7 +1043,7 @@ static int __cmd_top(struct perf_top *top)
                                               &top->session->host_machine);
        perf_top__start_counters(top);
        top->session->evlist = top->evlist;
-       perf_session__update_sample_type(top->session);
+       perf_session__set_id_hdr_size(top->session);
 
        /* Wait for a minimal set of events before starting the snapshot */
        poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
index 1b197280c621fea866e3bfd90f71f3213971ee4a..d84870b0642627b11b81b5b5dc1c0abade1a09e4 100644 (file)
@@ -197,9 +197,6 @@ int perf_event__preprocess_sample(const union perf_event *self,
 
 const char *perf_event__name(unsigned int id);
 
-int perf_event__parse_sample(const union perf_event *event, u64 type,
-                            int sample_size, bool sample_id_all,
-                            struct perf_sample *sample, bool swapped);
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
                                  const struct perf_sample *sample,
                                  bool swapped);
index 3edfd3483816dfa88ac49dc966d0c2a4db2b5923..9b38681add9e2d46e3a02b8ca0ffe48363a3e3c5 100644 (file)
@@ -881,3 +881,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
 
        return 0;
 }
+
+int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
+                             struct perf_sample *sample, bool swapped)
+{
+       struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node);
+       return perf_evsel__parse_sample(e, event, sample, swapped);
+}
index 40d4d3cdced0e081ec41863abe6ab46c562a3e3a..528c1acd9298443ce37afee8a2f3be515f49adfe 100644 (file)
@@ -122,6 +122,9 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
 u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
 
+int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
+                             struct perf_sample *sample, bool swapped);
+
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
 
index e81771364867bd2b5d7bf52e38e9ae0984316a0a..2eaae140def26b5ef952d814e47a1a3179d8abbb 100644 (file)
@@ -20,7 +20,7 @@
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
 
-int __perf_evsel__sample_size(u64 sample_type)
+static int __perf_evsel__sample_size(u64 sample_type)
 {
        u64 mask = sample_type & PERF_SAMPLE_MASK;
        int size = 0;
@@ -53,6 +53,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
        evsel->attr        = *attr;
        INIT_LIST_HEAD(&evsel->node);
        hists__init(&evsel->hists);
+       evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
 }
 
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -728,10 +729,10 @@ static bool sample_overlap(const union perf_event *event,
        return false;
 }
 
-int perf_event__parse_sample(const union perf_event *event, u64 type,
-                            int sample_size, bool sample_id_all,
+int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
                             struct perf_sample *data, bool swapped)
 {
+       u64 type = evsel->attr.sample_type;
        const u64 *array;
 
        /*
@@ -746,14 +747,14 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
        data->period = 1;
 
        if (event->header.type != PERF_RECORD_SAMPLE) {
-               if (!sample_id_all)
+               if (!evsel->attr.sample_id_all)
                        return 0;
                return perf_event__parse_id_sample(event, type, data, swapped);
        }
 
        array = event->sample.array;
 
-       if (sample_size + sizeof(event->header) > event->header.size)
+       if (evsel->sample_size + sizeof(event->header) > event->header.size)
                return -EFAULT;
 
        if (type & PERF_SAMPLE_IP) {
@@ -895,7 +896,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
                u.val32[1] = sample->tid;
                if (swapped) {
                        /*
-                        * Inverse of what is done in perf_event__parse_sample
+                        * Inverse of what is done in perf_evsel__parse_sample
                         */
                        u.val32[0] = bswap_32(u.val32[0]);
                        u.val32[1] = bswap_32(u.val32[1]);
@@ -930,7 +931,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
                u.val32[0] = sample->cpu;
                if (swapped) {
                        /*
-                        * Inverse of what is done in perf_event__parse_sample
+                        * Inverse of what is done in perf_evsel__parse_sample
                         */
                        u.val32[0] = bswap_32(u.val32[0]);
                        u.val64 = bswap_64(u.val64);
index 67cc5033d19234e28071523f51ecf7c7186822b1..b559929983bbefd2e991fdf26e338fe588570a66 100644 (file)
@@ -65,6 +65,7 @@ struct perf_evsel {
                void            *func;
                void            *data;
        } handler;
+       unsigned int            sample_size;
        bool                    supported;
 };
 
@@ -177,13 +178,8 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
        return __perf_evsel__read(evsel, ncpus, nthreads, true);
 }
 
-int __perf_evsel__sample_size(u64 sample_type);
-
-static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
-{
-       return __perf_evsel__sample_size(evsel->attr.sample_type);
-}
-
 void hists__init(struct hists *hists);
 
+int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
+                            struct perf_sample *sample, bool swapped);
 #endif /* __PERF_EVSEL_H */
index 3a6d20443330b13d74b2b69b4c1d0e39cd5bb678..74ea3c2f81382c2881d9eda1e1cfb451b2a138f7 100644 (file)
@@ -174,6 +174,15 @@ perf_header__set_cmdline(int argc, const char **argv)
 {
        int i;
 
+       /*
+        * If header_argv has already been set, do not override it.
+        * This allows a command to set the cmdline, parse args and
+        * then call another builtin function that implements a
+        * command -- e.g, cmd_kvm calling cmd_record.
+        */
+       if (header_argv)
+               return 0;
+
        header_argc = (u32)argc;
 
        /* do not include NULL termination */
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
new file mode 100644 (file)
index 0000000..fd530dc
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Based on intlist.c by:
+ * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <linux/compiler.h>
+
+#include "intlist.h"
+
+static struct rb_node *intlist__node_new(struct rblist *rblist __used,
+                                        const void *entry)
+{
+       int i = (int)((long)entry);
+       struct rb_node *rc = NULL;
+       struct int_node *node = malloc(sizeof(*node));
+
+       if (node != NULL) {
+               node->i = i;
+               rc = &node->rb_node;
+       }
+
+       return rc;
+}
+
+static void int_node__delete(struct int_node *ilist)
+{
+       free(ilist);
+}
+
+static void intlist__node_delete(struct rblist *rblist __used,
+                                struct rb_node *rb_node)
+{
+       struct int_node *node = container_of(rb_node, struct int_node, rb_node);
+
+       int_node__delete(node);
+}
+
+static int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
+{
+       int i = (int)((long)entry);
+       struct int_node *node = container_of(rb_node, struct int_node, rb_node);
+
+       return node->i - i;
+}
+
+int intlist__add(struct intlist *ilist, int i)
+{
+       return rblist__add_node(&ilist->rblist, (void *)((long)i));
+}
+
+void intlist__remove(struct intlist *ilist __used, struct int_node *node)
+{
+       int_node__delete(node);
+}
+
+struct int_node *intlist__find(struct intlist *ilist, int i)
+{
+       struct int_node *node = NULL;
+       struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
+
+       if (rb_node)
+               node = container_of(rb_node, struct int_node, rb_node);
+
+       return node;
+}
+
+struct intlist *intlist__new(void)
+{
+       struct intlist *ilist = malloc(sizeof(*ilist));
+
+       if (ilist != NULL) {
+               rblist__init(&ilist->rblist);
+               ilist->rblist.node_cmp    = intlist__node_cmp;
+               ilist->rblist.node_new    = intlist__node_new;
+               ilist->rblist.node_delete = intlist__node_delete;
+       }
+
+       return ilist;
+}
+
+void intlist__delete(struct intlist *ilist)
+{
+       if (ilist != NULL)
+               rblist__delete(&ilist->rblist);
+}
+
+struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
+{
+       struct int_node *node = NULL;
+       struct rb_node *rb_node;
+
+       rb_node = rblist__entry(&ilist->rblist, idx);
+       if (rb_node)
+               node = container_of(rb_node, struct int_node, rb_node);
+
+       return node;
+}
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
new file mode 100644 (file)
index 0000000..6d63ab9
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef __PERF_INTLIST_H
+#define __PERF_INTLIST_H
+
+#include <linux/rbtree.h>
+#include <stdbool.h>
+
+#include "rblist.h"
+
+struct int_node {
+       struct rb_node rb_node;
+       int i;
+};
+
+struct intlist {
+       struct rblist rblist;
+};
+
+struct intlist *intlist__new(void);
+void intlist__delete(struct intlist *ilist);
+
+void intlist__remove(struct intlist *ilist, struct int_node *in);
+int intlist__add(struct intlist *ilist, int i);
+
+struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
+struct int_node *intlist__find(struct intlist *ilist, int i);
+
+static inline bool intlist__has_entry(struct intlist *ilist, int i)
+{
+       return intlist__find(ilist, i) != NULL;
+}
+
+static inline bool intlist__empty(const struct intlist *ilist)
+{
+       return rblist__empty(&ilist->rblist);
+}
+
+static inline unsigned int intlist__nr_entries(const struct intlist *ilist)
+{
+       return rblist__nr_entries(&ilist->rblist);
+}
+
+/* For intlist iteration */
+static inline struct int_node *intlist__first(struct intlist *ilist)
+{
+       struct rb_node *rn = rb_first(&ilist->rblist.entries);
+       return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
+}
+static inline struct int_node *intlist__next(struct int_node *in)
+{
+       struct rb_node *rn;
+       if (!in)
+               return NULL;
+       rn = rb_next(&in->rb_node);
+       return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
+}
+
+/**
+ * intlist_for_each      - iterate over a intlist
+ * @pos:       the &struct int_node to use as a loop cursor.
+ * @ilist:     the &struct intlist for loop.
+ */
+#define intlist__for_each(pos, ilist)  \
+       for (pos = intlist__first(ilist); pos; pos = intlist__next(pos))
+
+/**
+ * intlist_for_each_safe - iterate over a intlist safe against removal of
+ *                         int_node
+ * @pos:       the &struct int_node to use as a loop cursor.
+ * @n:         another &struct int_node to use as temporary storage.
+ * @ilist:     the &struct intlist for loop.
+ */
+#define intlist__for_each_safe(pos, n, ilist)  \
+       for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\
+            pos = n, n = intlist__next(n))
+#endif /* __PERF_INTLIST_H */
index 1b997d2b89ce2638f63c01aee63c2b7884028427..127d648cc5488e6b1216ce3d3428c7a69e5157fb 100644 (file)
@@ -13,6 +13,9 @@ do { \
        } \
 } while (0)
 
+#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
+                            PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
+
 static int test__checkevent_tracepoint(struct perf_evlist *evlist)
 {
        struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -21,8 +24,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
        TEST_ASSERT_VAL("wrong sample_type",
-               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-               evsel->attr.sample_type);
+               PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
        TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
        return 0;
 }
@@ -37,8 +39,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
                TEST_ASSERT_VAL("wrong type",
                        PERF_TYPE_TRACEPOINT == evsel->attr.type);
                TEST_ASSERT_VAL("wrong sample_type",
-                       (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
-                       == evsel->attr.sample_type);
+                       PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
                TEST_ASSERT_VAL("wrong sample_period",
                        1 == evsel->attr.sample_period);
        }
@@ -428,8 +429,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
        evsel = list_entry(evsel->node.next, struct perf_evsel, node);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
        TEST_ASSERT_VAL("wrong sample_type",
-               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-               evsel->attr.sample_type);
+               PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
        TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
        TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
        TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
index 99d02aa57dbf19a8c0cb1a1a3a900486ef956b65..594f8fad5ecd5ae3e858899173b1a18403335dc0 100644 (file)
@@ -1,6 +1,7 @@
 #include "util.h"
 #include "parse-options.h"
 #include "cache.h"
+#include "header.h"
 
 #define OPT_SHORT 1
 #define OPT_UNSET 2
@@ -413,6 +414,8 @@ int parse_options(int argc, const char **argv, const struct option *options,
 {
        struct parse_opt_ctx_t ctx;
 
+       perf_header__set_cmdline(argc, argv);
+
        parse_options_start(&ctx, argc, argv, flags);
        switch (parse_options_step(&ctx, options, usagestr)) {
        case PARSE_OPT_HELP:
index e03b58a4842431d51edaf68ec6da95cec6caadf5..0688bfb6d280a3b8ae3b8c0e3a474f51b9a404c2 100644 (file)
@@ -797,17 +797,13 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
 
        event = perf_evlist__mmap_read(evlist, cpu);
        if (event != NULL) {
-               struct perf_evsel *first;
                PyObject *pyevent = pyrf_event__new(event);
                struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
 
                if (pyevent == NULL)
                        return PyErr_NoMemory();
 
-               first = list_entry(evlist->entries.next, struct perf_evsel, node);
-               err = perf_event__parse_sample(event, first->attr.sample_type,
-                                              perf_evsel__sample_size(first),
-                                              sample_id_all, &pevent->sample, false);
+               err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
                if (err)
                        return PyErr_Format(PyExc_OSError,
                                            "perf: can't parse sample, err=%d", err);
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
new file mode 100644 (file)
index 0000000..0171fb6
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Based on strlist.c by:
+ * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rblist.h"
+
+int rblist__add_node(struct rblist *rblist, const void *new_entry)
+{
+       struct rb_node **p = &rblist->entries.rb_node;
+       struct rb_node *parent = NULL, *new_node;
+
+       while (*p != NULL) {
+               int rc;
+
+               parent = *p;
+
+               rc = rblist->node_cmp(parent, new_entry);
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       new_node = rblist->node_new(rblist, new_entry);
+       if (new_node == NULL)
+               return -ENOMEM;
+
+       rb_link_node(new_node, parent, p);
+       rb_insert_color(new_node, &rblist->entries);
+       ++rblist->nr_entries;
+
+       return 0;
+}
+
+void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
+{
+       rb_erase(rb_node, &rblist->entries);
+       rblist->node_delete(rblist, rb_node);
+}
+
+struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
+{
+       struct rb_node **p = &rblist->entries.rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*p != NULL) {
+               int rc;
+
+               parent = *p;
+
+               rc = rblist->node_cmp(parent, entry);
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return parent;
+       }
+
+       return NULL;
+}
+
+void rblist__init(struct rblist *rblist)
+{
+       if (rblist != NULL) {
+               rblist->entries  = RB_ROOT;
+               rblist->nr_entries = 0;
+       }
+
+       return;
+}
+
+void rblist__delete(struct rblist *rblist)
+{
+       if (rblist != NULL) {
+               struct rb_node *pos, *next = rb_first(&rblist->entries);
+
+               while (next) {
+                       pos = next;
+                       next = rb_next(pos);
+                       rb_erase(pos, &rblist->entries);
+                       rblist->node_delete(rblist, pos);
+               }
+               free(rblist);
+       }
+}
+
+struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
+{
+       struct rb_node *node;
+
+       for (node = rb_first(&rblist->entries); node; node = rb_next(node)) {
+               if (!idx--)
+                       return node;
+       }
+
+       return NULL;
+}
diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h
new file mode 100644 (file)
index 0000000..6d0cae5
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __PERF_RBLIST_H
+#define __PERF_RBLIST_H
+
+#include <linux/rbtree.h>
+#include <stdbool.h>
+
+/*
+ * create node structs of the form:
+ * struct my_node {
+ *     struct rb_node rb_node;
+ *     ... my data ...
+ * };
+ *
+ * create list structs of the form:
+ * struct mylist {
+ *     struct rblist rblist;
+ *     ... my data ...
+ * };
+ */
+
+struct rblist {
+       struct rb_root entries;
+       unsigned int   nr_entries;
+
+       int (*node_cmp)(struct rb_node *rbn, const void *entry);
+       struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry);
+       void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node);
+};
+
+void rblist__init(struct rblist *rblist);
+void rblist__delete(struct rblist *rblist);
+int rblist__add_node(struct rblist *rblist, const void *new_entry);
+void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
+struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
+struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
+
+static inline bool rblist__empty(const struct rblist *rblist)
+{
+       return rblist->nr_entries == 0;
+}
+
+static inline unsigned int rblist__nr_entries(const struct rblist *rblist)
+{
+       return rblist->nr_entries;
+}
+
+#endif /* __PERF_RBLIST_H */
index 8e4f0755d2aa8364d81fa714888d622d61f6a2db..2437fb0b463a21566ad9c8679861456e4f2b3f05 100644 (file)
@@ -80,14 +80,12 @@ out_close:
        return -1;
 }
 
-void perf_session__update_sample_type(struct perf_session *self)
+void perf_session__set_id_hdr_size(struct perf_session *session)
 {
-       self->sample_type = perf_evlist__sample_type(self->evlist);
-       self->sample_size = __perf_evsel__sample_size(self->sample_type);
-       self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
-       self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
-       self->host_machine.id_hdr_size = self->id_hdr_size;
-       machines__set_id_hdr_size(&self->machines, self->id_hdr_size);
+       u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
+
+       session->host_machine.id_hdr_size = id_hdr_size;
+       machines__set_id_hdr_size(&session->machines, id_hdr_size);
 }
 
 int perf_session__create_kernel_maps(struct perf_session *self)
@@ -147,7 +145,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        if (mode == O_RDONLY) {
                if (perf_session__open(self, force) < 0)
                        goto out_delete;
-               perf_session__update_sample_type(self);
+               perf_session__set_id_hdr_size(self);
        } else if (mode == O_WRONLY) {
                /*
                 * In O_RDONLY mode this will be performed when reading the
@@ -158,7 +156,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        }
 
        if (tool && tool->ordering_requires_timestamps &&
-           tool->ordered_samples && !self->sample_id_all) {
+           tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
                tool->ordered_samples = false;
        }
@@ -673,7 +671,8 @@ static void flush_sample_queue(struct perf_session *s,
                if (iter->timestamp > limit)
                        break;
 
-               ret = perf_session__parse_sample(s, iter->event, &sample);
+               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample,
+                                               s->header.needs_swap);
                if (ret)
                        pr_err("Can't parse sample, err = %d\n", ret);
                else
@@ -865,16 +864,18 @@ static void perf_session__print_tstamp(struct perf_session *session,
                                       union perf_event *event,
                                       struct perf_sample *sample)
 {
+       u64 sample_type = perf_evlist__sample_type(session->evlist);
+
        if (event->header.type != PERF_RECORD_SAMPLE &&
-           !session->sample_id_all) {
+           !perf_evlist__sample_id_all(session->evlist)) {
                fputs("-1 -1 ", stdout);
                return;
        }
 
-       if ((session->sample_type & PERF_SAMPLE_CPU))
+       if ((sample_type & PERF_SAMPLE_CPU))
                printf("%u ", sample->cpu);
 
-       if (session->sample_type & PERF_SAMPLE_TIME)
+       if (sample_type & PERF_SAMPLE_TIME)
                printf("%" PRIu64 " ", sample->time);
 }
 
@@ -899,6 +900,8 @@ static void dump_event(struct perf_session *session, union perf_event *event,
 static void dump_sample(struct perf_session *session, union perf_event *event,
                        struct perf_sample *sample)
 {
+       u64 sample_type;
+
        if (!dump_trace)
                return;
 
@@ -906,10 +909,12 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
               event->header.misc, sample->pid, sample->tid, sample->ip,
               sample->period, sample->addr);
 
-       if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
+       sample_type = perf_evlist__sample_type(session->evlist);
+
+       if (sample_type & PERF_SAMPLE_CALLCHAIN)
                callchain__printf(sample);
 
-       if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
+       if (sample_type & PERF_SAMPLE_BRANCH_STACK)
                branch_stack__printf(sample);
 }
 
@@ -1006,7 +1011,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
                                           union perf_event *event, struct perf_sample *sample)
 {
        if (event->header.type != PERF_RECORD_SAMPLE ||
-           !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
+           !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
                return 0;
 
        if (!ip_callchain__valid(sample->callchain, event)) {
@@ -1030,7 +1035,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
        case PERF_RECORD_HEADER_ATTR:
                err = tool->attr(event, &session->evlist);
                if (err == 0)
-                       perf_session__update_sample_type(session);
+                       perf_session__set_id_hdr_size(session);
                return err;
        case PERF_RECORD_HEADER_EVENT_TYPE:
                return tool->event_type(tool, event);
@@ -1065,7 +1070,7 @@ static int perf_session__process_event(struct perf_session *session,
        int ret;
 
        if (session->header.needs_swap)
-               event_swap(event, session->sample_id_all);
+               event_swap(event, perf_evlist__sample_id_all(session->evlist));
 
        if (event->header.type >= PERF_RECORD_HEADER_MAX)
                return -EINVAL;
@@ -1078,7 +1083,8 @@ static int perf_session__process_event(struct perf_session *session,
        /*
         * For all kernel events we get the sample data
         */
-       ret = perf_session__parse_sample(session, event, &sample);
+       ret = perf_evlist__parse_sample(session->evlist, event, &sample,
+                                       session->header.needs_swap);
        if (ret)
                return ret;
 
@@ -1389,9 +1395,9 @@ int perf_session__process_events(struct perf_session *self,
        return err;
 }
 
-bool perf_session__has_traces(struct perf_session *self, const char *msg)
+bool perf_session__has_traces(struct perf_session *session, const char *msg)
 {
-       if (!(self->sample_type & PERF_SAMPLE_RAW)) {
+       if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) {
                pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
                return false;
        }
index 7c435bde6eb0ea1f913e1dadfca3da0c23432302..1f7ec87db7d7369083895d596a979db460865d23 100644 (file)
@@ -41,13 +41,9 @@ struct perf_session {
         *        perf.data file.
         */
        struct hists            hists;
-       u64                     sample_type;
-       int                     sample_size;
        int                     fd;
        bool                    fd_pipe;
        bool                    repipe;
-       bool                    sample_id_all;
-       u16                     id_hdr_size;
        int                     cwdlen;
        char                    *cwd;
        struct ordered_samples  ordered_samples;
@@ -86,7 +82,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
 
 int perf_session__create_kernel_maps(struct perf_session *self);
 
-void perf_session__update_sample_type(struct perf_session *self);
+void perf_session__set_id_hdr_size(struct perf_session *session);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 
 static inline
@@ -130,24 +126,6 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
 
-static inline int perf_session__parse_sample(struct perf_session *session,
-                                            const union perf_event *event,
-                                            struct perf_sample *sample)
-{
-       return perf_event__parse_sample(event, session->sample_type,
-                                       session->sample_size,
-                                       session->sample_id_all, sample,
-                                       session->header.needs_swap);
-}
-
-static inline int perf_session__synthesize_sample(struct perf_session *session,
-                                                 union perf_event *event,
-                                                 const struct perf_sample *sample)
-{
-       return perf_event__synthesize_sample(event, session->sample_type,
-                                            sample, session->header.needs_swap);
-}
-
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
                                            unsigned int type);
 
index 6783a2043555404f393bcb3bd41e6a13d3495bc6..95856ff3dda417276792c98df568a56ea0c86bd8 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-static struct str_node *str_node__new(const char *s, bool dupstr)
+static
+struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
 {
-       struct str_node *self = malloc(sizeof(*self));
+       const char *s = entry;
+       struct rb_node *rc = NULL;
+       struct strlist *strlist = container_of(rblist, struct strlist, rblist);
+       struct str_node *snode = malloc(sizeof(*snode));
 
-       if (self != NULL) {
-               if (dupstr) {
+       if (snode != NULL) {
+               if (strlist->dupstr) {
                        s = strdup(s);
                        if (s == NULL)
                                goto out_delete;
                }
-               self->s = s;
+               snode->s = s;
+               rc = &snode->rb_node;
        }
 
-       return self;
+       return rc;
 
 out_delete:
-       free(self);
+       free(snode);
        return NULL;
 }
 
@@ -37,36 +42,26 @@ static void str_node__delete(struct str_node *self, bool dupstr)
        free(self);
 }
 
-int strlist__add(struct strlist *self, const char *new_entry)
+static
+void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
 {
-       struct rb_node **p = &self->entries.rb_node;
-       struct rb_node *parent = NULL;
-       struct str_node *sn;
-
-       while (*p != NULL) {
-               int rc;
-
-               parent = *p;
-               sn = rb_entry(parent, struct str_node, rb_node);
-               rc = strcmp(sn->s, new_entry);
-
-               if (rc > 0)
-                       p = &(*p)->rb_left;
-               else if (rc < 0)
-                       p = &(*p)->rb_right;
-               else
-                       return -EEXIST;
-       }
+       struct strlist *slist = container_of(rblist, struct strlist, rblist);
+       struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
 
-       sn = str_node__new(new_entry, self->dupstr);
-       if (sn == NULL)
-               return -ENOMEM;
+       str_node__delete(snode, slist->dupstr);
+}
 
-       rb_link_node(&sn->rb_node, parent, p);
-       rb_insert_color(&sn->rb_node, &self->entries);
-       ++self->nr_entries;
+static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
+{
+       const char *str = entry;
+       struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
+
+       return strcmp(snode->s, str);
+}
 
-       return 0;
+int strlist__add(struct strlist *self, const char *new_entry)
+{
+       return rblist__add_node(&self->rblist, new_entry);
 }
 
 int strlist__load(struct strlist *self, const char *filename)
@@ -96,34 +91,20 @@ out:
        return err;
 }
 
-void strlist__remove(struct strlist *self, struct str_node *sn)
+void strlist__remove(struct strlist *slist, struct str_node *snode)
 {
-       rb_erase(&sn->rb_node, &self->entries);
-       str_node__delete(sn, self->dupstr);
+       str_node__delete(snode, slist->dupstr);
 }
 
-struct str_node *strlist__find(struct strlist *self, const char *entry)
+struct str_node *strlist__find(struct strlist *slist, const char *entry)
 {
-       struct rb_node **p = &self->entries.rb_node;
-       struct rb_node *parent = NULL;
-
-       while (*p != NULL) {
-               struct str_node *sn;
-               int rc;
-
-               parent = *p;
-               sn = rb_entry(parent, struct str_node, rb_node);
-               rc = strcmp(sn->s, entry);
-
-               if (rc > 0)
-                       p = &(*p)->rb_left;
-               else if (rc < 0)
-                       p = &(*p)->rb_right;
-               else
-                       return sn;
-       }
+       struct str_node *snode = NULL;
+       struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
 
-       return NULL;
+       if (rb_node)
+               snode = container_of(rb_node, struct str_node, rb_node);
+
+       return snode;
 }
 
 static int strlist__parse_list_entry(struct strlist *self, const char *s)
@@ -156,9 +137,12 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
        struct strlist *self = malloc(sizeof(*self));
 
        if (self != NULL) {
-               self->entries    = RB_ROOT;
+               rblist__init(&self->rblist);
+               self->rblist.node_cmp    = strlist__node_cmp;
+               self->rblist.node_new    = strlist__node_new;
+               self->rblist.node_delete = strlist__node_delete;
+
                self->dupstr     = dupstr;
-               self->nr_entries = 0;
                if (slist && strlist__parse_list(self, slist) != 0)
                        goto out_error;
        }
@@ -171,30 +155,18 @@ out_error:
 
 void strlist__delete(struct strlist *self)
 {
-       if (self != NULL) {
-               struct str_node *pos;
-               struct rb_node *next = rb_first(&self->entries);
-
-               while (next) {
-                       pos = rb_entry(next, struct str_node, rb_node);
-                       next = rb_next(&pos->rb_node);
-                       strlist__remove(self, pos);
-               }
-               self->entries = RB_ROOT;
-               free(self);
-       }
+       if (self != NULL)
+               rblist__delete(&self->rblist);
 }
 
-struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
+struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
 {
-       struct rb_node *nd;
+       struct str_node *snode = NULL;
+       struct rb_node *rb_node;
 
-       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
-               struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
+       rb_node = rblist__entry(&slist->rblist, idx);
+       if (rb_node)
+               snode = container_of(rb_node, struct str_node, rb_node);
 
-               if (!idx--)
-                       return pos;
-       }
-
-       return NULL;
+       return snode;
 }
index 3ba839007d2c975c49e4f3f286e9d64eff3d3f60..dd9f922ec67c58845ff22b6d3fabe3eb888c21e6 100644 (file)
@@ -4,14 +4,15 @@
 #include <linux/rbtree.h>
 #include <stdbool.h>
 
+#include "rblist.h"
+
 struct str_node {
        struct rb_node rb_node;
        const char     *s;
 };
 
 struct strlist {
-       struct rb_root entries;
-       unsigned int   nr_entries;
+       struct rblist rblist;
        bool           dupstr;
 };
 
@@ -32,18 +33,18 @@ static inline bool strlist__has_entry(struct strlist *self, const char *entry)
 
 static inline bool strlist__empty(const struct strlist *self)
 {
-       return self->nr_entries == 0;
+       return rblist__empty(&self->rblist);
 }
 
 static inline unsigned int strlist__nr_entries(const struct strlist *self)
 {
-       return self->nr_entries;
+       return rblist__nr_entries(&self->rblist);
 }
 
 /* For strlist iteration */
 static inline struct str_node *strlist__first(struct strlist *self)
 {
-       struct rb_node *rn = rb_first(&self->entries);
+       struct rb_node *rn = rb_first(&self->rblist.entries);
        return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
 }
 static inline struct str_node *strlist__next(struct str_node *sn)
index fdad4eeeb429c1fce9ef90125aab3e4a288c6066..8b63b678e127ba5253477db6c65355e28ae49e66 100644 (file)
@@ -64,7 +64,7 @@ static enum dso_binary_type binary_type_symtab[] = {
        DSO_BINARY_TYPE__NOT_FOUND,
 };
 
-#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab)
+#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
 
 static enum dso_binary_type binary_type_data[] = {
        DSO_BINARY_TYPE__BUILD_ID_CACHE,
@@ -72,7 +72,7 @@ static enum dso_binary_type binary_type_data[] = {
        DSO_BINARY_TYPE__NOT_FOUND,
 };
 
-#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data)
+#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
 
 int dso__name_len(const struct dso *dso)
 {
@@ -2875,6 +2875,7 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
        int i, items = 0;
        char path[PATH_MAX];
        pid_t pid;
+       char *endp;
 
        if (symbol_conf.default_guest_vmlinux_name ||
            symbol_conf.default_guest_modules ||
@@ -2891,7 +2892,14 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
                                /* Filter out . and .. */
                                continue;
                        }
-                       pid = atoi(namelist[i]->d_name);
+                       pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
+                       if ((*endp != '\0') ||
+                           (endp == namelist[i]->d_name) ||
+                           (errno == ERANGE)) {
+                               pr_debug("invalid directory (%s). Skipping.\n",
+                                        namelist[i]->d_name);
+                               continue;
+                       }
                        sprintf(path, "%s/%s/proc/kallsyms",
                                symbol_conf.guestmount,
                                namelist[i]->d_name);
index 3f59c496e64c9035311389fb73e9468fb47e7889..051eaa68095e75a61b82aac4c479cf4c8101ef71 100644 (file)
@@ -110,7 +110,7 @@ int perf_target__strerror(struct perf_target *target, int errnum,
        int idx;
        const char *msg;
 
-       BUG_ON(buflen > 0);
+       BUG_ON(buflen == 0);
 
        if (errnum >= 0) {
                const char *err = strerror_r(errnum, buf, buflen);
index b0adb2710c0220660b0e76bc7a1d6cab73916c34..68d0734b2081718eeb762e6dcdfa77898d7f7b6c 100644 (file)
@@ -253,9 +253,6 @@ static int find_testdev(const char *name, const struct stat *sb, int flag)
 
        if (flag != FTW_F)
                return 0;
-       /* ignore /proc/bus/usb/{devices,drivers} */
-       if (strrchr(name, '/')[1] == 'd')
-               return 0;
 
        fd = fopen(name, "rb");
        if (!fd) {
@@ -356,28 +353,8 @@ restart:
 
 static const char *usbfs_dir_find(void)
 {
-       static char usbfs_path_0[] = "/dev/usb/devices";
-       static char usbfs_path_1[] = "/proc/bus/usb/devices";
        static char udev_usb_path[] = "/dev/bus/usb";
 
-       static char *const usbfs_paths[] = {
-               usbfs_path_0, usbfs_path_1
-       };
-
-       static char *const *
-               end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths;
-
-       char *const *it = usbfs_paths;
-       do {
-               int fd = open(*it, O_RDONLY);
-               close(fd);
-               if (fd >= 0) {
-                       strrchr(*it, '/')[0] = '\0';
-                       return *it;
-               }
-       } while (++it != end);
-
-       /* real device-nodes managed by udev */
        if (access(udev_usb_path, F_OK) == 0)
                return udev_usb_path;
 
@@ -489,7 +466,7 @@ usage:
                goto usage;
        if (!all && !device) {
                fprintf (stderr, "must specify '-a' or '-D dev', "
-                       "or DEVICE=/proc/bus/usb/BBB/DDD in env\n");
+                       "or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
                goto usage;
        }