]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge branch 'fix/asoc' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Fri, 26 Nov 2010 16:17:42 +0000 (17:17 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 26 Nov 2010 16:17:42 +0000 (17:17 +0100)
1121 files changed:
Documentation/ABI/obsolete/proc-pid-oom_adj [new file with mode: 0644]
Documentation/DocBook/uio-howto.tmpl
Documentation/arm/OMAP/DSS
Documentation/block/switching-sched.txt
Documentation/development-process/2.Process
Documentation/feature-removal-schedule.txt
Documentation/filesystems/configfs/configfs_example_explicit.c
Documentation/filesystems/xfs-delayed-logging-design.txt
Documentation/gpio.txt
Documentation/hwmon/lm93
Documentation/hwmon/max6650
Documentation/kernel-parameters.txt
Documentation/leds-class.txt
Documentation/leds/leds-lp5521.txt [new file with mode: 0644]
Documentation/leds/leds-lp5523.txt [new file with mode: 0644]
Documentation/networking/ip-sysctl.txt
Documentation/power/opp.txt
Documentation/rbtree.txt
Documentation/sysctl/kernel.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/common/gic.c
arch/arm/include/asm/hardware/it8152.h
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/stacktrace.c
arch/arm/kernel/traps.c
arch/arm/kernel/unwind.c
arch/arm/mach-ep93xx/include/mach/dma.h
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/d2net_v2-setup.c
arch/arm/mach-kirkwood/lacie_v2-common.c
arch/arm/mach-kirkwood/lacie_v2-common.h
arch/arm/mach-kirkwood/mpp.c
arch/arm/mach-kirkwood/netspace_v2-setup.c
arch/arm/mach-kirkwood/netxbig_v2-setup.c
arch/arm/mach-kirkwood/ts41x-setup.c
arch/arm/mach-mmp/include/mach/cputype.h
arch/arm/mach-mv78xx0/mpp.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/include/mach/camera.h
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-orion5x/mpp.c
arch/arm/mach-orion5x/ts78xx-setup.c
arch/arm/mach-pxa/cm-x2xx.c
arch/arm/mach-pxa/saar.c
arch/arm/mach-s3c64xx/Kconfig
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/include/mach/gpio.h
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mm/dma-mapping.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-orion/include/plat/pcie.h
arch/arm/plat-orion/pcie.c
arch/blackfin/kernel/process.c
arch/frv/kernel/process.c
arch/h8300/kernel/process.c
arch/ia64/hp/sim/simscsi.c
arch/m68k/include/asm/irqflags.h
arch/m68k/include/asm/machdep.h
arch/m68k/kernel/process.c
arch/m68knommu/kernel/process.c
arch/mn10300/kernel/process.c
arch/parisc/hpux/sys_hpux.c
arch/parisc/kernel/sys_parisc32.c
arch/powerpc/Kconfig
arch/powerpc/boot/div64.S
arch/powerpc/kernel/kgdb.c
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/sys_ppc32.c
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/timing.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/tlb_low_64e.S
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/s390/Kconfig.debug
arch/s390/include/asm/page.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/kprobes.c
arch/s390/mm/gup.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/Makefile
arch/sh/boards/board-edosk7705.c [new file with mode: 0644]
arch/sh/boards/board-secureedge5410.c [new file with mode: 0644]
arch/sh/boards/mach-edosk7705/Makefile [deleted file]
arch/sh/boards/mach-edosk7705/io.c [deleted file]
arch/sh/boards/mach-edosk7705/setup.c [deleted file]
arch/sh/boards/mach-microdev/io.c
arch/sh/boards/mach-microdev/setup.c
arch/sh/boards/mach-se/7206/Makefile
arch/sh/boards/mach-se/7206/io.c [deleted file]
arch/sh/boards/mach-se/7206/irq.c
arch/sh/boards/mach-se/7206/setup.c
arch/sh/boards/mach-se/770x/Makefile
arch/sh/boards/mach-se/770x/io.c [deleted file]
arch/sh/boards/mach-se/770x/setup.c
arch/sh/boards/mach-se/7751/Makefile
arch/sh/boards/mach-se/7751/io.c [deleted file]
arch/sh/boards/mach-se/7751/setup.c
arch/sh/boards/mach-snapgear/Makefile [deleted file]
arch/sh/boards/mach-snapgear/io.c [deleted file]
arch/sh/boards/mach-snapgear/setup.c [deleted file]
arch/sh/boards/mach-systemh/Makefile [deleted file]
arch/sh/boards/mach-systemh/io.c [deleted file]
arch/sh/boards/mach-systemh/irq.c [deleted file]
arch/sh/boards/mach-systemh/setup.c [deleted file]
arch/sh/configs/secureedge5410_defconfig [new file with mode: 0644]
arch/sh/configs/snapgear_defconfig [deleted file]
arch/sh/configs/systemh_defconfig [deleted file]
arch/sh/include/asm/addrspace.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/system.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/system_64.h
arch/sh/include/asm/uncached.h
arch/sh/include/mach-common/mach/edosk7705.h [deleted file]
arch/sh/include/mach-common/mach/microdev.h
arch/sh/include/mach-common/mach/secureedge5410.h [new file with mode: 0644]
arch/sh/include/mach-common/mach/snapgear.h [deleted file]
arch/sh/include/mach-common/mach/systemh7751.h [deleted file]
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/mm/Kconfig
arch/sh/mm/consistent.c
arch/sh/mm/uncached.c
arch/sh/tools/mach-types
arch/sparc/kernel/leon_smp.c
arch/sparc/kernel/sys_sparc32.c
arch/sparc/kernel/sys_sparc_32.c
arch/sparc/kernel/unaligned_32.c
arch/sparc/kernel/windows.c
arch/tile/include/asm/highmem.h
arch/tile/include/asm/kmap_types.h
arch/tile/include/asm/pgtable.h
arch/tile/include/asm/stat.h
arch/tile/include/asm/unistd.h
arch/tile/kernel/compat.c
arch/tile/kernel/compat_signal.c
arch/tile/kernel/early_printk.c
arch/tile/kernel/hardwall.c
arch/tile/kernel/irq.c
arch/tile/kernel/machine_kexec.c
arch/tile/kernel/messaging.c
arch/tile/kernel/ptrace.c
arch/tile/kernel/reboot.c
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/smp.c
arch/tile/kernel/smpboot.c
arch/tile/kernel/sys.c
arch/tile/kernel/time.c
arch/tile/lib/memcpy_tile64.c
arch/tile/mm/fault.c
arch/tile/mm/highmem.c
arch/tile/mm/hugetlbpage.c
arch/tile/mm/init.c
arch/tile/mm/pgtable.c
arch/um/include/asm/ptrace-generic.h
arch/um/kernel/exec.c
arch/um/kernel/ptrace.c
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/apic.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/include/asm/xen/interface.h
arch/x86/include/asm/xen/interface_32.h
arch/x86/include/asm/xen/interface_64.h
arch/x86/include/asm/xen/page.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/microcode_amd.c
arch/x86/kernel/mmconf-fam10h_64.c
arch/x86/kernel/msr.c
arch/x86/kernel/pvclock.c
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/tlb.c
arch/x86/pci/acpi.c
arch/x86/pci/xen.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/setup.c
block/blk-core.c
block/blk-ioc.c
block/blk-map.c
block/compat_ioctl.c
block/elevator.c
block/ioctl.c
block/scsi_ioctl.c
crypto/pcrypt.c
drivers/Makefile
drivers/acpi/debugfs.c
drivers/ata/libata-scsi.c
drivers/ata/pata_legacy.c
drivers/ata/pata_octeon_cf.c
drivers/ata/sata_via.c
drivers/atm/solos-attrlist.c
drivers/atm/solos-pci.c
drivers/base/power/main.c
drivers/block/aoe/aoeblk.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_scsi.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_proc.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_worker.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/xen-blkfront.c
drivers/bluetooth/btusb.c
drivers/char/.gitignore [deleted file]
drivers/char/Makefile
drivers/char/agp/frontend.c
drivers/char/agp/intel-gtt.c
drivers/char/amiserial.c
drivers/char/briq_panel.c
drivers/char/consolemap.c [deleted file]
drivers/char/cp437.uni [deleted file]
drivers/char/defkeymap.c_shipped [deleted file]
drivers/char/defkeymap.map [deleted file]
drivers/char/hpet.c
drivers/char/hw_random/core.c
drivers/char/i8k.c
drivers/char/istallion.c
drivers/char/keyboard.c [deleted file]
drivers/char/n_gsm.c [deleted file]
drivers/char/n_hdlc.c [deleted file]
drivers/char/n_r3964.c [deleted file]
drivers/char/n_tty.c [deleted file]
drivers/char/nozomi.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/pty.c [deleted file]
drivers/char/selection.c [deleted file]
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/stallion.c
drivers/char/sx.c
drivers/char/sysrq.c [deleted file]
drivers/char/tty_audit.c [deleted file]
drivers/char/tty_buffer.c [deleted file]
drivers/char/tty_io.c [deleted file]
drivers/char/tty_ioctl.c [deleted file]
drivers/char/tty_ldisc.c [deleted file]
drivers/char/tty_mutex.c [deleted file]
drivers/char/tty_port.c [deleted file]
drivers/char/uv_mmtimer.c
drivers/char/vc_screen.c [deleted file]
drivers/char/vt.c [deleted file]
drivers/char/vt_ioctl.c [deleted file]
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/crypto/n2_core.c
drivers/crypto/padlock-aes.c
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_suspend.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_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/nouveau/nouveau_backlight.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_hw.c
drivers/gpu/drm/nouveau/nouveau_hw.h
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_ramht.c
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_temp.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_pm.c
drivers/gpu/drm/nouveau/nv50_calc.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fifo.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_blit_kms.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit_kms.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_atombios.c
drivers/gpu/drm/radeon/radeon_benchmark.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_irq.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_manager.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/via/via_dmablit.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/stub/Kconfig
drivers/hid/hidraw.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/ad7414.c
drivers/hwmon/adt7470.c
drivers/hwmon/amc6821.c
drivers/hwmon/gpio-fan.c
drivers/hwmon/lm93.c
drivers/hwmon/lm95241.c
drivers/hwmon/ltc4261.c
drivers/hwmon/max6650.c
drivers/hwmon/w83795.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-mux.c
drivers/infiniband/hw/ipath/ipath_file_ops.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/input.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/atkbd.c
drivers/input/misc/pcf8574_keypad.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/serio_raw.c
drivers/input/tablet/acecad.c
drivers/input/tablet/aiptek.c
drivers/isdn/hisax/isar.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/led-triggers.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lp5521.c [new file with mode: 0644]
drivers/leds/leds-lp5523.c [new file with mode: 0644]
drivers/leds/leds-net5501.c
drivers/leds/ledtrig-timer.c
drivers/macintosh/adb-iop.c
drivers/md/md.c
drivers/media/Kconfig
drivers/media/common/saa7146_i2c.c
drivers/media/dvb/dvb-core/dvb_ca_en50221.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/frontends/dibx000_common.c
drivers/media/dvb/ngene/ngene-core.c
drivers/media/dvb/ngene/ngene-dvb.c
drivers/media/dvb/ngene/ngene-i2c.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cafe_ccic.c
drivers/media/video/cx231xx/cx231xx-417.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/imx074.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/omap1_camera.c
drivers/media/video/ov6650.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7164/saa7164.h
drivers/media/video/se401.c
drivers/media/video/stk-webcam.c
drivers/media/video/tlg2300/pd-main.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-dev.c
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_driver.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptspi.c
drivers/message/i2o/i2o_scsi.c
drivers/misc/apds9802als.c
drivers/misc/bh1770glc.c
drivers/misc/isl29020.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/atl1c/atl1c_hw.c
drivers/net/atlx/atl1.c
drivers/net/benet/be_main.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bonding/bond_main.c
drivers/net/caif/caif_spi.c
drivers/net/caif/caif_spi_slave.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/cxgb4vf/sge.c
drivers/net/cxgb4vf/t4vf_common.h
drivers/net/cxgb4vf/t4vf_hw.c
drivers/net/e1000/e1000_main.c
drivers/net/gianfar.c
drivers/net/gianfar_ethtool.c
drivers/net/ibm_newemac/core.c
drivers/net/ipg.c
drivers/net/irda/sh_sir.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/jme.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/phy/marvell.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/qlge/qlge_main.c
drivers/net/r8169.c
drivers/net/skge.c
drivers/net/smsc911x.h
drivers/net/tulip/de2104x.c
drivers/net/ucc_geth.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/carl9170/usb.c
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/rt2x00/Kconfig
drivers/parisc/eisa_eeprom.c
drivers/pci/bus.c
drivers/pci/hotplug/ibmphp_ebda.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/proc.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/pd6729.h
drivers/pcmcia/pxa2xx_sharpsl.c
drivers/pcmcia/sa1100_assabet.c
drivers/pcmcia/sa1100_cerf.c
drivers/pcmcia/sa1100_generic.c
drivers/pcmcia/sa1100_h3600.c
drivers/pcmcia/sa1100_shannon.c
drivers/pcmcia/sa1100_simpad.c
drivers/pcmcia/soc_common.c
drivers/pnp/isapnp/proc.c
drivers/rapidio/rio.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-sh.c
drivers/s390/block/dasd_eer.c
drivers/s390/char/fs3270.c
drivers/s390/char/tape_char.c
drivers/s390/char/tape_core.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/cio/device.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-sas.c
drivers/scsi/3w-xxxx.c
drivers/scsi/53c700.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/NCR53c406a.c
drivers/scsi/a100u2w.c
drivers/scsi/aacraid/linit.c
drivers/scsi/advansys.c
drivers/scsi/aha152x.c
drivers/scsi/aha1542.c
drivers/scsi/aha1542.h
drivers/scsi/aha1740.c
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/aic7xxx_old.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/arm/acornscsi.c
drivers/scsi/arm/fas216.c
drivers/scsi/arm/fas216.h
drivers/scsi/atari_NCR5380.c
drivers/scsi/atari_scsi.c
drivers/scsi/atp870u.c
drivers/scsi/bfa/bfad_im.c
drivers/scsi/dc395x.c
drivers/scsi/dpt_i2o.c
drivers/scsi/dpti.h
drivers/scsi/dtc.h
drivers/scsi/eata.c
drivers/scsi/eata_pio.c
drivers/scsi/esp_scsi.c
drivers/scsi/fd_mcs.c
drivers/scsi/fdomain.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/g_NCR5380.h
drivers/scsi/gdth.c
drivers/scsi/hpsa.c
drivers/scsi/hptiop.c
drivers/scsi/ibmmca.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/imm.c
drivers/scsi/in2000.c
drivers/scsi/in2000.h
drivers/scsi/initio.c
drivers/scsi/ipr.c
drivers/scsi/ips.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/mac53c94.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/mesh.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/nsp32.c
drivers/scsi/pas16.h
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/nsp_cs.h
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/pm8001/pm8001_sas.h
drivers/scsi/pmcraid.c
drivers/scsi/ppa.c
drivers/scsi/ps3rom.c
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qlogicfas408.c
drivers/scsi/qlogicfas408.h
drivers/scsi/qlogicpti.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/sd.c
drivers/scsi/stex.c
drivers/scsi/sun3_NCR5380.c
drivers/scsi/sun3_scsi.h
drivers/scsi/sym53c416.c
drivers/scsi/sym53c416.h
drivers/scsi/sym53c8xx_2/sym_glue.c
drivers/scsi/t128.h
drivers/scsi/tmscsim.c
drivers/scsi/u14-34f.c
drivers/scsi/ultrastor.c
drivers/scsi/ultrastor.h
drivers/scsi/vmw_pvscsi.c
drivers/scsi/wd33c93.c
drivers/scsi/wd33c93.h
drivers/scsi/wd7000.c
drivers/serial/8250_pci.c
drivers/serial/bfin_5xx.c
drivers/serial/crisv10.c
drivers/serial/kgdboc.c
drivers/serial/serial_core.c
drivers/sh/clk/core.c
drivers/sh/intc/core.c
drivers/sh/intc/dynamic.c
drivers/sh/intc/virq.c
drivers/staging/ath6kl/Kconfig
drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
drivers/staging/ath6kl/os/linux/ar6000_drv.c
drivers/staging/ath6kl/os/linux/cfg80211.c
drivers/staging/ath6kl/os/linux/include/athendpack_linux.h [deleted file]
drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h [deleted file]
drivers/staging/batman-adv/hard-interface.c
drivers/staging/batman-adv/routing.c
drivers/staging/batman-adv/routing.h
drivers/staging/batman-adv/unicast.c
drivers/staging/bcm/Bcmchar.c
drivers/staging/brcm80211/README
drivers/staging/brcm80211/TODO
drivers/staging/brcm80211/brcmfmac/dhd_linux.c
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
drivers/staging/cpia/cpia.c
drivers/staging/easycap/easycap.h
drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c
drivers/staging/hv/hv_utils.c
drivers/staging/hv/storvsc_drv.c
drivers/staging/intel_sst/intel_sst_app_interface.c
drivers/staging/intel_sst/intel_sst_common.h
drivers/staging/keucr/init.c
drivers/staging/keucr/ms.c
drivers/staging/keucr/msscsi.c
drivers/staging/keucr/scsiglue.c
drivers/staging/keucr/sdscsi.c
drivers/staging/keucr/smilsub.c
drivers/staging/keucr/transport.c
drivers/staging/olpc_dcon/olpc_dcon.c
drivers/staging/rt2860/common/cmm_aes.c
drivers/staging/rt2860/usb_main_dev.c
drivers/staging/rtl8192e/r8192E_core.c
drivers/staging/rtl8712/osdep_service.h
drivers/staging/solo6x10/solo6010-v4l2-enc.c
drivers/staging/solo6x10/solo6010-v4l2.c
drivers/staging/speakup/buffers.c
drivers/staging/stradis/Kconfig
drivers/staging/stradis/stradis.c
drivers/staging/tidspbridge/Kconfig
drivers/staging/tidspbridge/Makefile
drivers/staging/tidspbridge/core/_deh.h
drivers/staging/tidspbridge/core/_tiomap.h
drivers/staging/tidspbridge/core/dsp-mmu.c [deleted file]
drivers/staging/tidspbridge/core/io_sm.c
drivers/staging/tidspbridge/core/tiomap3430.c
drivers/staging/tidspbridge/core/tiomap3430_pwr.c
drivers/staging/tidspbridge/core/tiomap_io.c
drivers/staging/tidspbridge/core/ue_deh.c
drivers/staging/tidspbridge/hw/EasiGlobal.h [new file with mode: 0644]
drivers/staging/tidspbridge/hw/MMUAccInt.h [new file with mode: 0644]
drivers/staging/tidspbridge/hw/MMURegAcM.h [new file with mode: 0644]
drivers/staging/tidspbridge/hw/hw_defs.h [new file with mode: 0644]
drivers/staging/tidspbridge/hw/hw_mmu.c [new file with mode: 0644]
drivers/staging/tidspbridge/hw/hw_mmu.h [new file with mode: 0644]
drivers/staging/tidspbridge/include/dspbridge/cfgdefs.h
drivers/staging/tidspbridge/include/dspbridge/dev.h
drivers/staging/tidspbridge/include/dspbridge/dmm.h [new file with mode: 0644]
drivers/staging/tidspbridge/include/dspbridge/drv.h
drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h [deleted file]
drivers/staging/tidspbridge/include/dspbridge/dspdefs.h
drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
drivers/staging/tidspbridge/include/dspbridge/proc.h
drivers/staging/tidspbridge/pmgr/dev.c
drivers/staging/tidspbridge/pmgr/dmm.c [new file with mode: 0644]
drivers/staging/tidspbridge/pmgr/dspapi.c
drivers/staging/tidspbridge/rmgr/drv.c
drivers/staging/tidspbridge/rmgr/drv_interface.c
drivers/staging/tidspbridge/rmgr/node.c
drivers/staging/tidspbridge/rmgr/proc.c
drivers/staging/tm6000/tm6000-video.c
drivers/staging/udlfb/udlfb.c
drivers/staging/vt6656/main_usb.c
drivers/staging/westbridge/astoria/api/src/cyasusb.c
drivers/staging/wlan-ng/cfg80211.c
drivers/staging/wlan-ng/p80211netdev.c
drivers/tty/Makefile [new file with mode: 0644]
drivers/tty/n_gsm.c [new file with mode: 0644]
drivers/tty/n_hdlc.c [new file with mode: 0644]
drivers/tty/n_r3964.c [new file with mode: 0644]
drivers/tty/n_tty.c [new file with mode: 0644]
drivers/tty/pty.c [new file with mode: 0644]
drivers/tty/sysrq.c [new file with mode: 0644]
drivers/tty/tty_audit.c [new file with mode: 0644]
drivers/tty/tty_buffer.c [new file with mode: 0644]
drivers/tty/tty_io.c [new file with mode: 0644]
drivers/tty/tty_ioctl.c [new file with mode: 0644]
drivers/tty/tty_ldisc.c [new file with mode: 0644]
drivers/tty/tty_mutex.c [new file with mode: 0644]
drivers/tty/tty_port.c [new file with mode: 0644]
drivers/tty/vt/.gitignore [new file with mode: 0644]
drivers/tty/vt/Makefile [new file with mode: 0644]
drivers/tty/vt/consolemap.c [new file with mode: 0644]
drivers/tty/vt/cp437.uni [new file with mode: 0644]
drivers/tty/vt/defkeymap.c_shipped [new file with mode: 0644]
drivers/tty/vt/defkeymap.map [new file with mode: 0644]
drivers/tty/vt/keyboard.c [new file with mode: 0644]
drivers/tty/vt/selection.c [new file with mode: 0644]
drivers/tty/vt/vc_screen.c [new file with mode: 0644]
drivers/tty/vt/vt.c [new file with mode: 0644]
drivers/tty/vt/vt_ioctl.c [new file with mode: 0644]
drivers/usb/atm/ueagle-atm.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/file.c
drivers/usb/core/inode.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/f_hid.c
drivers/usb/gadget/goku_udc.h
drivers/usb/gadget/u_ether.c
drivers/usb/gadget/u_serial.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mem.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/ohci-jz4740.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/image/microtek.c
drivers/usb/misc/cypress_cy7c63.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/trancevibrator.c
drivers/usb/misc/usbled.c
drivers/usb/misc/usbsevseg.c
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_stat.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_regs.h
drivers/usb/musb/musbhsdma.c
drivers/usb/otg/langwell_otg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/sierra_ms.c
drivers/usb/storage/uas.c
drivers/uwb/allocator.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/lms283gf05.c
drivers/video/backlight/mbp_nvidia_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/s6e63m0.c
drivers/video/console/vgacon.c
drivers/video/omap2/vram.c
drivers/video/riva/rivafb-i2c.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sis/sis_main.c
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events.c
drivers/xen/evtchn.c
drivers/xen/xenfs/privcmd.c
drivers/xen/xenfs/super.c
drivers/zorro/proc.c
fs/bio.c
fs/block_dev.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/super.h
fs/cifs/TODO
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/misc.c
fs/compat_ioctl.c
fs/ecryptfs/super.c
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/gfs2/export.c
fs/gfs2/glock.c
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/rgrp.c
fs/hugetlbfs/inode.c
fs/ioctl.c
fs/ioprio.c
fs/jbd2/journal.c
fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/lockd/host.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/locks.c
fs/logfs/logfs.h
fs/namespace.c
fs/ncpfs/dir.c
fs/ncpfs/file.c
fs/ncpfs/inode.c
fs/ncpfs/ioctl.c
fs/nfs/callback.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/super.c
fs/nfsd/nfs4state.c
fs/ocfs2/ocfs2.h
fs/ocfs2/super.c
fs/openpromfs/inode.c
fs/proc/inode.c
fs/read_write.c
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/journal.c
fs/reiserfs/super.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_quota.h
include/asm-generic/stat.h
include/drm/nouveau_drm.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/linux/atomic.h [new file with mode: 0644]
include/linux/bio.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
include/linux/ceph/osd_client.h
include/linux/drbd.h
include/linux/fs.h
include/linux/fsl-diu-fb.h
include/linux/hardirq.h
include/linux/highmem.h
include/linux/i2c-id.h
include/linux/i2c.h
include/linux/i2c/adp5588.h
include/linux/if_vlan.h
include/linux/input.h
include/linux/iocontext.h
include/linux/kernel.h
include/linux/leds-lp5521.h [new file with mode: 0644]
include/linux/leds-lp5523.h [new file with mode: 0644]
include/linux/leds.h
include/linux/libata.h
include/linux/lockd/lockd.h
include/linux/marvell_phy.h
include/linux/mmc/sh_mmcif.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/nfs_fs.h
include/linux/perf_event.h
include/linux/printk.h [new file with mode: 0644]
include/linux/pwm_backlight.h
include/linux/radix-tree.h
include/linux/reiserfs_fs.h
include/linux/resource.h
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/security.h
include/linux/sh_clk.h
include/linux/sh_intc.h
include/linux/sh_timer.h
include/linux/smp_lock.h
include/linux/sunrpc/svc_xprt.h
include/linux/tty.h
include/linux/usb.h
include/linux/usb/musb.h
include/net/caif/caif_dev.h
include/net/caif/caif_spi.h
include/net/caif/cfcnfg.h
include/net/cfg80211.h
include/net/dn.h
include/net/dst_ops.h
include/net/neighbour.h
include/net/netlink.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/scsi/libfc.h
include/scsi/libiscsi.h
include/scsi/libsas.h
include/scsi/scsi_host.h
include/trace/events/ext4.h
include/xen/interface/memory.h
include/xen/page.h
include/xen/privcmd.h
init/main.c
kernel/debug/kdb/kdb_main.c
kernel/exit.c
kernel/futex.c
kernel/futex_compat.c
kernel/latencytop.c
kernel/perf_event.c
kernel/pm_qos_params.c
kernel/power/Kconfig
kernel/printk.c
kernel/range.c
kernel/relay.c
kernel/sched.c
kernel/sched_fair.c
kernel/sched_stoptask.c
kernel/sysctl.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/trace.c
kernel/watchdog.c
lib/radix-tree.c
mm/filemap.c
mm/memcontrol.c
mm/mprotect.c
mm/slub.c
mm/vmscan.c
mm/vmstat.c
net/ax25/af_ax25.c
net/bluetooth/hci_event.c
net/bluetooth/hidp/Kconfig
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/caif/caif_config_util.c
net/caif/caif_dev.c
net/caif/caif_socket.c
net/caif/cfcnfg.c
net/caif/cfctrl.c
net/caif/cfdbgl.c
net/caif/cfrfml.c
net/can/bcm.c
net/ceph/buffer.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/pagevec.c
net/core/dev.c
net/core/dst.c
net/core/filter.c
net/core/net-sysfs.c
net/core/pktgen.c
net/core/request_sock.c
net/core/rtnetlink.c
net/core/sock.c
net/decnet/af_decnet.c
net/decnet/sysctl_net_decnet.c
net/ipv4/fib_lookup.h
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_diag.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv4/proc.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/irda/af_irda.c
net/irda/irnet/irnet_ppp.c
net/irda/irttp.c
net/l2tp/l2tp_debugfs.c
net/mac80211/iface.c
net/netfilter/ipvs/Kconfig
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/packet/af_packet.c
net/rds/loop.c
net/rds/message.c
net/rds/rdma.c
net/rds/tcp.c
net/sched/cls_basic.c
net/sched/cls_cgroup.c
net/sched/em_text.c
net/sctp/protocol.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sunrpc/stats.c
net/sunrpc/svc_xprt.c
net/tipc/socket.c
net/wireless/chan.c
net/wireless/nl80211.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/xfrm/xfrm_hash.c
scripts/kconfig/symbol.c
scripts/kernel-doc
security/Kconfig
security/apparmor/lsm.c
security/apparmor/policy.c
security/capability.c
security/commoncap.c
security/security.c
security/selinux/hooks.c
security/smack/smack_lsm.c
sound/atmel/abdac.c
sound/core/info.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/sound.c
sound/oss/dev_table.c
sound/oss/midibuf.c
sound/oss/pss.c
sound/oss/sequencer.c
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpioctl.c
sound/pci/azt3328.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/ctxfi/ctpcm.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/intel8x0.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx6464es.h
sound/pci/lx6464es/lx_core.c
sound/pci/mixart/mixart_hwdep.h
sound/ppc/pmac.c
sound/sound_core.c
sound/spi/at73c213.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
tools/perf/Documentation/perf-trace.txt
tools/perf/builtin-record.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/scripts/perl/bin/failed-syscalls-record
tools/perf/scripts/perl/bin/rw-by-file-record
tools/perf/scripts/perl/bin/rw-by-pid-record
tools/perf/scripts/perl/bin/rwtop-record
tools/perf/scripts/perl/bin/wakeup-latency-record
tools/perf/scripts/perl/bin/workqueue-stats-record
tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
tools/perf/scripts/python/bin/futex-contention-record
tools/perf/scripts/python/bin/netdev-times-record
tools/perf/scripts/python/bin/sched-migration-record
tools/perf/scripts/python/bin/sctop-record
tools/perf/scripts/python/bin/syscall-counts-by-pid-record
tools/perf/scripts/python/bin/syscall-counts-record
tools/perf/util/ui/util.c

diff --git a/Documentation/ABI/obsolete/proc-pid-oom_adj b/Documentation/ABI/obsolete/proc-pid-oom_adj
new file mode 100644 (file)
index 0000000..cf63f26
--- /dev/null
@@ -0,0 +1,22 @@
+What:  /proc/<pid>/oom_adj
+When:  August 2012
+Why:   /proc/<pid>/oom_adj allows userspace to influence the oom killer's
+       badness heuristic used to determine which task to kill when the kernel
+       is out of memory.
+
+       The badness heuristic has since been rewritten since the introduction of
+       this tunable such that its meaning is deprecated.  The value was
+       implemented as a bitshift on a score generated by the badness()
+       function that did not have any precise units of measure.  With the
+       rewrite, the score is given as a proportion of available memory to the
+       task allocating pages, so using a bitshift which grows the score
+       exponentially is, thus, impossible to tune with fine granularity.
+
+       A much more powerful interface, /proc/<pid>/oom_score_adj, was
+       introduced with the oom killer rewrite that allows users to increase or
+       decrease the badness() score linearly.  This interface will replace
+       /proc/<pid>/oom_adj.
+
+       A warning will be emitted to the kernel log if an application uses this
+       deprecated interface.  After it is printed once, future warnings will be
+       suppressed until the kernel is rebooted.
index 4d4ce0e61e424708a94db666e0496d7c0f3fc253..b4665b9c40b0ec46253b9ae6cf9bb1bbd06ec563 100644 (file)
@@ -16,7 +16,7 @@
        </orgname>
 
        <address>
-          <email>hjk@linutronix.de</email>
+          <email>hjk@hansjkoch.de</email>
        </address>
     </affiliation>
 </author>
@@ -114,7 +114,7 @@ GPL version 2.
 
 <para>If you know of any translations for this document, or you are
 interested in translating it, please email me
-<email>hjk@linutronix.de</email>.
+<email>hjk@hansjkoch.de</email>.
 </para>
 </sect1>
 
@@ -171,7 +171,7 @@ interested in translating it, please email me
 <title>Feedback</title>
        <para>Find something wrong with this document? (Or perhaps something
        right?) I would love to hear from you. Please email me at
-       <email>hjk@linutronix.de</email>.</para>
+       <email>hjk@hansjkoch.de</email>.</para>
 </sect1>
 </chapter>
 
index 0af0e9eed5d6c1281433b4c0bc26f7c6577fe8a6..888ae7b83ae4783da38b4db2f69b94d45ba193c8 100644 (file)
@@ -255,9 +255,10 @@ framebuffer parameters.
 Kernel boot arguments
 ---------------------
 
-vram=<size>
-       - Amount of total VRAM to preallocate. For example, "10M". omapfb
-         allocates memory for framebuffers from VRAM.
+vram=<size>[,<physaddr>]
+       - Amount of total VRAM to preallocate and optionally a physical start
+         memory address. For example, "10M". omapfb allocates memory for
+         framebuffers from VRAM.
 
 omapfb.mode=<display>:<mode>[,...]
        - Default video mode for specified displays. For example,
index d5af3f630814862c5f15194d871766510e16893c..71cfbdc0f74d1da35a9064c6b48490ff5797d660 100644 (file)
@@ -16,7 +16,7 @@ you can do so by typing:
 As of the Linux 2.6.10 kernel, it is now possible to change the
 IO scheduler for a given block device on the fly (thus making it possible,
 for instance, to set the CFQ scheduler for the system default, but
-set a specific device to use the anticipatory or noop schedulers - which
+set a specific device to use the deadline or noop schedulers - which
 can improve that device's throughput).
 
 To set a specific scheduler, simply do this:
@@ -31,7 +31,7 @@ a "cat /sys/block/DEV/queue/scheduler" - the list of valid names
 will be displayed, with the currently selected scheduler in brackets:
 
 # cat /sys/block/hda/queue/scheduler
-noop anticipatory deadline [cfq]
-# echo anticipatory > /sys/block/hda/queue/scheduler
+noop deadline [cfq]
+# echo deadline > /sys/block/hda/queue/scheduler
 # cat /sys/block/hda/queue/scheduler
-noop [anticipatory] deadline cfq
+noop [deadline] cfq
index 97726eba6102ca31410028391d8f637b3d7a01c5..911a4518634048d9098a02865d328c18824c8248 100644 (file)
@@ -154,7 +154,7 @@ The stages that a patch goes through are, generally:
    inclusion, it should be accepted by a relevant subsystem maintainer -
    though this acceptance is not a guarantee that the patch will make it
    all the way to the mainline.  The patch will show up in the maintainer's
-   subsystem tree and into the staging trees (described below).  When the
+   subsystem tree and into the -next trees (described below).  When the
    process works, this step leads to more extensive review of the patch and
    the discovery of any problems resulting from the integration of this
    patch with work being done by others.
@@ -236,7 +236,7 @@ finding the right maintainer.  Sending patches directly to Linus is not
 normally the right way to go.
 
 
-2.4: STAGING TREES
+2.4: NEXT TREES
 
 The chain of subsystem trees guides the flow of patches into the kernel,
 but it also raises an interesting question: what if somebody wants to look
@@ -250,7 +250,7 @@ changes land in the mainline kernel.  One could pull changes from all of
 the interesting subsystem trees, but that would be a big and error-prone
 job.
 
-The answer comes in the form of staging trees, where subsystem trees are
+The answer comes in the form of -next trees, where subsystem trees are
 collected for testing and review.  The older of these trees, maintained by
 Andrew Morton, is called "-mm" (for memory management, which is how it got
 started).  The -mm tree integrates patches from a long list of subsystem
@@ -275,7 +275,7 @@ directory at:
 Use of the MMOTM tree is likely to be a frustrating experience, though;
 there is a definite chance that it will not even compile.
 
-The other staging tree, started more recently, is linux-next, maintained by
+The other -next tree, started more recently, is linux-next, maintained by
 Stephen Rothwell.  The linux-next tree is, by design, a snapshot of what
 the mainline is expected to look like after the next merge window closes.
 Linux-next trees are announced on the linux-kernel and linux-next mailing
@@ -303,12 +303,25 @@ volatility of linux-next tends to make it a difficult development target.
 See http://lwn.net/Articles/289013/ for more information on this topic, and
 stay tuned; much is still in flux where linux-next is involved.
 
-Besides the mmotm and linux-next trees, the kernel source tree now contains
-the drivers/staging/ directory and many sub-directories for drivers or
-filesystems that are on their way to being added to the kernel tree
-proper, but they remain in drivers/staging/ while they still need more
-work.
-
+2.4.1: STAGING TREES
+
+The kernel source tree now contains the drivers/staging/ directory, where
+many sub-directories for drivers or filesystems that are on their way to
+being added to the kernel tree live.  They remain in drivers/staging while
+they still need more work; once complete, they can be moved into the
+kernel proper.  This is a way to keep track of drivers that aren't
+up to Linux kernel coding or quality standards, but people may want to use
+them and track development.
+
+Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree.
+Drivers that still need work are sent to him, with each driver having
+its own subdirectory in drivers/staging/.  Along with the driver source
+files, a TODO file should be present in the directory as well.  The TODO
+file lists the pending work that the driver needs for acceptance into
+the kernel proper, as well as a list of people that should be Cc'd for any
+patches to the driver.  Staging drivers that don't currently build should
+have their config entries depend upon CONFIG_BROKEN.  Once they can
+be successfully built without outside patches, CONFIG_BROKEN can be removed.
 
 2.5: TOOLS
 
index d8f36f984faa517c84883f625a93ee45a3f91dcc..6c2f55e05f13c31675bcbcbc70d6254e2d70783d 100644 (file)
@@ -554,3 +554,13 @@ Why:    This is a legacy interface which have been replaced by a more
 Who:    NeilBrown <neilb@suse.de>
 
 ----------------------------
+
+What:  i2c_adapter.id
+When:  June 2011
+Why:   This field is deprecated. I2C device drivers shouldn't change their
+       behavior based on the underlying I2C adapter. Instead, the I2C
+       adapter driver should instantiate the I2C devices and provide the
+       needed platform-specific information.
+Who:   Jean Delvare <khali@linux-fr.org>
+
+----------------------------
index d428cc9f07f399141e643fc6d8df8ce88433365b..fd53869f5633f2994fe06365fe53c1754747dc6a 100644 (file)
@@ -89,7 +89,7 @@ static ssize_t childless_storeme_write(struct childless *childless,
        char *p = (char *) page;
 
        tmp = simple_strtoul(p, &p, 10);
-       if (!p || (*p && (*p != '\n')))
+       if ((*p != '\0') && (*p != '\n'))
                return -EINVAL;
 
        if (tmp > INT_MAX)
index 96d0df28bed323d5596fc051b0ffb96ed8e3c8df..7445bf335dae7eeba4bd6640a82fa3987f48d2cc 100644 (file)
@@ -794,17 +794,6 @@ designed.
 
 Roadmap:
 
-2.6.37 Remove experimental tag from mount option
-       => should be roughly 6 months after initial merge
-       => enough time to:
-               => gain confidence and fix problems reported by early
-                  adopters (a.k.a. guinea pigs)
-               => address worst performance regressions and undesired
-                  behaviours
-               => start tuning/optimising code for parallelism
-               => start tuning/optimising algorithms consuming
-                  excessive CPU time
-
 2.6.39 Switch default mount option to use delayed logging
        => should be roughly 12 months after initial merge
        => enough time to shake out remaining problems before next round of
index 9633da01ff46afb008566ccb53aa381606654e85..792faa3c06cf7ccda5ab081dbf568276324538e5 100644 (file)
@@ -617,6 +617,16 @@ and have the following read/write attributes:
                is configured as an output, this value may be written;
                any nonzero value is treated as high.
 
+               If the pin can be configured as interrupt-generating interrupt
+               and if it has been configured to generate interrupts (see the
+               description of "edge"), you can poll(2) on that file and
+               poll(2) will return whenever the interrupt was triggered. If
+               you use poll(2), set the events POLLPRI and POLLERR. If you
+               use select(2), set the file descriptor in exceptfds. After
+               poll(2) returns, either lseek(2) to the beginning of the sysfs
+               file and read the new value or close the file and re-open it
+               to read the value.
+
        "edge" ... reads as either "none", "rising", "falling", or
                "both". Write these strings to select the signal edge(s)
                that will make poll(2) on the "value" file return.
index ac711f357fafb0793d10c3cb31d2cd882647f767..7a10616d0b441c473e82d8c2c31489d7dd5e80c2 100644 (file)
@@ -11,7 +11,7 @@ Authors:
        Mark M. Hoffman <mhoffman@lightlink.com>
        Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
        Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
-       Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+       Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
 
 Module Parameters
 -----------------
index 8be7beb9e3e81122d015a3eab8f634d22562bd91..c565650fcfc6f6949c8a24ae1bd2002ae9da86fa 100644 (file)
@@ -8,7 +8,7 @@ Supported chips:
     Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
 
 Authors:
-    Hans J. Koch <hjk@linutronix.de>
+    Hans J. Koch <hjk@hansjkoch.de>
     John Morris <john.morris@spirentcom.com>
     Claus Gindhart <claus.gindhart@kontron.com>
 
index ed45e9802aa810a71e1f53fdde2a5d7bbba6789e..92e83e53148fe8b1d4848af9a8fd7442cc5624ba 100644 (file)
@@ -706,7 +706,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        arch/x86/kernel/cpu/cpufreq/elanfreq.c.
 
        elevator=       [IOSCHED]
-                       Format: {"anticipatory" | "cfq" | "deadline" | "noop"}
+                       Format: {"cfq" | "deadline" | "noop"}
                        See Documentation/block/as-iosched.txt and
                        Documentation/block/deadline-iosched.txt for details.
 
index 8fd5ca2ae32dde4d9eb27722942a5d099f4afbc3..58b266bd1846f1d0560bdae575f6e764a95fd4b3 100644 (file)
@@ -60,15 +60,18 @@ Hardware accelerated blink of LEDs
 
 Some LEDs can be programmed to blink without any CPU interaction. To
 support this feature, a LED driver can optionally implement the
-blink_set() function (see <linux/leds.h>). If implemented, triggers can
-attempt to use it before falling back to software timers. The blink_set()
-function should return 0 if the blink setting is supported, or -EINVAL
-otherwise, which means that LED blinking will be handled by software.
-
-The blink_set() function should choose a user friendly blinking
-value if it is called with *delay_on==0 && *delay_off==0 parameters. In
-this case the driver should give back the chosen value through delay_on
-and delay_off parameters to the leds subsystem.
+blink_set() function (see <linux/leds.h>). To set an LED to blinking,
+however, it is better to use use the API function led_blink_set(),
+as it will check and implement software fallback if necessary.
+
+To turn off blinking again, use the API function led_brightness_set()
+as that will not just set the LED brightness but also stop any software
+timers that may have been required for blinking.
+
+The blink_set() function should choose a user friendly blinking value
+if it is called with *delay_on==0 && *delay_off==0 parameters. In this
+case the driver should give back the chosen value through delay_on and
+delay_off parameters to the leds subsystem.
 
 Setting the brightness to zero with brightness_set() callback function
 should completely turn off the LED and cancel the previously programmed
diff --git a/Documentation/leds/leds-lp5521.txt b/Documentation/leds/leds-lp5521.txt
new file mode 100644 (file)
index 0000000..c4d8d15
--- /dev/null
@@ -0,0 +1,88 @@
+Kernel driver for lp5521
+========================
+
+* National Semiconductor LP5521 led driver chip
+* Datasheet: http://www.national.com/pf/LP/LP5521.html
+
+Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo
+Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
+
+Description
+-----------
+
+LP5521 can drive up to 3 channels. Leds can be controlled directly via
+the led class control interface. Channels have generic names:
+lp5521:channelx, where x is 0 .. 2
+
+All three channels can be also controlled using the engine micro programs.
+More details of the instructions can be found from the public data sheet.
+
+Control interface for the engines:
+x is 1 .. 3
+enginex_mode : disabled, load, run
+enginex_load : store program (visible only in engine load mode)
+
+Example (start to blink the channel 2 led):
+cd   /sys/class/leds/lp5521:channel2/device
+echo "load" > engine3_mode
+echo "037f4d0003ff6000" > engine3_load
+echo "run" > engine3_mode
+
+stop the engine:
+echo "disabled" > engine3_mode
+
+sysfs contains a selftest entry.
+The test communicates with the chip and checks that
+the clock mode is automatically set to the requested one.
+
+Each channel has its own led current settings.
+/sys/class/leds/lp5521:channel0/led_current - RW
+/sys/class/leds/lp5521:channel0/max_current - RO
+Format: 10x mA i.e 10 means 1.0 mA
+
+example platform data:
+
+Note: chan_nr can have values between 0 and 2.
+
+static struct lp5521_led_config lp5521_led_config[] = {
+        {
+                .chan_nr        = 0,
+                .led_current    = 50,
+               .max_current    = 130,
+        }, {
+                .chan_nr        = 1,
+                .led_current    = 0,
+               .max_current    = 130,
+        }, {
+                .chan_nr        = 2,
+                .led_current    = 0,
+               .max_current    = 130,
+        }
+};
+
+static int lp5521_setup(void)
+{
+       /* setup HW resources */
+}
+
+static void lp5521_release(void)
+{
+       /* Release HW resources */
+}
+
+static void lp5521_enable(bool state)
+{
+       /* Control of chip enable signal */
+}
+
+static struct lp5521_platform_data lp5521_platform_data = {
+        .led_config     = lp5521_led_config,
+        .num_channels   = ARRAY_SIZE(lp5521_led_config),
+        .clock_mode     = LP5521_CLOCK_EXT,
+        .setup_resources   = lp5521_setup,
+        .release_resources = lp5521_release,
+        .enable            = lp5521_enable,
+};
+
+If the current is set to 0 in the platform data, that channel is
+disabled and it is not visible in the sysfs.
diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt
new file mode 100644 (file)
index 0000000..fad2feb
--- /dev/null
@@ -0,0 +1,83 @@
+Kernel driver for lp5523
+========================
+
+* National Semiconductor LP5523 led driver chip
+* Datasheet: http://www.national.com/pf/LP/LP5523.html
+
+Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo
+Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
+
+Description
+-----------
+LP5523 can drive up to 9 channels. Leds can be controlled directly via
+the led class control interface. Channels have generic names:
+lp5523:channelx where x is 0...8
+
+The chip provides 3 engines. Each engine can control channels without
+interaction from the main CPU. Details of the micro engine code can be found
+from the public data sheet. Leds can be muxed to different channels.
+
+Control interface for the engines:
+x is 1 .. 3
+enginex_mode : disabled, load, run
+enginex_load : microcode load (visible only in load mode)
+enginex_leds : led mux control (visible only in load mode)
+
+cd /sys/class/leds/lp5523:channel2/device
+echo "load" > engine3_mode
+echo "9d80400004ff05ff437f0000" > engine3_load
+echo "111111111" > engine3_leds
+echo "run" > engine3_mode
+
+sysfs contains a selftest entry. It measures each channel
+voltage level and checks if it looks reasonable. If the level is too high,
+the led is missing; if the level is too low, there is a short circuit.
+
+Selftest uses always the current from the platform data.
+
+Each channel contains led current settings.
+/sys/class/leds/lp5523:channel2/led_current - RW
+/sys/class/leds/lp5523:channel2/max_current - RO
+Format: 10x mA i.e 10 means 1.0 mA
+
+Example platform data:
+
+Note - chan_nr can have values between 0 and 8.
+
+static struct lp5523_led_config lp5523_led_config[] = {
+        {
+                .chan_nr        = 0,
+                .led_current    = 50,
+               .max_current    = 130,
+        },
+...
+        }, {
+                .chan_nr        = 8,
+                .led_current    = 50,
+               .max_current    = 130,
+        }
+};
+
+static int lp5523_setup(void)
+{
+       /* Setup HW resources */
+}
+
+static void lp5523_release(void)
+{
+       /* Release HW resources */
+}
+
+static void lp5523_enable(bool state)
+{
+       /* Control chip enable signal */
+}
+
+static struct lp5523_platform_data lp5523_platform_data = {
+        .led_config     = lp5523_led_config,
+        .num_channels   = ARRAY_SIZE(lp5523_led_config),
+        .clock_mode     = LP5523_CLOCK_EXT,
+        .setup_resources   = lp5523_setup,
+        .release_resources = lp5523_release,
+        .enable            = lp5523_enable,
+};
index c7165f4cb7927a152ec547caeecb393f5ad3c27e..fe95105992c57f1c81248dd8d3c1c38c3272e0f9 100644 (file)
@@ -20,6 +20,15 @@ ip_no_pmtu_disc - BOOLEAN
 min_pmtu - INTEGER
        default 562 - minimum discovered Path MTU
 
+route/max_size - INTEGER
+       Maximum number of routes allowed in the kernel.  Increase
+       this when using large numbers of interfaces and/or routes.
+
+neigh/default/gc_thresh3 - INTEGER
+       Maximum number of neighbor entries allowed.  Increase this
+       when using large numbers of interfaces and when communicating
+       with large numbers of directly-connected peers.
+
 mtu_expires - INTEGER
        Time, in seconds, that cached PMTU information is kept.
 
index 44d87ad3cea9fd345a774e196578a0cc8bf4d779..cd445582d1f80a91abb619230d7b0a9dcb84e6e3 100644 (file)
@@ -37,6 +37,9 @@ Typical usage of the OPP library is as follows:
 SoC framework  -> modifies on required cases certain OPPs      -> OPP layer
                -> queries to search/retrieve information       ->
 
+Architectures that provide a SoC framework for OPP should select ARCH_HAS_OPP
+to make the OPP layer available.
+
 OPP layer expects each domain to be represented by a unique device pointer. SoC
 framework registers a set of initial OPPs per device with the OPP layer. This
 list is expected to be an optimally small number typically around 5 per device.
index 221f38be98f47be1e682876ef55c2984a8484e76..19f8278c38548405165d43256bcf8be021070087 100644 (file)
@@ -21,8 +21,8 @@ three rotations, respectively, to balance the tree), with slightly slower
 To quote Linux Weekly News:
 
     There are a number of red-black trees in use in the kernel.
-    The anticipatory, deadline, and CFQ I/O schedulers all employ
-    rbtrees to track requests; the packet CD/DVD driver does the same.
+    The deadline and CFQ I/O schedulers employ rbtrees to
+    track requests; the packet CD/DVD driver does the same.
     The high-resolution timer code uses an rbtree to organize outstanding
     timer requests.  The ext3 filesystem tracks directory entries in a
     red-black tree.  Virtual memory areas (VMAs) are tracked with red-black
index 3894eaa23486f951ace787893740ac2850f7d6d9..209e1584c3dc25e8e1af61a3061c779a28f5d11e 100644 (file)
@@ -28,6 +28,7 @@ show up in /proc/sys/kernel:
 - core_uses_pid
 - ctrl-alt-del
 - dentry-state
+- dmesg_restrict
 - domainname
 - hostname
 - hotplug
@@ -213,6 +214,19 @@ to decide what to do with it.
 
 ==============================================================
 
+dmesg_restrict:
+
+This toggle indicates whether unprivileged users are prevented from using
+dmesg(8) to view messages from the kernel's log buffer.  When
+dmesg_restrict is set to (0) there are no restrictions.  When
+dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use
+dmesg(8).
+
+The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default
+value of dmesg_restrict.
+
+==============================================================
+
 domainname & hostname:
 
 These files can be used to set the NIS/YP domainname and the
index 0094224ca79b018ced32c21fb67506d07aae93f8..b49ba9a43bf80a11315105fd5dfe46f172f2815a 100644 (file)
@@ -161,7 +161,7 @@ M:  Greg Kroah-Hartman <gregkh@suse.de>
 L:     linux-serial@vger.kernel.org
 W:     http://serial.sourceforge.net
 S:     Maintained
-T:     quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
 F:     drivers/serial/8250*
 F:     include/linux/serial_8250.h
 
@@ -945,7 +945,7 @@ M:  Magnus Damm <magnus.damm@gmail.com>
 L:     linux-sh@vger.kernel.org
 W:     http://oss.renesas.com
 Q:     http://patchwork.kernel.org/project/linux-sh/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/genesis-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git rmobile-latest
 S:     Supported
 F:     arch/arm/mach-shmobile/
 F:     drivers/sh/
@@ -1359,7 +1359,7 @@ F:        include/net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <fubar@us.ibm.com>
-L:     bonding-devel@lists.sourceforge.net
+L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
 F:     drivers/net/bonding/
@@ -1829,6 +1829,13 @@ W:       http://www.chelsio.com
 S:     Supported
 F:     drivers/net/cxgb4vf/
 
+STMMAC ETHERNET DRIVER
+M:     Giuseppe Cavallaro <peppe.cavallaro@st.com>
+L:     netdev@vger.kernel.org
+W:     http://www.stlinux.com
+S:     Supported
+F:     drivers/net/stmmac/
+
 CYBERPRO FB DRIVER
 M:     Russell King <linux@arm.linux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2008,6 +2015,7 @@ F:        drivers/hwmon/dme1737.c
 DOCBOOK FOR DOCUMENTATION
 M:     Randy Dunlap <rdunlap@xenotime.net>
 S:     Maintained
+F:     scripts/kernel-doc
 
 DOCKING STATION DRIVER
 M:     Shaohua Li <shaohua.li@intel.com>
@@ -2018,6 +2026,7 @@ F:        drivers/acpi/dock.c
 DOCUMENTATION
 M:     Randy Dunlap <rdunlap@xenotime.net>
 L:     linux-doc@vger.kernel.org
+T:     quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/
 S:     Maintained
 F:     Documentation/
 
@@ -2435,6 +2444,7 @@ F:        drivers/net/wan/sdla.c
 FRAMEBUFFER LAYER
 L:     linux-fbdev@vger.kernel.org
 W:     http://linux-fbdev.sourceforge.net/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git
 S:     Orphan
 F:     Documentation/fb/
 F:     drivers/video/fb*
@@ -5676,7 +5686,7 @@ S:        Maintained
 
 STAGING SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@suse.de>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-next-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6.git
 L:     devel@driverdev.osuosl.org
 S:     Maintained
 F:     drivers/staging/
@@ -5705,7 +5715,7 @@ M:        Paul Mundt <lethal@linux-sh.org>
 L:     linux-sh@vger.kernel.org
 W:     http://www.linux-sh.org
 Q:     http://patchwork.kernel.org/project/linux-sh/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git sh-latest
 S:     Supported
 F:     Documentation/sh/
 F:     arch/sh/
@@ -5910,7 +5920,7 @@ S:        Maintained
 TTY LAYER
 M:     Greg Kroah-Hartman <gregkh@suse.de>
 S:     Maintained
-T:     quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
 F:     drivers/char/tty_*
 F:     drivers/serial/serial_core.c
 F:     include/linux/serial_core.h
@@ -6233,7 +6243,7 @@ USB SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@suse.de>
 L:     linux-usb@vger.kernel.org
 W:     http://www.linux-usb.org
-T:     quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git
 S:     Supported
 F:     Documentation/usb/
 F:     drivers/net/usb/
@@ -6598,14 +6608,14 @@ F:      drivers/platform/x86
 
 XEN PCI SUBSYSTEM
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-L:     xen-devel@lists.xensource.com
+L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
 S:     Supported
 F:     arch/x86/pci/*xen*
 F:     drivers/pci/*xen*
 
 XEN SWIOTLB SUBSYSTEM
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-L:     xen-devel@lists.xensource.com
+L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
 S:     Supported
 F:     arch/x86/xen/*swiotlb*
 F:     drivers/xen/*swiotlb*
@@ -6613,7 +6623,7 @@ F:        drivers/xen/*swiotlb*
 XEN HYPERVISOR INTERFACE
 M:     Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
 M:     Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-L:     xen-devel@lists.xen.org
+L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
 L:     virtualization@lists.osdl.org
 S:     Supported
 F:     arch/x86/xen/
index 6619720f50dd667abf746f1dd892b35c67a9742c..b31d21377e4ce8f776ddd4e60a7f5457196551e6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 37
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc3
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index a19a5266d5fc989327d2f5e82b8068e13462a5b8..db524e75c4a21e4f45bc4b72e459adcdaf1dda4b 100644 (file)
@@ -6,7 +6,7 @@ config ARM
        select HAVE_MEMBLOCK
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
-       select GENERIC_ATOMIC64 if (!CPU_32v6K)
+       select GENERIC_ATOMIC64 if (!CPU_32v6K || !AEABI)
        select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
        select HAVE_ARCH_KGDB
        select HAVE_KPROBES if (!XIP_KERNEL)
@@ -646,7 +646,7 @@ config ARCH_S3C2410
        select ARCH_HAS_CPUFREQ
        select HAVE_CLK
        select ARCH_USES_GETTIMEOFFSET
-       select HAVE_S3C2410_I2C
+       select HAVE_S3C2410_I2C if I2C
        help
          Samsung S3C2410X CPU based systems, such as the Simtec Electronics
          BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
@@ -676,8 +676,8 @@ config ARCH_S3C64XX
        select S3C_DEV_NAND
        select USB_ARCH_HAS_OHCI
        select SAMSUNG_GPIOLIB_4BIT
-       select HAVE_S3C2410_I2C
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C2410_I2C if I2C
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        help
          Samsung S3C64XX series based systems
 
@@ -686,10 +686,10 @@ config ARCH_S5P64X0
        select CPU_V6
        select GENERIC_GPIO
        select HAVE_CLK
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        select ARCH_USES_GETTIMEOFFSET
-       select HAVE_S3C2410_I2C
-       select HAVE_S3C_RTC
+       select HAVE_S3C2410_I2C if I2C
+       select HAVE_S3C_RTC if RTC_CLASS
        help
          Samsung S5P64X0 CPU based systems, such as the Samsung SMDK6440,
          SMDK6450.
@@ -700,7 +700,7 @@ config ARCH_S5P6442
        select GENERIC_GPIO
        select HAVE_CLK
        select ARCH_USES_GETTIMEOFFSET
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        help
          Samsung S5P6442 CPU based systems
 
@@ -711,9 +711,9 @@ config ARCH_S5PC100
        select CPU_V7
        select ARM_L1_CACHE_SHIFT_6
        select ARCH_USES_GETTIMEOFFSET
-       select HAVE_S3C2410_I2C
-       select HAVE_S3C_RTC
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C2410_I2C if I2C
+       select HAVE_S3C_RTC if RTC_CLASS
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        help
          Samsung S5PC100 series based systems
 
@@ -726,9 +726,9 @@ config ARCH_S5PV210
        select ARM_L1_CACHE_SHIFT_6
        select ARCH_HAS_CPUFREQ
        select ARCH_USES_GETTIMEOFFSET
-       select HAVE_S3C2410_I2C
-       select HAVE_S3C_RTC
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C2410_I2C if I2C
+       select HAVE_S3C_RTC if RTC_CLASS
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        help
          Samsung S5PV210/S5PC110 series based systems
 
@@ -739,9 +739,9 @@ config ARCH_S5PV310
        select GENERIC_GPIO
        select HAVE_CLK
        select GENERIC_CLOCKEVENTS
-       select HAVE_S3C_RTC
-       select HAVE_S3C2410_I2C
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C_RTC if RTC_CLASS
+       select HAVE_S3C2410_I2C if I2C
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        help
          Samsung S5PV310 series based systems
 
index ada6359160ebef12614e9cd725449e5353a7a85b..772f95f1aecddf49ada9ceea0caa5295d22c9613 100644 (file)
@@ -251,15 +251,16 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
                writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
 
        /*
-        * Set priority on all interrupts.
+        * Set priority on all global interrupts.
         */
-       for (i = 0; i < max_irq; i += 4)
+       for (i = 32; i < max_irq; i += 4)
                writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
        /*
-        * Disable all interrupts.
+        * Disable all interrupts.  Leave the PPI and SGIs alone
+        * as these enables are banked registers.
         */
-       for (i = 0; i < max_irq; i += 32)
+       for (i = 32; i < max_irq; i += 32)
                writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
        /*
@@ -277,11 +278,30 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
 
 void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
 {
+       void __iomem *dist_base;
+       int i;
+
        if (gic_nr >= MAX_GIC_NR)
                BUG();
 
+       dist_base = gic_data[gic_nr].dist_base;
+       BUG_ON(!dist_base);
+
        gic_data[gic_nr].cpu_base = base;
 
+       /*
+        * Deal with the banked PPI and SGI interrupts - disable all
+        * PPI interrupts, ensure all SGI interrupts are enabled.
+        */
+       writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
+       writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
+
+       /*
+        * Set priority on PPI and SGI interrupts
+        */
+       for (i = 0; i < 32; i += 4)
+               writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+
        writel(0xf0, base + GIC_CPU_PRIMASK);
        writel(1, base + GIC_CPU_CTRL);
 }
index 6700c7fc7ebd2e3cfc03e9a11accba01e58440e3..21fa272301f804b9bad3218b74147f6e450fa026 100644 (file)
@@ -75,7 +75,7 @@ extern unsigned long it8152_base_address;
   IT8152_PD_IRQ(1)  USB (USBR)
   IT8152_PD_IRQ(0)  Audio controller (ACR)
  */
-#define IT8152_IRQ(x)   (IRQ_BOARD_END + (x))
+#define IT8152_IRQ(x)   (IRQ_BOARD_START + (x))
 
 /* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
 #define IT8152_LD_IRQ_COUNT     9
index 54593b0c241b4ec78d7b6f23356666787eedd7b4..21e3a4ab3b8c58047304b694aa8161b9ebbf1c31 100644 (file)
@@ -748,8 +748,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
                breakpoint_handler(addr, regs);
                break;
        case ARM_ENTRY_ASYNC_WATCHPOINT:
-               WARN_ON("Asynchronous watchpoint exception taken. "
-                       "Debugging results may be unreliable");
+               WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n");
        case ARM_ENTRY_SYNC_WATCHPOINT:
                watchpoint_handler(addr, regs);
                break;
index 49643b1467e62d529d4edd661990bb64da1e1f73..07a50357492ac6858bc21d0b7913aefc93cbb1cf 100644 (file)
@@ -1749,7 +1749,7 @@ static inline int armv7_pmnc_has_overflowed(unsigned long pmnc)
 static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc,
                                        enum armv7_counters counter)
 {
-       int ret;
+       int ret = 0;
 
        if (counter == ARMV7_CYCLE_COUNTER)
                ret = pmnc & ARMV7_FLAG_C;
index 20b7411e47fdeef9e31606e665957ea862638f5a..c2e112e1a05fbf0d4485db1236448653e25aa8cc 100644 (file)
@@ -28,7 +28,7 @@ int notrace unwind_frame(struct stackframe *frame)
 
        /* only go to a higher address on the stack */
        low = frame->sp;
-       high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
+       high = ALIGN(low, THREAD_SIZE);
 
        /* check current frame pointer is within bounds */
        if (fp < (low + 12) || fp + 4 >= high)
index cda78d59aa31b2971ed897b9db78afd6bfb0f36e..446aee97436f22b82ba7d2f16a06d74b507b7042 100644 (file)
@@ -53,10 +53,7 @@ static void dump_mem(const char *, const char *, unsigned long, unsigned long);
 void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
 {
 #ifdef CONFIG_KALLSYMS
-       char sym1[KSYM_SYMBOL_LEN], sym2[KSYM_SYMBOL_LEN];
-       sprint_symbol(sym1, where);
-       sprint_symbol(sym2, from);
-       printk("[<%08lx>] (%s) from [<%08lx>] (%s)\n", where, sym1, from, sym2);
+       printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
 #else
        printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
 #endif
index 2a161765f6d5fdc0ac07805c2a4a62957adf72a0..d2cb0b3c987216b4b7eea39289b739fbc7d0136d 100644 (file)
@@ -279,7 +279,7 @@ int unwind_frame(struct stackframe *frame)
 
        /* only go to a higher address on the stack */
        low = frame->sp;
-       high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
+       high = ALIGN(low, THREAD_SIZE);
 
        pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
                 frame->pc, frame->lr, frame->sp);
index 3a5961d3f3b1bf810c8d7d8369132fc64fcee54e..5e31b2b25da95a4511ddfc431d320c24c7c93211 100644 (file)
@@ -1,5 +1,13 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/dma.h
+/**
+ * DOC: EP93xx DMA M2P memory to peripheral and peripheral to memory engine
+ *
+ * The EP93xx DMA M2P subsystem handles DMA transfers between memory and
+ * peripherals. DMA M2P channels are available for audio, UARTs and IrDA.
+ * See chapter 10 of the EP93xx users guide for full details on the DMA M2P
+ * engine.
+ *
+ * See sound/soc/ep93xx/ep93xx-pcm.c for an example use of the DMA M2P code.
+ *
  */
 
 #ifndef __ASM_ARCH_DMA_H
 #include <linux/list.h>
 #include <linux/types.h>
 
+/**
+ * struct ep93xx_dma_buffer - Information about a buffer to be transferred
+ * using the DMA M2P engine
+ *
+ * @list: Entry in DMA buffer list
+ * @bus_addr: Physical address of the buffer
+ * @size: Size of the buffer in bytes
+ */
 struct ep93xx_dma_buffer {
        struct list_head        list;
        u32                     bus_addr;
        u16                     size;
 };
 
+/**
+ * struct ep93xx_dma_m2p_client - Information about a DMA M2P client
+ *
+ * @name: Unique name for this client
+ * @flags: Client flags
+ * @cookie: User data to pass to callback functions
+ * @buffer_started: Non NULL function to call when a transfer is started.
+ *                     The arguments are the user data cookie and the DMA
+ *                     buffer which is starting.
+ * @buffer_finished: Non NULL function to call when a transfer is completed.
+ *                     The arguments are the user data cookie, the DMA buffer
+ *                     which has completed, and a boolean flag indicating if
+ *                     the transfer had an error.
+ */
 struct ep93xx_dma_m2p_client {
        char                    *name;
        u8                      flags;
@@ -24,10 +54,11 @@ struct ep93xx_dma_m2p_client {
                                        struct ep93xx_dma_buffer *buf,
                                        int bytes, int error);
 
-       /* Internal to the DMA code.  */
+       /* private: Internal use only */
        void                    *channel;
 };
 
+/* DMA M2P ports */
 #define EP93XX_DMA_M2P_PORT_I2S1       0x00
 #define EP93XX_DMA_M2P_PORT_I2S2       0x01
 #define EP93XX_DMA_M2P_PORT_AAC1       0x02
@@ -39,18 +70,80 @@ struct ep93xx_dma_m2p_client {
 #define EP93XX_DMA_M2P_PORT_UART3      0x08
 #define EP93XX_DMA_M2P_PORT_IRDA       0x09
 #define EP93XX_DMA_M2P_PORT_MASK       0x0f
-#define EP93XX_DMA_M2P_TX              0x00
-#define EP93XX_DMA_M2P_RX              0x10
-#define EP93XX_DMA_M2P_ABORT_ON_ERROR  0x20
-#define EP93XX_DMA_M2P_IGNORE_ERROR    0x40
-#define EP93XX_DMA_M2P_ERROR_MASK      0x60
 
-int  ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p);
+/* DMA M2P client flags */
+#define EP93XX_DMA_M2P_TX              0x00    /* Memory to peripheral */
+#define EP93XX_DMA_M2P_RX              0x10    /* Peripheral to memory */
+
+/*
+ * DMA M2P client error handling flags. See the EP93xx users guide
+ * documentation on the DMA M2P CONTROL register for more details
+ */
+#define EP93XX_DMA_M2P_ABORT_ON_ERROR  0x20    /* Abort on peripheral error */
+#define EP93XX_DMA_M2P_IGNORE_ERROR    0x40    /* Ignore peripheral errors */
+#define EP93XX_DMA_M2P_ERROR_MASK      0x60    /* Mask of error bits */
+
+/**
+ * ep93xx_dma_m2p_client_register - Register a client with the DMA M2P
+ * subsystem
+ *
+ * @m2p: Client information to register
+ * returns 0 on success
+ *
+ * The DMA M2P subsystem allocates a channel and an interrupt line for the DMA
+ * client
+ */
+int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p);
+
+/**
+ * ep93xx_dma_m2p_client_unregister - Unregister a client from the DMA M2P
+ * subsystem
+ *
+ * @m2p: Client to unregister
+ *
+ * Any transfers currently in progress will be completed in hardware, but
+ * ignored in software.
+ */
 void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *m2p);
+
+/**
+ * ep93xx_dma_m2p_submit - Submit a DMA M2P transfer
+ *
+ * @m2p: DMA Client to submit the transfer on
+ * @buf: DMA Buffer to submit
+ *
+ * If the current or next transfer positions are free on the M2P client then
+ * the transfer is started immediately. If not, the transfer is added to the
+ * list of pending transfers. This function must not be called from the
+ * buffer_finished callback for an M2P channel.
+ *
+ */
 void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *m2p,
                           struct ep93xx_dma_buffer *buf);
+
+/**
+ * ep93xx_dma_m2p_submit_recursive - Put a DMA transfer on the pending list
+ * for an M2P channel
+ *
+ * @m2p: DMA Client to submit the transfer on
+ * @buf: DMA Buffer to submit
+ *
+ * This function must only be called from the buffer_finished callback for an
+ * M2P channel. It is commonly used to add the next transfer in a chained list
+ * of DMA transfers.
+ */
 void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *m2p,
                                     struct ep93xx_dma_buffer *buf);
+
+/**
+ * ep93xx_dma_m2p_flush - Flush all pending transfers on a DMA M2P client
+ *
+ * @m2p: DMA client to flush transfers on
+ *
+ * Any transfers currently in progress will be completed in hardware, but
+ * ignored in software.
+ *
+ */
 void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *m2p);
 
 #endif /* __ASM_ARCH_DMA_H */
index 51ff23b72d3a3e8d6982b031dd36df0c3c1cc711..3688123b5ad8e5ea233b1346f22d19e3ec149030 100644 (file)
@@ -854,10 +854,9 @@ int __init kirkwood_find_tclk(void)
 
        kirkwood_pcie_id(&dev, &rev);
 
-       if ((dev == MV88F6281_DEV_ID && (rev == MV88F6281_REV_A0 ||
-                                       rev == MV88F6281_REV_A1)) ||
-           (dev == MV88F6282_DEV_ID))
-               return 200000000;
+       if (dev == MV88F6281_DEV_ID || dev == MV88F6282_DEV_ID)
+               if (((readl(SAMPLE_AT_RESET) >> 21) & 1) == 0)
+                       return 200000000;
 
        return 166666667;
 }
index 4aa86e4a152c22bc2707463b85d1f3d98240a509..a31c9499ab36c6a0f235e39cf22e4bd7f522d14c 100644 (file)
@@ -225,5 +225,5 @@ MACHINE_START(D2NET_V2, "LaCie d2 Network v2")
        .init_machine   = d2net_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &lacie_v2_timer,
+       .timer          = &kirkwood_timer,
 MACHINE_END
index d3ea1b6c8a02ff8790db0bf51d61f6643028cbc0..285edab776e9f5f389be444c343d7246694058ea 100644 (file)
@@ -111,17 +111,3 @@ void __init lacie_v2_hdd_power_init(int hdd_num)
                        pr_err("Failed to power up HDD%d\n", i + 1);
        }
 }
-
-/*****************************************************************************
- * Timer
- ****************************************************************************/
-
-static void lacie_v2_timer_init(void)
-{
-       kirkwood_tclk = 166666667;
-       orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
-
-struct sys_timer lacie_v2_timer = {
-       .init = lacie_v2_timer_init,
-};
index af521315b87bd621152cac1ae086edfa1db45373..fc64f578536ecc10f74517e991d948c81c331c14 100644 (file)
@@ -13,6 +13,4 @@ void lacie_v2_register_flash(void);
 void lacie_v2_register_i2c_devices(void);
 void lacie_v2_hdd_power_init(int hdd_num);
 
-extern struct sys_timer lacie_v2_timer;
-
 #endif
index 065187d177c6299f12543c3198c23c7cbd8f2476..27901f702feb28d5f4c5a0ff6ce9acbc0780af9d 100644 (file)
@@ -59,7 +59,7 @@ void __init kirkwood_mpp_conf(unsigned int *mpp_list)
        }
        printk("\n");
 
-       while (*mpp_list) {
+       for ( ; *mpp_list; mpp_list++) {
                unsigned int num = MPP_NUM(*mpp_list);
                unsigned int sel = MPP_SEL(*mpp_list);
                int shift, gpio_mode;
@@ -88,8 +88,6 @@ void __init kirkwood_mpp_conf(unsigned int *mpp_list)
                if (sel != 0)
                        gpio_mode = 0;
                orion_gpio_set_valid(num, gpio_mode);
-
-               mpp_list++;
        }
 
        printk(KERN_DEBUG "  final MPP regs:");
index 5ea66f1f4178b0b846cfb42e6e600ddb2d3a1f87..65ee21fd2f3bd5657ede5a034924c47e4a3cd6f8 100644 (file)
@@ -262,7 +262,7 @@ MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
        .init_machine   = netspace_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &lacie_v2_timer,
+       .timer          = &kirkwood_timer,
 MACHINE_END
 #endif
 
@@ -272,7 +272,7 @@ MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
        .init_machine   = netspace_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &lacie_v2_timer,
+       .timer          = &kirkwood_timer,
 MACHINE_END
 #endif
 
@@ -282,6 +282,6 @@ MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
        .init_machine   = netspace_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &lacie_v2_timer,
+       .timer          = &kirkwood_timer,
 MACHINE_END
 #endif
index a1b45d501aef57393a47e0d99e67a423ae3355fc..93afd3c8bfd8a66fdb80bdf6acf0cbc1538c31ed 100644 (file)
@@ -403,7 +403,7 @@ MACHINE_START(NET2BIG_V2, "LaCie 2Big Network v2")
        .init_machine   = netxbig_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &lacie_v2_timer,
+       .timer          = &kirkwood_timer,
 MACHINE_END
 #endif
 
@@ -413,6 +413,6 @@ MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
        .init_machine   = netxbig_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &lacie_v2_timer,
+       .timer          = &kirkwood_timer,
 MACHINE_END
 #endif
index 8be09a0ce4ac724a8e5981dba3ab1a723f5e77f5..3587a281d993825076e9e16032ad4c8b76ec4b88 100644 (file)
 #include "mpp.h"
 #include "tsx1x-common.h"
 
+/* for the PCIe reset workaround */
+#include <plat/pcie.h>
+
+
 #define QNAP_TS41X_JUMPER_JP1  45
 
 static struct i2c_board_info __initdata qnap_ts41x_i2c_rtc = {
@@ -140,8 +144,16 @@ static void __init qnap_ts41x_init(void)
 
 static int __init ts41x_pci_init(void)
 {
-       if (machine_is_ts41x())
+       if (machine_is_ts41x()) {
+               /*
+                * Without this explicit reset, the PCIe SATA controller
+                * (Marvell 88sx7042/sata_mv) is known to stop working
+                * after a few minutes.
+                */
+               orion_pcie_reset((void __iomem *)PCIE_VIRT_BASE);
+
                kirkwood_pcie_init(KW_PCIE0);
+       }
 
    return 0;
 }
index f43a68b213f111a200e0395638e3cc538e442b3e..8a3b56dfd35d7af96d47b367e5ccf0078d5d2f08 100644 (file)
@@ -46,7 +46,8 @@ static inline int cpu_is_pxa910(void)
 #ifdef CONFIG_CPU_MMP2
 static inline int cpu_is_mmp2(void)
 {
-       return (((cpu_readid_id() >> 8) & 0xff) == 0x58);
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x58);
+}
 #else
 #define cpu_is_mmp2()  (0)
 #endif
index 354ac514eb899125121eb84127bcb93deac2a115..84db2dfc475ca9b24f5b30fad2637ee099de08f6 100644 (file)
@@ -54,7 +54,7 @@ void __init mv78xx0_mpp_conf(unsigned int *mpp_list)
        }
        printk("\n");
 
-       while (*mpp_list) {
+       for ( ; *mpp_list; mpp_list++) {
                unsigned int num = MPP_NUM(*mpp_list);
                unsigned int sel = MPP_SEL(*mpp_list);
                int shift, gpio_mode;
@@ -83,8 +83,6 @@ void __init mv78xx0_mpp_conf(unsigned int *mpp_list)
                if (sel != 0)
                        gpio_mode = 0;
                orion_gpio_set_valid(num, gpio_mode);
-
-               mpp_list++;
        }
 
        printk(KERN_DEBUG "  final MPP regs:");
index ea0d80a89da7560ac0a6a9d5b0d5d3a52a89c258..e7f9ee63dce5f5cd5656dbff364cb4dc149dd2a2 100644 (file)
@@ -321,10 +321,9 @@ static struct platform_device omap_wdt_device = {
 static int __init omap_init_wdt(void)
 {
        if (!cpu_is_omap16xx())
-               return;
+               return -ENODEV;
 
-       platform_device_register(&omap_wdt_device);
-       return 0;
+       return platform_device_register(&omap_wdt_device);
 }
 subsys_initcall(omap_init_wdt);
 #endif
index fd54b452eb2289de01f31bada3de656509614116..847d00f0bb0a6ae2393e0bf116cc3df76e24b92b 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_ARCH_CAMERA_H_
 #define __ASM_ARCH_CAMERA_H_
 
+#include <media/omap1_camera.h>
+
 void omap1_camera_init(void *);
 
 static inline void omap1_set_camera_info(struct omap1_cam_platform_data *info)
index 067f4379c87fc5d927d201df192883b5bd914820..53ac762518bd7361c28833b626ef06ac5a836996 100644 (file)
@@ -242,9 +242,6 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
        mmc[0].gpio_cd = gpio + 0;
        omap2_hsmmc_init(mmc);
 
-       /* link regulators to MMC adapters */
-       devkit8000_vmmc1_supply.dev = mmc[0].dev;
-
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
 
index bc4c3b9aaf83346fc054b5cb23eb19287b3e2fc0..db485d3b814484f76faefa2943c4a2a17b8f08c4 100644 (file)
@@ -127,7 +127,7 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
        /* Initialize gpiolib. */
        orion_gpio_init();
 
-       while (mode->mpp >= 0) {
+       for ( ; mode->mpp >= 0; mode++) {
                u32 *reg;
                int num_type;
                int shift;
@@ -160,8 +160,6 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
                        orion_gpio_set_unused(mode->mpp);
 
                orion_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
-
-               mode++;
        }
 
        writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
index 16f1bd5324bebb94b01ec5af9db5eb82d4e3509f..c1c1cd04bdde4dc77dd4408096048c3f45b47964 100644 (file)
@@ -239,7 +239,7 @@ static struct platform_nand_data ts78xx_ts_nand_data = {
 static struct resource ts78xx_ts_nand_resources = {
        .start          = TS_NAND_DATA,
        .end            = TS_NAND_DATA + 4,
-       .flags          = IORESOURCE_IO,
+       .flags          = IORESOURCE_MEM,
 };
 
 static struct platform_device ts78xx_ts_nand_device = {
index ac5598ce97241f7d29947ee434d539c5c2109fe6..d34b99febeb99c76eef86caf2b20881f45b39fc1 100644 (file)
@@ -476,8 +476,6 @@ static void __init cmx2xx_init(void)
 
 static void __init cmx2xx_init_irq(void)
 {
-       pxa27x_init_irq();
-
        if (cpu_is_pxa25x()) {
                pxa25x_init_irq();
                cmx2xx_pci_init_irq(CMX255_GPIO_IT8152_IRQ);
index 4b521e045d754471df4cf4a66daff5d7434992b5..ffa50e633ee6856b88901228f46b6f21d527cc2f 100644 (file)
@@ -116,7 +116,7 @@ static struct platform_device smc91x_device = {
        },
 };
 
-#if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULE)
+#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
 static uint16_t lcd_power_on[] = {
        /* single frame */
        SMART_CMD_NOOP,
index 1ca7bdc6485c44aaffd773a97f524f3a8131c972..579d2f0f4dd0ec3c536262f2d52706ae81c4bac7 100644 (file)
@@ -143,7 +143,7 @@ config MACH_SMDK6410
        select S3C_DEV_USB_HSOTG
        select S3C_DEV_WDT
        select SAMSUNG_DEV_KEYPAD
-       select HAVE_S3C2410_WATCHDOG
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        select S3C64XX_SETUP_SDHCI
        select S3C64XX_SETUP_I2C1
        select S3C64XX_SETUP_IDE
index 54b479c35ee01d2db0f2f5c75f9786f329293146..51dcd59eda6a1aeb965d02b5b94bf66e8737e2ff 100644 (file)
@@ -116,4 +116,6 @@ endmenu
 config SH_CLK_CPG
        bool
 
+source "drivers/sh/Kconfig"
+
 endif
index 46ca4d4abf910aad98652306a7d41bfa7ccdcfe8..d3260542b943df9a4743b7ba5489f3a0d5733780 100644 (file)
@@ -163,11 +163,13 @@ static struct mtd_partition nor_flash_partitions[] = {
                .name           = "loader",
                .offset         = 0x00000000,
                .size           = 512 * 1024,
+               .mask_flags     = MTD_WRITEABLE,
        },
        {
                .name           = "bootenv",
                .offset         = MTDPART_OFS_APPEND,
                .size           = 512 * 1024,
+               .mask_flags     = MTD_WRITEABLE,
        },
        {
                .name           = "kernel_ro",
@@ -565,12 +567,54 @@ static struct platform_device *qhd_devices[] __initdata = {
 
 /* FSI */
 #define IRQ_FSI                evt2irq(0x1840)
+
+static int fsi_set_rate(int is_porta, int rate)
+{
+       struct clk *fsib_clk;
+       struct clk *fdiv_clk = &sh7372_fsidivb_clk;
+       int ret;
+
+       /* set_rate is not needed if port A */
+       if (is_porta)
+               return 0;
+
+       fsib_clk = clk_get(NULL, "fsib_clk");
+       if (IS_ERR(fsib_clk))
+               return -EINVAL;
+
+       switch (rate) {
+       case 44100:
+               clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 11283000));
+               ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+               break;
+       case 48000:
+               clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000));
+               clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000));
+               ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+               break;
+       default:
+               pr_err("unsupported rate in FSI2 port B\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       clk_put(fsib_clk);
+
+       return ret;
+}
+
 static struct sh_fsi_platform_info fsi_info = {
        .porta_flags = SH_FSI_BRS_INV |
                       SH_FSI_OUT_SLAVE_MODE |
                       SH_FSI_IN_SLAVE_MODE |
                       SH_FSI_OFMT(PCM) |
                       SH_FSI_IFMT(PCM),
+
+       .portb_flags = SH_FSI_BRS_INV |
+                      SH_FSI_BRM_INV |
+                      SH_FSI_LRS_INV |
+                      SH_FSI_OFMT(SPDIF),
+       .set_rate = fsi_set_rate,
 };
 
 static struct resource fsi_resources[] = {
@@ -634,6 +678,7 @@ static struct platform_device lcdc1_device = {
 static struct sh_mobile_hdmi_info hdmi_info = {
        .lcd_chan = &sh_mobile_lcdc1_info.ch[0],
        .lcd_dev = &lcdc1_device.dev,
+       .flags = HDMI_SND_SRC_SPDIF,
 };
 
 static struct resource hdmi_resources[] = {
@@ -992,6 +1037,7 @@ static void __init ap4evb_map_io(void)
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
+#define USCCR1         0xE6058144
 static void __init ap4evb_init(void)
 {
        u32 srcr4;
@@ -1062,7 +1108,7 @@ static void __init ap4evb_init(void)
        /* setup USB phy */
        __raw_writew(0x8a0a, 0xE6058130);       /* USBCR2 */
 
-       /* enable FSI2 */
+       /* enable FSI2 port A (ak4643) */
        gpio_request(GPIO_FN_FSIAIBT,   NULL);
        gpio_request(GPIO_FN_FSIAILR,   NULL);
        gpio_request(GPIO_FN_FSIAISLD,  NULL);
@@ -1079,6 +1125,10 @@ static void __init ap4evb_init(void)
        gpio_request(GPIO_PORT41, NULL);
        gpio_direction_input(GPIO_PORT41);
 
+       /* setup FSI2 port B (HDMI) */
+       gpio_request(GPIO_FN_FSIBCK, NULL);
+       __raw_writew(__raw_readw(USCCR1) & ~(1 << 6), USCCR1); /* use SPDIF */
+
        /* set SPU2 clock to 119.6 MHz */
        clk = clk_get(NULL, "spu_clk");
        if (!IS_ERR(clk)) {
index 8565aefa21fd3c2e62877c3de33a43d8390dda76..7db31e6c6bf2085908cb66ce669238488c5aa444 100644 (file)
@@ -50,6 +50,9 @@
 #define SMSTPCR3       0xe615013c
 #define SMSTPCR4       0xe6150140
 
+#define FSIDIVA                0xFE1F8000
+#define FSIDIVB                0xFE1F8008
+
 /* Platforms must set frequency on their DV_CLKI pin */
 struct clk sh7372_dv_clki_clk = {
 };
@@ -288,6 +291,7 @@ struct clk sh7372_pllc2_clk = {
        .ops            = &pllc2_clk_ops,
        .parent         = &extal1_div2_clk,
        .freq_table     = pllc2_freq_table,
+       .nr_freqs       = ARRAY_SIZE(pllc2_freq_table) - 1,
        .parent_table   = pllc2_parent,
        .parent_num     = ARRAY_SIZE(pllc2_parent),
 };
@@ -417,6 +421,101 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
                                      fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2),
 };
 
+/* FSI DIV */
+static unsigned long fsidiv_recalc(struct clk *clk)
+{
+       unsigned long value;
+
+       value = __raw_readl(clk->mapping->base);
+
+       if ((value & 0x3) != 0x3)
+               return 0;
+
+       value >>= 16;
+       if (value < 2)
+               return 0;
+
+       return clk->parent->rate / value;
+}
+
+static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk_rate_div_range_round(clk, 2, 0xffff, rate);
+}
+
+static void fsidiv_disable(struct clk *clk)
+{
+       __raw_writel(0, clk->mapping->base);
+}
+
+static int fsidiv_enable(struct clk *clk)
+{
+       unsigned long value;
+
+       value  = __raw_readl(clk->mapping->base) >> 16;
+       if (value < 2) {
+               fsidiv_disable(clk);
+               return -ENOENT;
+       }
+
+       __raw_writel((value << 16) | 0x3, clk->mapping->base);
+
+       return 0;
+}
+
+static int fsidiv_set_rate(struct clk *clk,
+                          unsigned long rate, int algo_id)
+{
+       int idx;
+
+       if (clk->parent->rate == rate) {
+               fsidiv_disable(clk);
+               return 0;
+       }
+
+       idx = (clk->parent->rate / rate) & 0xffff;
+       if (idx < 2)
+               return -ENOENT;
+
+       __raw_writel(idx << 16, clk->mapping->base);
+       return fsidiv_enable(clk);
+}
+
+static struct clk_ops fsidiv_clk_ops = {
+       .recalc         = fsidiv_recalc,
+       .round_rate     = fsidiv_round_rate,
+       .set_rate       = fsidiv_set_rate,
+       .enable         = fsidiv_enable,
+       .disable        = fsidiv_disable,
+};
+
+static struct clk_mapping sh7372_fsidiva_clk_mapping = {
+       .phys   = FSIDIVA,
+       .len    = 8,
+};
+
+struct clk sh7372_fsidiva_clk = {
+       .ops            = &fsidiv_clk_ops,
+       .parent         = &div6_reparent_clks[DIV6_FSIA], /* late install */
+       .mapping        = &sh7372_fsidiva_clk_mapping,
+};
+
+static struct clk_mapping sh7372_fsidivb_clk_mapping = {
+       .phys   = FSIDIVB,
+       .len    = 8,
+};
+
+struct clk sh7372_fsidivb_clk = {
+       .ops            = &fsidiv_clk_ops,
+       .parent         = &div6_reparent_clks[DIV6_FSIB],  /* late install */
+       .mapping        = &sh7372_fsidivb_clk_mapping,
+};
+
+static struct clk *late_main_clks[] = {
+       &sh7372_fsidiva_clk,
+       &sh7372_fsidivb_clk,
+};
+
 enum { MSTP001,
        MSTP131, MSTP130,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
@@ -585,6 +684,9 @@ void __init sh7372_clock_init(void)
        if (!ret)
                ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
+       for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+               ret = clk_register(late_main_clks[k]);
+
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
index 5bc6bd444d7236016eac8c004f764da16a481380..2b1bb9e43ddadc8b83505b021c5ca7ae4f4704c5 100644 (file)
@@ -35,12 +35,12 @@ static inline int gpio_cansleep(unsigned gpio)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       return -ENOSYS;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
 {
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 #endif /* CONFIG_GPIOLIB */
index 147775a94bcefa528d662f8d49d0d93b6302cddf..e4f9004e710382574fcf5e23cb67339fa0f53148 100644 (file)
@@ -464,5 +464,7 @@ extern struct clk sh7372_dv_clki_div2_clk;
 extern struct clk sh7372_pllc2_clk;
 extern struct clk sh7372_fsiack_clk;
 extern struct clk sh7372_fsibck_clk;
+extern struct clk sh7372_fsidiva_clk;
+extern struct clk sh7372_fsidivb_clk;
 
 #endif /* __ASM_SH7372_H__ */
index 4cd3cae38e7297fbe21c4acfc52f1c91f135a7cf..30b2f400666af11a0097eb593b949affc818c547 100644 (file)
@@ -98,7 +98,7 @@ static struct intc_vect intca_vectors[] __initdata = {
        INTC_VECT(IRQ14A, 0x03c0), INTC_VECT(IRQ15A, 0x03e0),
        INTC_VECT(IRQ16A, 0x3200), INTC_VECT(IRQ17A, 0x3220),
        INTC_VECT(IRQ18A, 0x3240), INTC_VECT(IRQ19A, 0x3260),
-       INTC_VECT(IRQ20A, 0x3280), INTC_VECT(IRQ31A, 0x32a0),
+       INTC_VECT(IRQ20A, 0x3280), INTC_VECT(IRQ21A, 0x32a0),
        INTC_VECT(IRQ22A, 0x32c0), INTC_VECT(IRQ23A, 0x32e0),
        INTC_VECT(IRQ24A, 0x3300), INTC_VECT(IRQ25A, 0x3320),
        INTC_VECT(IRQ26A, 0x3340), INTC_VECT(IRQ27A, 0x3360),
index c2e405a9e0256141d62dfad2f359bfa7bac87555..fd25ccd7272f7045b24a193f4c025a84c3bca97b 100644 (file)
@@ -54,7 +54,9 @@ static struct map_desc ct_ca9x4_io_desc[] __initdata = {
 
 static void __init ct_ca9x4_map_io(void)
 {
+#ifdef CONFIG_LOCAL_TIMERS
        twd_base = MMIO_P2V(A9_MPCORE_TWD);
+#endif
        v2m_map_io(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
index e4dd0646e85978b89a164c40100d0561bd1005f7..ac6a36142fcd5a28084b3c669fac9e800fd65497 100644 (file)
@@ -198,7 +198,7 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot)
         * fragmentation of the DMA space, and also prevents allocations
         * smaller than a section from crossing a section boundary.
         */
-       bit = fls(size - 1) + 1;
+       bit = fls(size - 1);
        if (bit > SECTION_SHIFT)
                bit = SECTION_SHIFT;
        align = 1 << bit;
index 6f42a18b8aa417abc5622bf9492d9a4587111738..fc819120978dbe9e722903c95296aa6faa7a6f4e 100644 (file)
@@ -284,12 +284,14 @@ void __init omap_dsp_reserve_sdram_memblock(void)
        if (!size)
                return;
 
-       paddr = __memblock_alloc_base(size, SZ_1M, MEMBLOCK_REAL_LIMIT);
+       paddr = memblock_alloc(size, SZ_1M);
        if (!paddr) {
                pr_err("%s: failed to reserve %x bytes\n",
                                __func__, size);
                return;
        }
+       memblock_free(paddr, size);
+       memblock_remove(paddr, size);
 
        omap_dsp_phys_mempool_base = paddr;
 }
index f5c5b8da9a87f194683afa8b51ebecb39e53f302..2c2826571d45856145f7a31a416edee84b13802e 100644 (file)
@@ -1983,6 +1983,8 @@ static int omap2_dma_handle_ch(int ch)
 
        dma_write(OMAP2_DMA_CSR_CLEAR_MASK, CSR(ch));
        dma_write(1 << ch, IRQSTATUS_L0);
+       /* read back the register to flush the write */
+       dma_read(IRQSTATUS_L0);
 
        /* If the ch is not chained then chain_id will be -1 */
        if (dma_chan[ch].chain_id != -1) {
index 3ebfef72b4e700406f43131349eda135747a3304..cc99163e73fdbde0f4945a93c35cdd5830c25ac5 100644 (file)
 #ifndef __PLAT_PCIE_H
 #define __PLAT_PCIE_H
 
+struct pci_bus;
+
 u32 orion_pcie_dev_id(void __iomem *base);
 u32 orion_pcie_rev(void __iomem *base);
 int orion_pcie_link_up(void __iomem *base);
 int orion_pcie_x4_mode(void __iomem *base);
 int orion_pcie_get_local_bus_nr(void __iomem *base);
 void orion_pcie_set_local_bus_nr(void __iomem *base, int nr);
+void orion_pcie_reset(void __iomem *base);
 void orion_pcie_setup(void __iomem *base,
                      struct mbus_dram_target_info *dram);
 int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
index 779553a1595e938ead6a4764e84ee8d87087acb9..af2d733c50b5cf9a32ec07932a1b64131d95ca46 100644 (file)
@@ -181,11 +181,6 @@ void __init orion_pcie_setup(void __iomem *base,
        u16 cmd;
        u32 mask;
 
-       /*
-        * soft reset PCIe unit
-        */
-       orion_pcie_reset(base);
-
        /*
         * Point PCIe unit MBUS decode windows to DRAM space.
         */
index cd0c090ebc54e1c59225144d2bf9118f7c74dca5..b407bc8ad9186f05fee0f657ffec48e7aab87efe 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/unistd.h>
 #include <linux/user.h>
 #include <linux/uaccess.h>
index 2b63b0191f529d187f0cde1298c637e32973fabb..efad12071c2e7b95324e9a1f0a8f7e88a6a7d645 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
index 97478138e361ad702308539b4d067543402df7cb..933bd388efb28c35804b482aab8014f75036afce 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
index 3a078ad3aa44e4a91ebfb256ca49ba674a35a3da..331de723c6767f264e8ee682fcb73aa44d4a7bf7 100644 (file)
@@ -202,7 +202,7 @@ simscsi_readwrite10 (struct scsi_cmnd *sc, int mode)
 }
 
 static int
-simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
        unsigned int target_id = sc->device->id;
        char fname[MAX_ROOT_LEN+16];
@@ -326,6 +326,8 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(simscsi_queuecommand)
+
 static int
 simscsi_host_reset (struct scsi_cmnd *sc)
 {
index 4a5b284a15500f4a1a8525dab1609d34310599c0..7ef4115b8c4a59f0248df2273184ab5e2ed8f053 100644 (file)
@@ -2,7 +2,9 @@
 #define _M68K_IRQFLAGS_H
 
 #include <linux/types.h>
+#ifdef CONFIG_MMU
 #include <linux/hardirq.h>
+#endif
 #include <linux/preempt.h>
 #include <asm/thread_info.h>
 #include <asm/entry.h>
index 789f3b2de0e9bf2f63720bcc0c522c686e9c9d31..415d5484916c4d9e6ec1981e380cfe9a0f1ab4de 100644 (file)
@@ -40,5 +40,6 @@ extern unsigned long hw_timer_offset(void);
 extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
 
 extern void config_BSP(char *command, int len);
+extern void do_IRQ(int irq, struct pt_regs *fp);
 
 #endif /* _M68K_MACHDEP_H */
index 18732ab232923faeedbbcd80c02a98364f285215..c2a1fc23dd758e69a49bb45d6e62247f4adf68ce 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
index 6d3390590e5ba24be497b5c4a42d0327dbae6cf9..e2a63af5d517510820cfa9085d46b08bcd403f46 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
index 0d0f8049a17b557183be48f844bb4b100f5cc87a..e1b14a6ed544675bf7929dc7861876a1a3bf2cc8 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
index ba430a03bc7a51cd99f8dd9ed3688ba531748c0e..30394081d9b6d51ab7486c70054b4bea7beaec89 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/utsname.h>
 #include <linux/vfs.h>
index 9779ece2b07079189884f2f17807adb85e6e5bbe..88a0ad14a9c99a466c9aaaf6ba6459868a61d1fa 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/times.h>
 #include <linux/time.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
index b6447190e1a2acee2b6fddf9ef90bd5a3d0a1da9..e625e9e034ae19abe973282a3d83952493e8b709 100644 (file)
@@ -4,6 +4,10 @@ config PPC32
        bool
        default y if !PPC64
 
+config 32BIT
+       bool
+       default y if PPC32
+
 config 64BIT
        bool
        default y if PPC64
index 722f360a32a9e905b2edf6f3cdb90b9ef9e5d588..d271ab5426732ab07ec0bec73e52a195e493fe64 100644 (file)
@@ -33,9 +33,10 @@ __div64_32:
        cntlzw  r0,r5           # we are shifting the dividend right
        li      r10,-1          # to make it < 2^32, and shifting
        srw     r10,r10,r0      # the divisor right the same amount,
-       add     r9,r4,r10       # rounding up (so the estimate cannot
+       addc    r9,r4,r10       # rounding up (so the estimate cannot
        andc    r11,r6,r10      # ever be too large, only too small)
        andc    r9,r9,r10
+       addze   r9,r9
        or      r11,r5,r11
        rotlw   r9,r9,r0
        rotlw   r11,r11,r0
index 7a9db64f3f0438f8bf366b9cb2244f1ef3178004..42850ee00adabfa33f0bb5ccd69efe1388d8ec96 100644 (file)
@@ -337,7 +337,7 @@ char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
                /* FP registers 32 -> 63 */
 #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
                if (current)
-                       memcpy(mem, current->thread.evr[regno-32],
+                       memcpy(mem, &current->thread.evr[regno-32],
                                        dbg_reg_def[regno].size);
 #else
                /* fp registers not used by kernel, leave zero */
@@ -362,7 +362,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
        if (regno >= 32 && regno < 64) {
                /* FP registers 32 -> 63 */
 #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
-               memcpy(current->thread.evr[regno-32], mem,
+               memcpy(&current->thread.evr[regno-32], mem,
                                dbg_reg_def[regno].size);
 #else
                /* fp registers not used by kernel, leave zero */
index 428d0e538aec50880f23b8b097698572a2d2a01a..b06bdae04064f59d2c4c4c98e76304dee6ca98c8 100644 (file)
@@ -127,7 +127,7 @@ static void kvm_patch_ins_nop(u32 *inst)
 
 static void kvm_patch_ins_b(u32 *inst, int addr)
 {
-#ifdef CONFIG_RELOCATABLE
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S)
        /* On relocatable kernels interrupts handlers and our code
           can be in different regions, so we don't patch them */
 
index 2a178b0ebcdf8ea33ed67c8a4516b7ec0f1d9f26..ce6f61c6f871022baedac98bd751de6110ff42c1 100644 (file)
@@ -497,9 +497,8 @@ static void __init emergency_stack_init(void)
 }
 
 /*
- * Called into from start_kernel, after lock_kernel has been called.
- * Initializes bootmem, which is unsed to manage page allocation until
- * mem_init is called.
+ * Called into from start_kernel this initializes bootmem, which is used
+ * to manage page allocation until mem_init is called.
  */
 void __init setup_arch(char **cmdline_p)
 {
index b1b6043a56c44f6b07537e8eb4a0aa720400e296..4e5bf1edc0f2e19690175719fcaf20bc2994237f 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
index 049846911ce4d18d8097507b9be0caa8d767733c..1cc471faac2dd4bac032a956860b4f10d29170cb 100644 (file)
@@ -416,7 +416,7 @@ lightweight_exit:
        lwz     r3, VCPU_PC(r4)
        mtsrr0  r3
        lwz     r3, VCPU_SHARED(r4)
-       lwz     r3, VCPU_SHARED_MSR(r3)
+       lwz     r3, (VCPU_SHARED_MSR + 4)(r3)
        oris    r3, r3, KVMPPC_MSR_MASK@h
        ori     r3, r3, KVMPPC_MSR_MASK@l
        mtsrr1  r3
index 71750f2dd5d34378c963acf7bf9d3a69a15863cc..e3768ee9b59537bf92eceb853fa9edf56d7d5b6c 100644 (file)
@@ -138,8 +138,8 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 
        free_page((unsigned long)vcpu->arch.shared);
-       kvmppc_e500_tlb_uninit(vcpu_e500);
        kvm_vcpu_uninit(vcpu);
+       kvmppc_e500_tlb_uninit(vcpu_e500);
        kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 }
 
index 2f87a1627f6cff35604f96e8e041cffd9af071ff..38f756f2505389ac5f59eb9ae3921ef72175eea1 100644 (file)
@@ -617,6 +617,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
        switch (ioctl) {
        case KVM_PPC_GET_PVINFO: {
                struct kvm_ppc_pvinfo pvinfo;
+               memset(&pvinfo, 0, sizeof(pvinfo));
                r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
                if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
                        r = -EFAULT;
index 46fa04f12a9b979c7cbe50c703d43e2c2705604e..a021f5827a336ce97b6c62ed5b8d0ca625d571bf 100644 (file)
@@ -35,7 +35,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        int i;
 
        /* pause guest execution to avoid concurrent updates */
-       local_irq_disable();
        mutex_lock(&vcpu->mutex);
 
        vcpu->arch.last_exit_type = 0xDEAD;
@@ -51,7 +50,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        vcpu->arch.timing_last_enter.tv64 = 0;
 
        mutex_unlock(&vcpu->mutex);
-       local_irq_enable();
 }
 
 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
index 83f534d862db2cd3934fca431e9b4d67b4ac7d38..5e9584405c4560c13c5567ba6affa81b2391e6bd 100644 (file)
@@ -1123,7 +1123,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
        else
 #endif /* CONFIG_PPC_HAS_HASH_64K */
                rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
-                                   subpage_protection(pgdir, ea));
+                                   subpage_protection(mm, ea));
 
        /* Dump some info in case of hash insertion failure, they should
         * never happen so it is really useful to know if/when they do
index 8b04c54e596f2a5a1bf770cb44013808eaf27246..8526bd9d2aa33603be03dbf10bc3656c7a833448 100644 (file)
        cmpldi  cr0,r15,0                       /* Check for user region */
        std     r14,EX_TLB_ESR(r12)             /* write crazy -1 to frame */
        beq     normal_tlb_miss
+
+       li      r11,_PAGE_PRESENT|_PAGE_BAP_SX  /* Base perm */
+       oris    r11,r11,_PAGE_ACCESSED@h
        /* XXX replace the RMW cycles with immediate loads + writes */
-1:     mfspr   r10,SPRN_MAS1
+       mfspr   r10,SPRN_MAS1
        cmpldi  cr0,r15,8                       /* Check for vmalloc region */
        rlwinm  r10,r10,0,16,1                  /* Clear TID */
        mtspr   SPRN_MAS1,r10
index 36c0c449a89993659c60d1b4c4b772fb5aa5f94c..2a030d89bbc6e65a847a29f6c4bf012f2e6188b0 100644 (file)
@@ -585,6 +585,6 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
        ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
 
        /* Finally limit subsequent allocations */
-       memblock_set_current_limit(ppc64_memblock_base + ppc64_rma_size);
+       memblock_set_current_limit(first_memblock_base + ppc64_rma_size);
 }
 #endif /* CONFIG_PPC64 */
index c667f0f02c34cc44eb75138e8eae6b140a49c3e8..3139814f643985e1879ed876b651a7f1e2a370a7 100644 (file)
@@ -47,6 +47,12 @@ config LPARCFG
 config PPC_PSERIES_DEBUG
        depends on PPC_PSERIES && PPC_EARLY_DEBUG
        bool "Enable extra debug logging in platforms/pseries"
+        help
+         Say Y here if you want the pseries core to produce a bunch of
+         debug messages to the system log. Select this if you are having a
+         problem with the pseries core and want to see more of what is
+         going on. This does not enable debugging in lpar.c, which must
+         be manually done due to its verbosity.
        default y
 
 config PPC_SMLPAR
index 34b7dc12e731231e9c0110bbe7caeda20ec5c0c0..17a11c82e6f8d61676edc341783a81fc4da1cb4a 100644 (file)
@@ -21,8 +21,6 @@
  * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com>
  */
 
-#undef DEBUG
-
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/list.h>
index 4b7a062dee15373e93b0b44c66c5ad0fbd5ee086..5fcc92a12d3e1256b1c5d648b624f4791e3b0817 100644 (file)
@@ -25,8 +25,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#undef DEBUG
-
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
index 45e0c6199f36d6484df7adc657527c02c7974a4e..05221b13ffb1ed746b4a276a06ad0b9bfca95364 100644 (file)
@@ -6,6 +6,18 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
+config STRICT_DEVMEM
+       def_bool y
+       prompt "Filter access to /dev/mem"
+       ---help---
+         This option restricts access to /dev/mem.  If this option is
+         disabled, you allow userspace access to all memory, including
+         kernel and userspace memory. Accidental memory access is likely
+         to be disastrous.
+         Memory access is required for experts who want to debug the kernel.
+
+         If you are unsure, say Y.
+
 config DEBUG_STRICT_USER_COPY_CHECKS
        bool "Strict user copy size checks"
        ---help---
index a8729ea7e9ac1d12826fb4a0e76923a19af307fa..3c987e9ec8d69e61d4eaaa5f21e409613662324c 100644 (file)
@@ -130,6 +130,11 @@ struct page;
 void arch_free_page(struct page *page, int order);
 void arch_alloc_page(struct page *page, int order);
 
+static inline int devmem_is_allowed(unsigned long pfn)
+{
+       return 0;
+}
+
 #define HAVE_ARCH_FREE_PAGE
 #define HAVE_ARCH_ALLOC_PAGE
 
index 1e6449c79ab6de6de8d7c9f1de8ed1b8bdde66d5..53acaa86dd94f353e36beb03f5c9e904c14d42d3 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
index d60fc439851658761cd105d8d403be2e69fee0ad..2564793ec2b6fd0dede210f10694615606239511 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/sections.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/hardirq.h>
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -212,7 +213,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
        /* Set the PER control regs, turns on single step for this address */
        __ctl_load(kprobe_per_regs, 9, 11);
        regs->psw.mask |= PSW_MASK_PER;
-       regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+       regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
 }
 
 static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
@@ -239,7 +240,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
        __get_cpu_var(current_kprobe) = p;
        /* Save the interrupt and per flags */
        kcb->kprobe_saved_imask = regs->psw.mask &
-           (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+               (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
        /* Save the control regs that govern PER */
        __ctl_store(kcb->kprobe_saved_ctl, 9, 11);
 }
@@ -316,8 +317,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
                return 1;
 
 ss_probe:
-       if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
-               local_irq_disable();
        prepare_singlestep(p, regs);
        kcb->kprobe_status = KPROBE_HIT_SS;
        return 1;
@@ -350,6 +349,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
        struct hlist_node *node, *tmp;
        unsigned long flags, orig_ret_address = 0;
        unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+       kprobe_opcode_t *correct_ret_addr = NULL;
 
        INIT_HLIST_HEAD(&empty_rp);
        kretprobe_hash_lock(current, &head, &flags);
@@ -372,10 +372,32 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
                        /* another task is sharing our hash bucket */
                        continue;
 
-               if (ri->rp && ri->rp->handler)
-                       ri->rp->handler(ri, regs);
+               orig_ret_address = (unsigned long)ri->ret_addr;
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+       correct_ret_addr = ri->ret_addr;
+       hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
 
                orig_ret_address = (unsigned long)ri->ret_addr;
+
+               if (ri->rp && ri->rp->handler) {
+                       ri->ret_addr = correct_ret_addr;
+                       ri->rp->handler(ri, regs);
+               }
+
                recycle_rp_inst(ri, &empty_rp);
 
                if (orig_ret_address != trampoline_address) {
@@ -387,7 +409,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
                        break;
                }
        }
-       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
        regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
 
        reset_current_kprobe();
@@ -465,8 +487,6 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
                goto out;
        }
        reset_current_kprobe();
-       if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
-               local_irq_enable();
 out:
        preempt_enable_no_resched();
 
@@ -482,7 +502,7 @@ out:
        return 1;
 }
 
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
 {
        struct kprobe *cur = kprobe_running();
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -508,8 +528,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
                        restore_previous_kprobe(kcb);
                else {
                        reset_current_kprobe();
-                       if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
-                               local_irq_enable();
                }
                preempt_enable_no_resched();
                break;
@@ -553,6 +571,18 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
        return 0;
 }
 
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       int ret;
+
+       if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+               local_irq_disable();
+       ret = kprobe_trap_handler(regs, trapnr);
+       if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+               local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
+       return ret;
+}
+
 /*
  * Wrapper routine to for handling exceptions.
  */
@@ -560,8 +590,12 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                                       unsigned long val, void *data)
 {
        struct die_args *args = (struct die_args *)data;
+       struct pt_regs *regs = args->regs;
        int ret = NOTIFY_DONE;
 
+       if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+               local_irq_disable();
+
        switch (val) {
        case DIE_BPT:
                if (kprobe_handler(args->regs))
@@ -572,16 +606,17 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                        ret = NOTIFY_STOP;
                break;
        case DIE_TRAP:
-               /* kprobe_running() needs smp_processor_id() */
-               preempt_disable();
-               if (kprobe_running() &&
-                   kprobe_fault_handler(args->regs, args->trapnr))
+               if (!preemptible() && kprobe_running() &&
+                   kprobe_trap_handler(args->regs, args->trapnr))
                        ret = NOTIFY_STOP;
-               preempt_enable();
                break;
        default:
                break;
        }
+
+       if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+               local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
+
        return ret;
 }
 
@@ -595,6 +630,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 
        /* setup return addr to the jprobe handler routine */
        regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
+       regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
 
        /* r14 is the function return address */
        kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
index 38e641cdd9779ca3c96a1accf6faeb0d7148f82c..45b405ca25673a416ca33bfdd5b20a81c4876264 100644 (file)
 static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
                unsigned long end, int write, struct page **pages, int *nr)
 {
-       unsigned long mask, result;
+       unsigned long mask;
        pte_t *ptep, pte;
        struct page *page;
 
-       result = write ? 0 : _PAGE_RO;
-       mask = result | _PAGE_INVALID | _PAGE_SPECIAL;
+       mask = (write ? _PAGE_RO : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
 
        ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
        do {
                pte = *ptep;
                barrier();
-               if ((pte_val(pte) & mask) != result)
+               if ((pte_val(pte) & mask) != 0)
                        return 0;
                VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
                page = pte_page(pte);
index 5c075f562ebae912476974f20faee1bfaeec707d..7f217b3a50a806b7347f991b588397011aa3388e 100644 (file)
@@ -193,6 +193,7 @@ config CPU_SH2
 config CPU_SH2A
        bool
        select CPU_SH2
+       select UNCACHED_MAPPING
 
 config CPU_SH3
        bool
index 307b3a4a790b98b61bd3cb893dfa155ff4983e0b..9c8c6e1a2a154d4dff50db8d0d532201c5f991be 100644 (file)
@@ -133,10 +133,7 @@ machdir-$(CONFIG_SOLUTION_ENGINE)          += mach-se
 machdir-$(CONFIG_SH_HP6XX)                     += mach-hp6xx
 machdir-$(CONFIG_SH_DREAMCAST)                 += mach-dreamcast
 machdir-$(CONFIG_SH_SH03)                      += mach-sh03
-machdir-$(CONFIG_SH_SECUREEDGE5410)            += mach-snapgear
 machdir-$(CONFIG_SH_RTS7751R2D)                        += mach-r2d
-machdir-$(CONFIG_SH_7751_SYSTEMH)              += mach-systemh
-machdir-$(CONFIG_SH_EDOSK7705)                 += mach-edosk7705
 machdir-$(CONFIG_SH_HIGHLANDER)                        += mach-highlander
 machdir-$(CONFIG_SH_MIGOR)                     += mach-migor
 machdir-$(CONFIG_SH_AP325RXA)                  += mach-ap325rxa
index 9c94711aa6caee785b152ba7be282b98a6b6d285..2018c7ea4c93f49d53d7f1ff82f32db2b85e85bc 100644 (file)
@@ -81,13 +81,6 @@ config SH_7343_SOLUTION_ENGINE
          Select 7343 SolutionEngine if configuring for a Hitachi
          SH7343 (SH-Mobile 3AS) evaluation board.
 
-config SH_7751_SYSTEMH
-       bool "SystemH7751R"
-       depends on CPU_SUBTYPE_SH7751R
-       help
-         Select SystemH if you are configuring for a Renesas SystemH
-         7751R evaluation board.
-
 config SH_HP6XX
        bool "HP6XX"
        select SYS_SUPPORTS_APM_EMULATION
index 38ef655cc0f08cfe0f881b053f421e9861412556..be7d11d04b26a3abcaeacde829e496f970903c33 100644 (file)
@@ -2,10 +2,12 @@
 # Specific board support, not covered by a mach group.
 #
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)        += board-magicpanelr2.o
+obj-$(CONFIG_SH_SECUREEDGE5410)        += board-secureedge5410.o
 obj-$(CONFIG_SH_SH2007)                += board-sh2007.o
 obj-$(CONFIG_SH_SH7785LCR)     += board-sh7785lcr.o
 obj-$(CONFIG_SH_URQUELL)       += board-urquell.o
 obj-$(CONFIG_SH_SHMIN)         += board-shmin.o
+obj-$(CONFIG_SH_EDOSK7705)     += board-edosk7705.o
 obj-$(CONFIG_SH_EDOSK7760)     += board-edosk7760.o
 obj-$(CONFIG_SH_ESPT)          += board-espt.o
 obj-$(CONFIG_SH_POLARIS)       += board-polaris.o
diff --git a/arch/sh/boards/board-edosk7705.c b/arch/sh/boards/board-edosk7705.c
new file mode 100644 (file)
index 0000000..4cb3bb7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000  Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smc91x.h>
+#include <asm/machvec.h>
+#include <asm/sizes.h>
+
+#define SMC_IOBASE     0xA2000000
+#define SMC_IO_OFFSET  0x300
+#define SMC_IOADDR     (SMC_IOBASE + SMC_IO_OFFSET)
+
+#define ETHERNET_IRQ   0x09
+
+static void __init sh_edosk7705_init_irq(void)
+{
+       make_imask_irq(ETHERNET_IRQ);
+}
+
+/* eth initialization functions */
+static struct smc91x_platdata smc91x_info = {
+       .flags = SMC91X_USE_16BIT | SMC91X_IO_SHIFT_1 | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static struct resource smc91x_res[] = {
+       [0] = {
+               .start  = SMC_IOADDR,
+               .end    = SMC_IOADDR + SZ_32 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ETHERNET_IRQ,
+               .end    = ETHERNET_IRQ,
+               .flags  = IORESOURCE_IRQ ,
+       }
+};
+
+static struct platform_device smc91x_dev = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc91x_res),
+       .resource       = smc91x_res,
+
+       .dev    = {
+               .platform_data  = &smc91x_info,
+       },
+};
+
+/* platform init code */
+static struct platform_device *edosk7705_devices[] __initdata = {
+       &smc91x_dev,
+};
+
+static int __init init_edosk7705_devices(void)
+{
+       return platform_add_devices(edosk7705_devices,
+                                   ARRAY_SIZE(edosk7705_devices));
+}
+__initcall(init_edosk7705_devices);
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_edosk7705 __initmv = {
+       .mv_name                = "EDOSK7705",
+       .mv_nr_irqs             = 80,
+       .mv_init_irq            = sh_edosk7705_init_irq,
+};
diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c
new file mode 100644 (file)
index 0000000..32f875e
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ *
+ * Based on files with the following comments:
+ *
+ *           Copyright (C) 2000  Kazumoto Kojima
+ *
+ *           Modified for 7751 Solution Engine by
+ *           Ian da Silva and Jeremy Siegel, 2001.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/machvec.h>
+#include <mach/secureedge5410.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <cpu/timer.h>
+
+unsigned short secureedge5410_ioport;
+
+/*
+ * EraseConfig handling functions
+ */
+static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
+{
+       ctrl_delay();   /* dummy read */
+
+       printk("SnapGear: erase switch interrupt!\n");
+
+       return IRQ_HANDLED;
+}
+
+static int __init eraseconfig_init(void)
+{
+       unsigned int irq = evt2irq(0x240);
+
+       printk("SnapGear: EraseConfig init\n");
+
+       /* Setup "EraseConfig" switch on external IRQ 0 */
+       if (request_irq(irq, eraseconfig_interrupt, IRQF_DISABLED,
+                               "Erase Config", NULL))
+               printk("SnapGear: failed to register IRQ%d for Reset witch\n",
+                               irq);
+       else
+               printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
+                               irq);
+       return 0;
+}
+module_init(eraseconfig_init);
+
+/*
+ * Initialize IRQ setting
+ *
+ * IRL0 = erase switch
+ * IRL1 = eth0
+ * IRL2 = eth1
+ * IRL3 = crypto
+ */
+static void __init init_snapgear_IRQ(void)
+{
+       printk("Setup SnapGear IRQ/IPR ...\n");
+       /* enable individual interrupt mode for externals */
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_snapgear __initmv = {
+       .mv_name                = "SnapGear SecureEdge5410",
+       .mv_nr_irqs             = 72,
+       .mv_init_irq            = init_snapgear_IRQ,
+};
diff --git a/arch/sh/boards/mach-edosk7705/Makefile b/arch/sh/boards/mach-edosk7705/Makefile
deleted file mode 100644 (file)
index cd54acb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the EDOSK7705 specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-edosk7705/io.c b/arch/sh/boards/mach-edosk7705/io.c
deleted file mode 100644 (file)
index 5b9c57c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routines for Hitachi EDOSK7705 board.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <mach/edosk7705.h>
-#include <asm/addrspace.h>
-
-#define SMC_IOADDR     0xA2000000
-
-/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
-static unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
-{
-       /*
-        * SMC91C96 registers are 4 byte aligned rather than the
-        * usual 2 byte!
-        */
-       if (port >= 0x300 && port < 0x320)
-               return SMC_IOADDR + ((port - 0x300) * 2);
-
-       maybebadio(port);
-       return port;
-}
-
-/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
- * registers causes problems. So we bit-shift the value and read / write
- * in 2 byte chunks. Setting the low byte to 0 does not cause problems
- * now as odd byte writes are only made on the bit mask / interrupt
- * register. This may not be the case in future Mar-2003 SJD
- */
-unsigned char sh_edosk7705_inb(unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01)
-               return __raw_readw(port - 1) >> 8;
-
-       return __raw_readb(sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_outb(unsigned char value, unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01) {
-               __raw_writew(((unsigned short)value << 8), port - 1);
-               return;
-       }
-
-       __raw_writeb(value, sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-
-       while (count--)
-               *p++ = sh_edosk7705_inb(port);
-}
-
-void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char *)addr;
-
-       while (count--)
-               sh_edosk7705_outb(*p++, port);
-}
diff --git a/arch/sh/boards/mach-edosk7705/setup.c b/arch/sh/boards/mach-edosk7705/setup.c
deleted file mode 100644 (file)
index d59225e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SolutionEngine Support.
- *
- * Modified for edosk7705 development
- * board by S. Dunn, 2003.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/machvec.h>
-#include <mach/edosk7705.h>
-
-static void __init sh_edosk7705_init_irq(void)
-{
-       /* This is the Ethernet interrupt */
-       make_imask_irq(0x09);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_edosk7705 __initmv = {
-       .mv_name                = "EDOSK7705",
-       .mv_nr_irqs             = 80,
-
-       .mv_inb                 = sh_edosk7705_inb,
-       .mv_outb                = sh_edosk7705_outb,
-
-       .mv_insb                = sh_edosk7705_insb,
-       .mv_outsb               = sh_edosk7705_outsb,
-
-       .mv_init_irq            = sh_edosk7705_init_irq,
-};
index 2960c659020ee92e6c60c5c1d16d8d05ab73e267..acdafb0c6404a153cc482e46c0a17287f15ea26e 100644 (file)
@@ -54,7 +54,7 @@
 /*
  * map I/O ports to memory-mapped addresses
  */
-static unsigned long microdev_isa_port2addr(unsigned long offset)
+void __iomem *microdev_ioport_map(unsigned long offset, unsigned int len)
 {
        unsigned long result;
 
@@ -72,16 +72,6 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                         *      Configuration Registers
                         */
                result = IO_SUPERIO_PHYS + (offset << 1);
-#if 0
-       } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
-                  offset == KBD_STATUS_REG) {
-                       /*
-                        *      SMSC FDC37C93xAPM SuperIO chip
-                        *
-                        *      PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
-                        */
-               result = IO_SUPERIO_PHYS + (offset << 1);
-#endif
        } else if (((offset >= IO_IDE1_BASE) &&
                    (offset <  IO_IDE1_BASE + IO_IDE_EXTENT)) ||
                    (offset == IO_IDE1_MISC)) {
@@ -131,237 +121,5 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                result = PVR;
        }
 
-       return result;
-}
-
-#define PORT2ADDR(x) (microdev_isa_port2addr(x))
-
-static inline void delay(void)
-{
-#if defined(CONFIG_PCI)
-       /* System board present, just make a dummy SRAM access.  (CS0 will be
-          mapped to PCI memory, probably good to avoid it.) */
-       __raw_readw(0xa6800000);
-#else
-       /* CS0 will be mapped to flash, ROM etc so safe to access it. */
-       __raw_readw(0xa0000000);
-#endif
-}
-
-unsigned char microdev_inb(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inb(port);
-#endif
-       return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned short microdev_inw(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inw(port);
-#endif
-       return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int microdev_inl(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inl(port);
-#endif
-       return *(volatile unsigned int*)PORT2ADDR(port);
-}
-
-void microdev_outw(unsigned short b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outw(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void microdev_outb(unsigned char b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outb(b, port);
-               return;
-       }
-#endif
-
-       /*
-        *      There is a board feature with the current SH4-202 MicroDev in
-        *      that the 2 byte enables (nBE0 and nBE1) are tied together (and
-        *      to the Chip Select Line (Ethernet_CS)). Due to this connectivity,
-        *      it is not possible to safely perform 8-bit writes to the
-        *      Ethernet registers, as 16-bits will be consumed from the Data
-        *      lines (corrupting the other byte).  Hence, this function is
-        *      written to implement 16-bit read/modify/write for all byte-wide
-        *      accesses.
-        *
-        *      Note: there is no problem with byte READS (even or odd).
-        *
-        *                      Sean McGoogan - 16th June 2003.
-        */
-       if ((port >= IO_LAN91C111_BASE) &&
-           (port <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
-                       /*
-                        * Then are trying to perform a byte-write to the
-                        * LAN91C111.  This needs special care.
-                        */
-               if (port % 2 == 1) {    /* is the port odd ? */
-                       /* unset bit-0, i.e. make even */
-                       const unsigned long evenPort = port-1;
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving even byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(evenPort);
-                       word = (word & 0xffu) | (b << 8);
-                       microdev_outw(word, evenPort);
-               } else {
-                       /* else, we are trying to do an even byte write */
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving odd byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(port);
-                       word = (word & 0xff00u) | (b);
-                       microdev_outw(word, port);
-               }
-       } else {
-               *(volatile unsigned char*)PORT2ADDR(port) = b;
-       }
-}
-
-void microdev_outl(unsigned int b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outl(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned int*)PORT2ADDR(port) = b;
-}
-
-unsigned char microdev_inb_p(unsigned long port)
-{
-       unsigned char v = microdev_inb(port);
-       delay();
-       return v;
-}
-
-unsigned short microdev_inw_p(unsigned long port)
-{
-       unsigned short v = microdev_inw(port);
-       delay();
-       return v;
-}
-
-unsigned int microdev_inl_p(unsigned long port)
-{
-       unsigned int v = microdev_inl(port);
-       delay();
-       return v;
-}
-
-void microdev_outb_p(unsigned char b, unsigned long port)
-{
-       microdev_outb(b, port);
-       delay();
-}
-
-void microdev_outw_p(unsigned short b, unsigned long port)
-{
-       microdev_outw(b, port);
-       delay();
-}
-
-void microdev_outl_p(unsigned int b, unsigned long port)
-{
-       microdev_outl(b, port);
-       delay();
-}
-
-void microdev_insb(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insw(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insl(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       const unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       const unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       const unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
+       return (void __iomem *)result;
 }
index d1df2a4fb9b885913d38a90c49ff44f7bb0ace50..d8a747291e03ed82a829e20e4e779013881f1197 100644 (file)
@@ -195,27 +195,6 @@ device_initcall(microdev_devices_setup);
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
        .mv_name                = "SH4-202 MicroDev",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = microdev_inb,
-       .mv_inw                 = microdev_inw,
-       .mv_inl                 = microdev_inl,
-       .mv_outb                = microdev_outb,
-       .mv_outw                = microdev_outw,
-       .mv_outl                = microdev_outl,
-
-       .mv_inb_p               = microdev_inb_p,
-       .mv_inw_p               = microdev_inw_p,
-       .mv_inl_p               = microdev_inl_p,
-       .mv_outb_p              = microdev_outb_p,
-       .mv_outw_p              = microdev_outw_p,
-       .mv_outl_p              = microdev_outl_p,
-
-       .mv_insb                = microdev_insb,
-       .mv_insw                = microdev_insw,
-       .mv_insl                = microdev_insl,
-       .mv_outsb               = microdev_outsb,
-       .mv_outsw               = microdev_outsw,
-       .mv_outsl               = microdev_outsl,
-
+       .mv_ioport_map          = microdev_ioport_map,
        .mv_init_irq            = init_microdev_irq,
 };
index 63e7ed699f39b3c41d8578daa8b57ce31807c689..5c9eaa0535b935c5f90bde958b0ca79724e1dcc2 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7206 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7206/io.c b/arch/sh/boards/mach-se/7206/io.c
deleted file mode 100644 (file)
index adadc77..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
- *
- * linux/arch/sh/boards/se/7206/io.c
- *
- * Copyright (C) 2006 Yoshinori Sato
- *
- * I/O routine for Hitachi 7206 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7206.h>
-
-
-static inline void delay(void)
-{
-       __raw_readw(0x20000000);  /* P2 ROM Area */
-}
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000 && port < 0x2020)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x300 && port < 0x310)
-               return (volatile __u16 *) (PA_SMSC + (port - 0x300));
-
-       return (volatile __u16 *)port;
-}
-
-unsigned char se7206_inb(unsigned long port)
-{
-       return (*port2adr(port)) & 0xff;
-}
-
-unsigned char se7206_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       v = (*port2adr(port)) & 0xff;
-       delay();
-       return v;
-}
-
-unsigned short se7206_inw(unsigned long port)
-{
-       return *port2adr(port);
-}
-
-void se7206_outb(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-}
-
-void se7206_outb_p(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-       delay();
-}
-
-void se7206_outw(unsigned short value, unsigned long port)
-{
-       *port2adr(port) = value;
-}
-
-void se7206_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-       while (count--)
-               *p = *ap++;
-}
index 883b21eacaa686d00efbf822911dac79e6e220d5..d961949600fd462199f3d9706e86371e815e7b1b 100644 (file)
@@ -139,11 +139,13 @@ void __init init_se7206_IRQ(void)
        make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */
        make_se7206_irq(IRQ1_IRQ); /* ATA */
        make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */
-       __raw_writew(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */
+
+       __raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR); /* ICR1 */
 
        /* FPGA System register setup*/
        __raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */
        __raw_writew(0x0000,INTSTS1); /* Clear INTSTS1 */
+
        /* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */
        __raw_writew(0x0001,INTSEL);
 }
index 8f5c65d43d1d85a6e1db054cd5f065ee3aa72119..7f4871c71a01813dbd11882d9c55469d46359ce0 100644 (file)
@@ -86,20 +86,5 @@ __initcall(se7206_devices_setup);
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
        .mv_nr_irqs             = 256,
-       .mv_inb                 = se7206_inb,
-       .mv_inw                 = se7206_inw,
-       .mv_outb                = se7206_outb,
-       .mv_outw                = se7206_outw,
-
-       .mv_inb_p               = se7206_inb_p,
-       .mv_inw_p               = se7206_inw,
-       .mv_outb_p              = se7206_outb_p,
-       .mv_outw_p              = se7206_outw,
-
-       .mv_insb                = se7206_insb,
-       .mv_insw                = se7206_insw,
-       .mv_outsb               = se7206_outsb,
-       .mv_outsw               = se7206_outsw,
-
        .mv_init_irq            = init_se7206_IRQ,
 };
index 8e624b06d5ea67efc746ecab0716485d9a4742bc..43ea14feef51094d032c5b7eec98b35deff925f8 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 770x SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/770x/io.c b/arch/sh/boards/mach-se/770x/io.c
deleted file mode 100644 (file)
index 28833c8..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * I/O routine for Hitachi SolutionEngine.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se.h>
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port & 0xff000000)
-               return ( volatile __u16 *) port;
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x1000)
-               return (volatile __u16 *) (PA_83902 + (port << 1));
-       else
-               return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-}
-
-static inline int
-shifted_port(unsigned long port)
-{
-       /* For IDE registers, value is not shifted */
-       if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
-               return 0;
-       else
-               return 1;
-}
-
-unsigned char se_inb(unsigned long port)
-{
-       if (shifted_port(port))
-               return (*port2adr(port) >> 8);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char se_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       if (shifted_port(port))
-               v = (*port2adr(port) >> 8);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short se_inw(unsigned long port)
-{
-       if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int se_inl(unsigned long port)
-{
-       maybebadio(port);
-       return 0;
-}
-
-void se_outb(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-}
-
-void se_outb_p(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void se_outw(unsigned short value, unsigned long port)
-{
-       if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void se_outl(unsigned int value, unsigned long port)
-{
-       maybebadio(port);
-}
-
-void se_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *ap++ = *p >> 8;
-       } else {
-               while (count--)
-                       *ap++ = *p;
-       }
-}
-
-void se_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void se_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *p = *ap++ << 8;
-       } else {
-               while (count--)
-                       *p = *ap++;
-       }
-}
-
-void se_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 66d39d1b0901de5a9b6da4c7fb7978223b18b502..31330c65c0cec9aa1b78abb69e5bcb95c9c4cd80 100644 (file)
@@ -195,27 +195,5 @@ static struct sh_machine_vector mv_se __initmv = {
 #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
        .mv_nr_irqs             = 104,
 #endif
-
-       .mv_inb                 = se_inb,
-       .mv_inw                 = se_inw,
-       .mv_inl                 = se_inl,
-       .mv_outb                = se_outb,
-       .mv_outw                = se_outw,
-       .mv_outl                = se_outl,
-
-       .mv_inb_p               = se_inb_p,
-       .mv_inw_p               = se_inw,
-       .mv_inl_p               = se_inl,
-       .mv_outb_p              = se_outb_p,
-       .mv_outw_p              = se_outw,
-       .mv_outl_p              = se_outl,
-
-       .mv_insb                = se_insb,
-       .mv_insw                = se_insw,
-       .mv_insl                = se_insl,
-       .mv_outsb               = se_outsb,
-       .mv_outsw               = se_outsw,
-       .mv_outsl               = se_outsl,
-
        .mv_init_irq            = init_se_IRQ,
 };
index e6f4341bfe6eaa0467e60dfb56ae08688ea5a9c0..a338fd9d503944f84b4e84b5a3a3e7cccc4a5fcb 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7751 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7751/io.c b/arch/sh/boards/mach-se/7751/io.c
deleted file mode 100644 (file)
index 6e75bd4..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7751.h>
-#include <asm/addrspace.h>
-
-static inline volatile u16 *port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751se_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char sh7751se_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port)) & 0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751se_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751se_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751se_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751se_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751se_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 50572512e3e84a6db630114a57415153fd4e0506..9fbc51beb1812dfafd10a91cf7b6c02c1cabfdce 100644 (file)
@@ -56,23 +56,5 @@ __initcall(se7751_devices_setup);
 static struct sh_machine_vector mv_7751se __initmv = {
        .mv_name                = "7751 SolutionEngine",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751se_inb,
-       .mv_inw                 = sh7751se_inw,
-       .mv_inl                 = sh7751se_inl,
-       .mv_outb                = sh7751se_outb,
-       .mv_outw                = sh7751se_outw,
-       .mv_outl                = sh7751se_outl,
-
-       .mv_inb_p               = sh7751se_inb_p,
-       .mv_inw_p               = sh7751se_inw,
-       .mv_inl_p               = sh7751se_inl,
-       .mv_outb_p              = sh7751se_outb_p,
-       .mv_outw_p              = sh7751se_outw,
-       .mv_outl_p              = sh7751se_outl,
-
-       .mv_insl                = sh7751se_insl,
-       .mv_outsl               = sh7751se_outsl,
-
        .mv_init_irq            = init_7751se_IRQ,
 };
diff --git a/arch/sh/boards/mach-snapgear/Makefile b/arch/sh/boards/mach-snapgear/Makefile
deleted file mode 100644 (file)
index d2d2f4b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the SnapGear specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-snapgear/io.c b/arch/sh/boards/mach-snapgear/io.c
deleted file mode 100644 (file)
index 476650e..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-unsigned short secureedge5410_ioport;
-#endif
-
-static inline volatile __u16 *port2adr(unsigned int port)
-{
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char snapgear_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char snapgear_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-       if (PXSEG(port))
-               v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short snapgear_inw(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int snapgear_inl(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void snapgear_outb(unsigned char value, unsigned long port)
-{
-
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void snapgear_outb_p(unsigned char value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void snapgear_outw(unsigned short value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_outl(unsigned int value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-snapgear/setup.c b/arch/sh/boards/mach-snapgear/setup.c
deleted file mode 100644 (file)
index 331745d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * linux/arch/sh/boards/snapgear/setup.c
- *
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
- *
- * Based on files with the following comments:
- *
- *           Copyright (C) 2000  Kazumoto Kojima
- *
- *           Modified for 7751 Solution Engine by
- *           Ian da Silva and Jeremy Siegel, 2001.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <asm/machvec.h>
-#include <mach/snapgear.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <cpu/timer.h>
-
-/*
- * EraseConfig handling functions
- */
-
-static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
-{
-       (void)__raw_readb(0xb8000000);  /* dummy read */
-
-       printk("SnapGear: erase switch interrupt!\n");
-
-       return IRQ_HANDLED;
-}
-
-static int __init eraseconfig_init(void)
-{
-       printk("SnapGear: EraseConfig init\n");
-       /* Setup "EraseConfig" switch on external IRQ 0 */
-       if (request_irq(IRL0_IRQ, eraseconfig_interrupt, IRQF_DISABLED,
-                               "Erase Config", NULL))
-               printk("SnapGear: failed to register IRQ%d for Reset witch\n",
-                               IRL0_IRQ);
-       else
-               printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
-                               IRL0_IRQ);
-       return(0);
-}
-
-module_init(eraseconfig_init);
-
-/****************************************************************************/
-/*
- * Initialize IRQ setting
- *
- * IRL0 = erase switch
- * IRL1 = eth0
- * IRL2 = eth1
- * IRL3 = crypto
- */
-
-static void __init init_snapgear_IRQ(void)
-{
-       printk("Setup SnapGear IRQ/IPR ...\n");
-       /* enable individual interrupt mode for externals */
-       plat_irq_setup_pins(IRQ_MODE_IRQ);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_snapgear __initmv = {
-       .mv_name                = "SnapGear SecureEdge5410",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = snapgear_inb,
-       .mv_inw                 = snapgear_inw,
-       .mv_inl                 = snapgear_inl,
-       .mv_outb                = snapgear_outb,
-       .mv_outw                = snapgear_outw,
-       .mv_outl                = snapgear_outl,
-
-       .mv_inb_p               = snapgear_inb_p,
-       .mv_inw_p               = snapgear_inw,
-       .mv_inl_p               = snapgear_inl,
-       .mv_outb_p              = snapgear_outb_p,
-       .mv_outw_p              = snapgear_outw,
-       .mv_outl_p              = snapgear_outl,
-
-       .mv_init_irq            = init_snapgear_IRQ,
-};
diff --git a/arch/sh/boards/mach-systemh/Makefile b/arch/sh/boards/mach-systemh/Makefile
deleted file mode 100644 (file)
index 2cc6a23..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for the SystemH specific parts of the kernel
-#
-
-obj-y   := setup.o irq.o io.o
-
-# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
-# importantly, with the generic sh7751_pcic_init() code. For now, we'll
-# just abuse the hell out of kbuild, because we can..
-
-obj-$(CONFIG_PCI) += pci.o
-pci-y := ../../se/7751/pci.o
-
diff --git a/arch/sh/boards/mach-systemh/io.c b/arch/sh/boards/mach-systemh/io.c
deleted file mode 100644 (file)
index 15577ff..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 Systemh.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <mach/systemh7751.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
-                                                of smc lan chip*/
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751systemh_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               return *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char sh7751systemh_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               v = *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751systemh_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751systemh_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751systemh_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751systemh_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751systemh_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned short *)ETHER_IOMAP(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-       while (count--) *p++ = sh7751systemh_inb(port);
-}
-
-void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned short *p = addr;
-       while (count--) *p++ = sh7751systemh_inw(port);
-}
-
-void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char*)addr;
-       while (count--) sh7751systemh_outb(*p++, port);
-}
-
-void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned short *p = (unsigned short*)addr;
-       while (count--) sh7751systemh_outw(*p++, port);
-}
-
-void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c
deleted file mode 100644 (file)
index e5ee13a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/irq.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by
- * Jonathan Short.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <mach/systemh7751.h>
-#include <asm/smc37c93x.h>
-
-/* address of external interrupt mask register
- * address must be set prior to use these (maybe in init_XXX_irq())
- * XXX : is it better to use .config than specifying it in code? */
-static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
-static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
-
-static void disable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Clear the "irq"th bit in the mask and set it in the request */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val &= ~mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-
-       val = __raw_readl((unsigned long)systemh_irq_request_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_request_register);
-}
-
-static void enable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Set "irq"th bit in the mask register */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-}
-
-static struct irq_chip systemh_irq_type = {
-       .name           = "SystemH Register",
-       .irq_unmask     = enable_systemh_irq,
-       .irq_mask       = disable_systemh_irq,
-};
-
-void make_systemh_irq(unsigned int irq)
-{
-       disable_irq_nosync(irq);
-       set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
-       disable_systemh_irq(irq_get_irq_data(irq));
-}
diff --git a/arch/sh/boards/mach-systemh/setup.c b/arch/sh/boards/mach-systemh/setup.c
deleted file mode 100644 (file)
index 219fd80..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- * Copyright (C) 2003  Paul Mundt
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by Jonathan Short.
- *
- * Rewritten for 2.6 by Paul Mundt.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <asm/machvec.h>
-#include <mach/systemh7751.h>
-
-extern void make_systemh_irq(unsigned int irq);
-
-/*
- * Initialize IRQ setting
- */
-static void __init sh7751systemh_init_irq(void)
-{
-       make_systemh_irq(0xb);  /* Ethernet interrupt */
-}
-
-static struct sh_machine_vector mv_7751systemh __initmv = {
-       .mv_name                = "7751 SystemH",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751systemh_inb,
-       .mv_inw                 = sh7751systemh_inw,
-       .mv_inl                 = sh7751systemh_inl,
-       .mv_outb                = sh7751systemh_outb,
-       .mv_outw                = sh7751systemh_outw,
-       .mv_outl                = sh7751systemh_outl,
-
-       .mv_inb_p               = sh7751systemh_inb_p,
-       .mv_inw_p               = sh7751systemh_inw,
-       .mv_inl_p               = sh7751systemh_inl,
-       .mv_outb_p              = sh7751systemh_outb_p,
-       .mv_outw_p              = sh7751systemh_outw,
-       .mv_outl_p              = sh7751systemh_outl,
-
-       .mv_insb                = sh7751systemh_insb,
-       .mv_insw                = sh7751systemh_insw,
-       .mv_insl                = sh7751systemh_insl,
-       .mv_outsb               = sh7751systemh_outsb,
-       .mv_outsw               = sh7751systemh_outsw,
-       .mv_outsl               = sh7751systemh_outsl,
-
-       .mv_init_irq            = sh7751systemh_init_irq,
-};
diff --git a/arch/sh/configs/secureedge5410_defconfig b/arch/sh/configs/secureedge5410_defconfig
new file mode 100644 (file)
index 0000000..7eae4e5
--- /dev/null
@@ -0,0 +1,63 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7751R=y
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SECUREEDGE5410=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK_RO=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_CFI_I2 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1302=y
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
deleted file mode 100644 (file)
index 7eae4e5..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_SECUREEDGE5410=y
-CONFIG_SH_DMA=y
-CONFIG_SH_DMA_API=y
-CONFIG_PCI=y
-CONFIG_NET=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
-# CONFIG_MTD_CFI_I2 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_8139CP=y
-CONFIG_8139TOO=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_DS1302=y
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
deleted file mode 100644 (file)
index b58dfc5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_7751_SYSTEMH=y
-CONFIG_PREEMPT=y
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-# CONFIG_INPUT is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_VT is not set
-CONFIG_HW_RANDOM=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
index 446b3831c2149380265476f47674d4ad4ea72b1e..3d1ae2bfaa6fd7056701e8ddc41538d94a4a1a71 100644 (file)
 /*
  * These will never work in 32-bit, don't even bother.
  */
-#define P1SEGADDR(a)   __futile_remapping_attempt
-#define P2SEGADDR(a)   __futile_remapping_attempt
-#define P3SEGADDR(a)   __futile_remapping_attempt
-#define P4SEGADDR(a)   __futile_remapping_attempt
+#define P1SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P2SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P3SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P4SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
 #endif
 #endif /* P1SEG */
 
index a15f1058bbf439b8895f1b3d277f7e1bcf05c6aa..083ea068e819e80a389d5610bc9e19243d4ed950 100644 (file)
@@ -66,7 +66,6 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
 #define PHYS_ADDR_MASK29               0x1fffffff
 #define PHYS_ADDR_MASK32               0xffffffff
 
-#ifdef CONFIG_PMB
 static inline unsigned long phys_addr_mask(void)
 {
        /* Is the MMU in 29bit mode? */
@@ -75,17 +74,6 @@ static inline unsigned long phys_addr_mask(void)
 
        return PHYS_ADDR_MASK32;
 }
-#elif defined(CONFIG_32BIT)
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK32;
-}
-#else
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK29;
-}
-#endif
 
 #define PTE_PHYS_MASK          (phys_addr_mask() & PAGE_MASK)
 #define PTE_FLAGS_MASK         (~(PTE_PHYS_MASK) << PAGE_SHIFT)
index 1f1af5afff0374537f989911d4e98f51078a9c1e..10c8b1823a181ef6abd8f07766c801f7c2c6d3f1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 #include <asm/types.h>
+#include <asm/uncached.h>
 
 #define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
 
@@ -137,9 +138,6 @@ extern unsigned int instruction_size(unsigned int insn);
 #define instruction_size(insn) (4)
 #endif
 
-extern unsigned long cached_to_uncached;
-extern unsigned long uncached_size;
-
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
index c941b273940581bc4221458a8cabf639829e1500..a4ad1cd9bc4d02740bb8afcb1936a932b2ed3f35 100644 (file)
@@ -145,42 +145,6 @@ do {                                                               \
                __restore_dsp(prev);                            \
 } while (0)
 
-/*
- * Jump to uncached area.
- * When handling TLB or caches, we need to do it from an uncached area.
- */
-#define jump_to_uncached()                     \
-do {                                           \
-       unsigned long __dummy;                  \
-                                               \
-       __asm__ __volatile__(                   \
-               "mova   1f, %0\n\t"             \
-               "add    %1, %0\n\t"             \
-               "jmp    @%0\n\t"                \
-               " nop\n\t"                      \
-               ".balign 4\n"                   \
-               "1:"                            \
-               : "=&z" (__dummy)               \
-               : "r" (cached_to_uncached));    \
-} while (0)
-
-/*
- * Back to cached area.
- */
-#define back_to_cached()                               \
-do {                                                   \
-       unsigned long __dummy;                          \
-       ctrl_barrier();                                 \
-       __asm__ __volatile__(                           \
-               "mov.l  1f, %0\n\t"                     \
-               "jmp    @%0\n\t"                        \
-               " nop\n\t"                              \
-               ".balign 4\n"                           \
-               "1:     .long 2f\n"                     \
-               "2:"                                    \
-               : "=&r" (__dummy));                     \
-} while (0)
-
 #ifdef CONFIG_CPU_HAS_SR_RB
 #define lookup_exception_vector()      \
 ({                                     \
index 36338646dfc81832227e78d39ccf6cdc71df4963..8593bc8d1a4e74af89ace4cb2e767b9fd0567ea6 100644 (file)
@@ -34,9 +34,6 @@ do {                                                          \
                              &next->thread);                   \
 } while (0)
 
-#define jump_to_uncached()     do { } while (0)
-#define back_to_cached()       do { } while (0)
-
 #define __icbi(addr)   __asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
 #define __ocbp(addr)   __asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
 #define __ocbi(addr)   __asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
index e3419f96626ad49719130f120bcb71bcbdb40c42..6f8816b79cf152091b1fc08e6cd4dc5d4390bfe2 100644 (file)
@@ -4,15 +4,55 @@
 #include <linux/bug.h>
 
 #ifdef CONFIG_UNCACHED_MAPPING
+extern unsigned long cached_to_uncached;
+extern unsigned long uncached_size;
 extern unsigned long uncached_start, uncached_end;
 
 extern int virt_addr_uncached(unsigned long kaddr);
 extern void uncached_init(void);
 extern void uncached_resize(unsigned long size);
+
+/*
+ * Jump to uncached area.
+ * When handling TLB or caches, we need to do it from an uncached area.
+ */
+#define jump_to_uncached()                     \
+do {                                           \
+       unsigned long __dummy;                  \
+                                               \
+       __asm__ __volatile__(                   \
+               "mova   1f, %0\n\t"             \
+               "add    %1, %0\n\t"             \
+               "jmp    @%0\n\t"                \
+               " nop\n\t"                      \
+               ".balign 4\n"                   \
+               "1:"                            \
+               : "=&z" (__dummy)               \
+               : "r" (cached_to_uncached));    \
+} while (0)
+
+/*
+ * Back to cached area.
+ */
+#define back_to_cached()                               \
+do {                                                   \
+       unsigned long __dummy;                          \
+       ctrl_barrier();                                 \
+       __asm__ __volatile__(                           \
+               "mov.l  1f, %0\n\t"                     \
+               "jmp    @%0\n\t"                        \
+               " nop\n\t"                              \
+               ".balign 4\n"                           \
+               "1:     .long 2f\n"                     \
+               "2:"                                    \
+               : "=&r" (__dummy));                     \
+} while (0)
 #else
 #define virt_addr_uncached(kaddr)      (0)
 #define uncached_init()                        do { } while (0)
 #define uncached_resize(size)          BUG()
+#define jump_to_uncached()             do { } while (0)
+#define back_to_cached()               do { } while (0)
 #endif
 
 #endif /* __ASM_SH_UNCACHED_H */
diff --git a/arch/sh/include/mach-common/mach/edosk7705.h b/arch/sh/include/mach-common/mach/edosk7705.h
deleted file mode 100644 (file)
index efc43b3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __ASM_SH_EDOSK7705_H
-#define __ASM_SH_EDOSK7705_H
-
-#define __IO_PREFIX sh_edosk7705
-#include <asm/io_generic.h>
-
-#endif /* __ASM_SH_EDOSK7705_H */
index 1aed15856e11ff5bae72b2522f94f816084e0dee..dcb05fa8c164d9c9044df5ce85665953328f7e21 100644 (file)
@@ -68,13 +68,4 @@ extern void microdev_print_fpga_intc_status(void);
 #define __IO_PREFIX microdev
 #include <asm/io_generic.h>
 
-#if defined(CONFIG_PCI)
-unsigned char  microdev_pci_inb(unsigned long port);
-unsigned short microdev_pci_inw(unsigned long port);
-unsigned long  microdev_pci_inl(unsigned long port);
-void           microdev_pci_outb(unsigned char  data, unsigned long port);
-void           microdev_pci_outw(unsigned short data, unsigned long port);
-void           microdev_pci_outl(unsigned long  data, unsigned long port);
-#endif
-
 #endif /* __ASM_SH_MICRODEV_H */
diff --git a/arch/sh/include/mach-common/mach/secureedge5410.h b/arch/sh/include/mach-common/mach/secureedge5410.h
new file mode 100644 (file)
index 0000000..3653b9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * include/asm-sh/snapgear.h
+ *
+ * Modified version of io_se.h for the snapgear-specific functions.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a SnapGear
+ */
+
+#ifndef _ASM_SH_IO_SNAPGEAR_H
+#define _ASM_SH_IO_SNAPGEAR_H
+
+#define __IO_PREFIX    snapgear
+#include <asm/io_generic.h>
+
+/*
+ * We need to remember what was written to the ioport as some bits
+ * are shared with other functions and you cannot read back what was
+ * written :-|
+ *
+ * Bit        Read                   Write
+ * -----------------------------------------------
+ * D0         DCD on ttySC1          power
+ * D1         Reset Switch           heatbeat
+ * D2         ttySC0 CTS (7100)      LAN
+ * D3         -                      WAN
+ * D4         ttySC0 DCD (7100)      CONSOLE
+ * D5         -                      ONLINE
+ * D6         -                      VPN
+ * D7         -                      DTR on ttySC1
+ * D8         -                      ttySC0 RTS (7100)
+ * D9         -                      ttySC0 DTR (7100)
+ * D10        -                      RTC SCLK
+ * D11        RTC DATA               RTC DATA
+ * D12        -                      RTS RESET
+ */
+
+#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
+extern unsigned short secureedge5410_ioport;
+
+#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
+        (secureedge5410_ioport = \
+                       ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
+#define SECUREEDGE_READ_IOPORT() \
+        ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
+
+#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/snapgear.h b/arch/sh/include/mach-common/mach/snapgear.h
deleted file mode 100644 (file)
index 042d95f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * include/asm-sh/snapgear.h
- *
- * Modified version of io_se.h for the snapgear-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for a SnapGear
- */
-
-#ifndef _ASM_SH_IO_SNAPGEAR_H
-#define _ASM_SH_IO_SNAPGEAR_H
-
-#if defined(CONFIG_CPU_SH4)
-/*
- * The external interrupt lines, these take up ints 0 - 15 inclusive
- * depending on the priority for the interrupt.  In fact the priority
- * is the interrupt :-)
- */
-
-#define IRL0_IRQ       2
-#define IRL0_PRIORITY  13
-
-#define IRL1_IRQ       5
-#define IRL1_PRIORITY  10
-
-#define IRL2_IRQ       8
-#define IRL2_PRIORITY  7
-
-#define IRL3_IRQ       11
-#define IRL3_PRIORITY  4
-#endif
-
-#define __IO_PREFIX    snapgear
-#include <asm/io_generic.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-/*
- * We need to remember what was written to the ioport as some bits
- * are shared with other functions and you cannot read back what was
- * written :-|
- *
- * Bit        Read                   Write
- * -----------------------------------------------
- * D0         DCD on ttySC1          power
- * D1         Reset Switch           heatbeat
- * D2         ttySC0 CTS (7100)      LAN
- * D3         -                      WAN
- * D4         ttySC0 DCD (7100)      CONSOLE
- * D5         -                      ONLINE
- * D6         -                      VPN
- * D7         -                      DTR on ttySC1
- * D8         -                      ttySC0 RTS (7100)
- * D9         -                      ttySC0 DTR (7100)
- * D10        -                      RTC SCLK
- * D11        RTC DATA               RTC DATA
- * D12        -                      RTS RESET
- */
-
-#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
-extern unsigned short secureedge5410_ioport;
-
-#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
-        (secureedge5410_ioport = \
-                       ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
-#define SECUREEDGE_READ_IOPORT() \
-        ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
-#endif
-
-#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/systemh7751.h b/arch/sh/include/mach-common/mach/systemh7751.h
deleted file mode 100644 (file)
index 4161122..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
-#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
-
-/*
- * linux/include/asm-sh/systemh/7751systemh.h
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH support
-
- * Modified for 7751 SystemH by
- * Jonathan Short, 2002.
- */
-
-/* Box specific addresses.  */
-
-#define PA_ROM         0x00000000      /* EPROM */
-#define PA_ROM_SIZE    0x00400000      /* EPROM size 4M byte */
-#define PA_FROM                0x01000000      /* EPROM */
-#define PA_FROM_SIZE   0x00400000      /* EPROM size 4M byte */
-#define PA_EXT1                0x04000000
-#define PA_EXT1_SIZE   0x04000000
-#define PA_EXT2                0x08000000
-#define PA_EXT2_SIZE   0x04000000
-#define PA_SDRAM       0x0c000000
-#define PA_SDRAM_SIZE  0x04000000
-
-#define PA_EXT4                0x12000000
-#define PA_EXT4_SIZE   0x02000000
-#define PA_EXT5                0x14000000
-#define PA_EXT5_SIZE   0x04000000
-#define PA_PCIC                0x18000000      /* MR-SHPC-01 PCMCIA */
-
-#define PA_DIPSW0      0xb9000000      /* Dip switch 5,6 */
-#define PA_DIPSW1      0xb9000002      /* Dip switch 7,8 */
-#define PA_LED         0xba000000      /* LED */
-#define        PA_BCR          0xbb000000      /* FPGA on the MS7751SE01 */
-
-#define PA_MRSHPC      0xb83fffe0      /* MR-SHPC-01 PCMCIA controller */
-#define PA_MRSHPC_MW1  0xb8400000      /* MR-SHPC-01 memory window base */
-#define PA_MRSHPC_MW2  0xb8500000      /* MR-SHPC-01 attribute window base */
-#define PA_MRSHPC_IO   0xb8600000      /* MR-SHPC-01 I/O window base */
-#define MRSHPC_MODE     (PA_MRSHPC + 4)
-#define MRSHPC_OPTION   (PA_MRSHPC + 6)
-#define MRSHPC_CSR      (PA_MRSHPC + 8)
-#define MRSHPC_ISR      (PA_MRSHPC + 10)
-#define MRSHPC_ICR      (PA_MRSHPC + 12)
-#define MRSHPC_CPWCR    (PA_MRSHPC + 14)
-#define MRSHPC_MW0CR1   (PA_MRSHPC + 16)
-#define MRSHPC_MW1CR1   (PA_MRSHPC + 18)
-#define MRSHPC_IOWCR1   (PA_MRSHPC + 20)
-#define MRSHPC_MW0CR2   (PA_MRSHPC + 22)
-#define MRSHPC_MW1CR2   (PA_MRSHPC + 24)
-#define MRSHPC_IOWCR2   (PA_MRSHPC + 26)
-#define MRSHPC_CDCR     (PA_MRSHPC + 28)
-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
-
-#define BCR_ILCRA      (PA_BCR + 0)
-#define BCR_ILCRB      (PA_BCR + 2)
-#define BCR_ILCRC      (PA_BCR + 4)
-#define BCR_ILCRD      (PA_BCR + 6)
-#define BCR_ILCRE      (PA_BCR + 8)
-#define BCR_ILCRF      (PA_BCR + 10)
-#define BCR_ILCRG      (PA_BCR + 12)
-
-#define IRQ_79C973     13
-
-#define __IO_PREFIX    sh7751systemh
-#include <asm/io_generic.h>
-
-#endif  /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
index 2d9700c6b53a07426bdc6253e55a62effed962c0..0fe2e9329cb25f699acd433dd4f2d9b4b945f00b 100644 (file)
@@ -48,7 +48,7 @@ static struct clk r_clk = {
  * Default rate for the root input clock, reset this with clk_set_rate()
  * from the platform code.
  */
-struct clk extal_clk = {
+static struct clk extal_clk = {
        .rate           = 33333333,
 };
 
@@ -111,7 +111,7 @@ static struct clk div3_clk = {
        .parent         = &pll_clk,
 };
 
-struct clk *main_clks[] = {
+static struct clk *main_clks[] = {
        &r_clk,
        &extal_clk,
        &fll_clk,
@@ -156,7 +156,7 @@ struct clk div4_clks[DIV4_NR] = {
 
 enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR };
 
-struct clk div6_clks[DIV6_NR] = {
+static struct clk div6_clks[DIV6_NR] = {
        [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
        [DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0),
        [DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0),
index 09370392aff15d791d612ac57bcdf0c6031d8443..c3e61b36649380f5db818c5f6edb05bfc897de1c 100644 (file)
@@ -79,7 +79,7 @@ config 29BIT
 
 config 32BIT
        bool
-       default y if CPU_SH5
+       default y if CPU_SH5 || !MMU
 
 config PMB
        bool "Support 32-bit physical addressing through PMB"
index 0387932869904a042472cca19b65141b5b8bdc9f..40733a9524021d42d42ddc5a8d7e08ef77a1c155 100644 (file)
@@ -79,21 +79,20 @@ void dma_generic_free_coherent(struct device *dev, size_t size,
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                    enum dma_data_direction direction)
 {
-#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
-       void *p1addr = vaddr;
-#else
-       void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
-#endif
+       void *addr;
+
+       addr = __in_29bit_mode() ?
+              (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
 
        switch (direction) {
        case DMA_FROM_DEVICE:           /* invalidate only */
-               __flush_invalidate_region(p1addr, size);
+               __flush_invalidate_region(addr, size);
                break;
        case DMA_TO_DEVICE:             /* writeback only */
-               __flush_wback_region(p1addr, size);
+               __flush_wback_region(addr, size);
                break;
        case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
-               __flush_purge_region(p1addr, size);
+               __flush_purge_region(addr, size);
                break;
        default:
                BUG();
index 8a4eca551fc0a08542085faddeac7af373ad091b..a7767da815e91453c5b5526a05f4c72405e4afba 100644 (file)
@@ -28,7 +28,7 @@ EXPORT_SYMBOL(virt_addr_uncached);
 
 void __init uncached_init(void)
 {
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || !defined(CONFIG_MMU)
        uncached_start = P2SEG;
 #else
        uncached_start = memory_end;
index 9f56eb978024ef2b6e93497a6580d00dbc7f62eb..0e68465e7b50920ffcaa8a832402fdfc3670226c 100644 (file)
@@ -26,7 +26,6 @@ HD64461                       HD64461
 7724SE                 SH_7724_SOLUTION_ENGINE
 7751SE                 SH_7751_SOLUTION_ENGINE
 7780SE                 SH_7780_SOLUTION_ENGINE
-7751SYSTEMH            SH_7751_SYSTEMH
 HP6XX                  SH_HP6XX
 DREAMCAST              SH_DREAMCAST
 SNAPGEAR               SH_SECUREEDGE5410
index 7524689b03d24465f78500f87e804803509b3367..16582d85368af84b891fded4406d7f0088bf3056 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/sched.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
index e6375a750d9a641f4b253fdf2894fa989973b347..6db18c6927fbee68a20125e1eb31e486798eeac0 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
index 675c9e11ada5541085e2fd6e6129272c05713df4..42b282fa6112933681082c12bb95ef04fccc4b41 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mman.h>
 #include <linux/utsname.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ipc.h>
 
 #include <asm/uaccess.h>
index 12b9f352595f44e26c3f5730d3a84e8557d8cca8..4491f4cb26953c1582e0344311b62fe82b956900 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/perf_event.h>
 
 enum direction {
index b351770cbdd6aded05ca53554b30c8716a24a4ce..3107381e576d6f78431d0ccde6c73114ae387944 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
index e0f7ee186721cf554dc142efdfc58350eaf6a7df..b2a6c5de79abf00ddad0354fca8b694937282131 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/threads.h>
-#include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/homecache.h>
 
index 1480106d1c05c2572177058611ee655db569c41c..3d0f202462609e1401b4737b905cb324332d8b4c 100644 (file)
 #define _ASM_TILE_KMAP_TYPES_H
 
 /*
- * In TILE Linux each set of four of these uses another 16MB chunk of
- * address space, given 64 tiles and 64KB pages, so we only enable
- * ones that are required by the kernel configuration.
+ * In 32-bit TILE Linux we have to balance the desire to have a lot of
+ * nested atomic mappings with the fact that large page sizes and many
+ * processors chew up address space quickly.  In a typical
+ * 64-processor, 64KB-page layout build, making KM_TYPE_NR one larger
+ * adds 4MB of required address-space.  For now we leave KM_TYPE_NR
+ * set to depth 8.
  */
 enum km_type {
+       KM_TYPE_NR = 8
+};
+
+/*
+ * We provide dummy definitions of all the stray values that used to be
+ * required for kmap_atomic() and no longer are.
+ */
+enum {
        KM_BOUNCE_READ,
        KM_SKB_SUNRPC_DATA,
        KM_SKB_DATA_SOFTIRQ,
        KM_USER0,
        KM_USER1,
        KM_BIO_SRC_IRQ,
+       KM_BIO_DST_IRQ,
+       KM_PTE0,
+       KM_PTE1,
        KM_IRQ0,
        KM_IRQ1,
        KM_SOFTIRQ0,
        KM_SOFTIRQ1,
-       KM_MEMCPY0,
-       KM_MEMCPY1,
-#if defined(CONFIG_HIGHPTE)
-       KM_PTE0,
-       KM_PTE1,
-#endif
-       KM_TYPE_NR
+       KM_SYNC_ICACHE,
+       KM_SYNC_DCACHE,
+       KM_UML_USERCOPY,
+       KM_IRQ_PTE,
+       KM_NMI,
+       KM_NMI_PTE,
+       KM_KDB
 };
 
 #endif /* _ASM_TILE_KMAP_TYPES_H */
index dc4ccdd855bca293070ea8bff94a699821d5e01b..a6604e9485da2a188265d618eaaa8a75ec8a4828 100644 (file)
@@ -344,10 +344,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 #if defined(CONFIG_HIGHPTE)
-extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
-#define pte_offset_map(dir, address) \
-       _pte_offset_map(dir, address, KM_PTE0)
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+extern pte_t *pte_offset_map(pmd_t *, unsigned long address);
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte) do { } while (0)
index 3dc90fa92c704d8fb07d66b034daadd44ee6376b..b16e5db8f0e7225f9e8789a747f9295d341d947d 100644 (file)
@@ -1 +1,4 @@
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_STAT64     /* Used for compat_sys_stat64() etc. */
+#endif
 #include <asm-generic/stat.h>
index f2e3ff485333224f022344fad78f7c96b19d5243..b35c2db71199ae3d70fc2b1e29687dc350514a77 100644 (file)
@@ -41,6 +41,7 @@ __SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr)
 #ifdef CONFIG_COMPAT
 #define __ARCH_WANT_SYS_LLSEEK
 #endif
+#define __ARCH_WANT_SYS_NEWFSTATAT
 #endif
 
 #endif /* _ASM_TILE_UNISTD_H */
index 77739cdd9462dacf2a9188a0a0418c014e6379f9..dbc213adf5e1dac8557e38647266c730ecb7e6eb 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/kdev_t.h>
 #include <linux/fs.h>
 #include <linux/fcntl.h>
-#include <linux/smp_lock.h>
 #include <linux/uaccess.h>
 #include <linux/signal.h>
 #include <asm/syscalls.h>
@@ -148,11 +147,11 @@ long tile_compat_sys_msgrcv(int msqid,
 #define compat_sys_readahead sys32_readahead
 #define compat_sys_sync_file_range compat_sys_sync_file_range2
 
-/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
-#define compat_sys_stat64 sys_newstat
-#define compat_sys_lstat64 sys_newlstat
-#define compat_sys_fstat64 sys_newfstat
-#define compat_sys_fstatat64 sys_newfstatat
+/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
+#define compat_sys_stat64 sys_stat64
+#define compat_sys_lstat64 sys_lstat64
+#define compat_sys_fstat64 sys_fstat64
+#define compat_sys_fstatat64 sys_fstatat64
 
 /* The native sys_ptrace dynamically handles compat binaries. */
 #define compat_sys_ptrace sys_ptrace
index fb64b99959d42dd796c6d16c4b471cc8d9769a50..543d6a33aa26f6c02f7f41f59fcdceea1729bcd8 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
index 2c54fd43a8a0132533927ed5b5e373940f10ce18..493a0e66d916c618f867034db5647f72acd61999 100644 (file)
@@ -54,7 +54,7 @@ void early_printk(const char *fmt, ...)
 void early_panic(const char *fmt, ...)
 {
        va_list ap;
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        va_start(ap, fmt);
        early_printk("Kernel panic - not syncing: ");
        early_vprintk(fmt, ap);
index 1e54a7843410e57d021dbac9921acf4f39e2f481..e910530436e64a4079ba65e22bdca13e6ad01bfa 100644 (file)
@@ -151,12 +151,12 @@ enum direction_protect {
 
 static void enable_firewall_interrupts(void)
 {
-       raw_local_irq_unmask_now(INT_UDN_FIREWALL);
+       arch_local_irq_unmask_now(INT_UDN_FIREWALL);
 }
 
 static void disable_firewall_interrupts(void)
 {
-       raw_local_irq_mask_now(INT_UDN_FIREWALL);
+       arch_local_irq_mask_now(INT_UDN_FIREWALL);
 }
 
 /* Set up hardwall on this cpu based on the passed hardwall_info. */
@@ -768,13 +768,13 @@ static int hardwall_release(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations dev_hardwall_fops = {
+       .open           = nonseekable_open,
        .unlocked_ioctl = hardwall_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = hardwall_compat_ioctl,
 #endif
        .flush          = hardwall_flush,
        .release        = hardwall_release,
-       .llseek         = noop_llseek,
 };
 
 static struct cdev hardwall_dev;
index e63917687e998907824a62b1783ffef599418818..128805ef8f2c83c1a8b61cf03c5711e5fbb97ff1 100644 (file)
@@ -26,7 +26,7 @@
 #define IS_HW_CLEARED 1
 
 /*
- * The set of interrupts we enable for raw_local_irq_enable().
+ * The set of interrupts we enable for arch_local_irq_enable().
  * This is initialized to have just a single interrupt that the kernel
  * doesn't actually use as a sentinel.  During kernel init,
  * interrupts are added as the kernel gets prepared to support them.
@@ -225,7 +225,7 @@ void __cpuinit setup_irq_regs(void)
        /* Enable interrupt delivery. */
        unmask_irqs(~0UL);
 #if CHIP_HAS_IPI()
-       raw_local_irq_unmask(INT_IPI_K);
+       arch_local_irq_unmask(INT_IPI_K);
 #endif
 }
 
index ba7a265d61796a09168b6c35ed74af23f9fdb256..0d8b9e933487c2847824efc1637364cba8ec84d8 100644 (file)
@@ -182,13 +182,13 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                if ((entry & IND_SOURCE)) {
                        void *va =
-                               kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
+                               kmap_atomic_pfn(entry >> PAGE_SHIFT);
                        r = kexec_bn2cl(va);
                        if (r) {
                                command_line = r;
                                break;
                        }
-                       kunmap_atomic(va, KM_USER0);
+                       kunmap_atomic(va);
                }
        }
 
@@ -198,7 +198,7 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                hverr = hv_set_command_line(
                        (HV_VirtAddr) command_line, strlen(command_line));
-               kunmap_atomic(command_line, KM_USER0);
+               kunmap_atomic(command_line);
        } else {
                pr_info("%s: no command line found; making empty\n",
                       __func__);
index 997e3933f72679718583dae5a82c72c4d2f9fbdb..0858ee6b520f6acf4c23b3a27c8491267919b943 100644 (file)
@@ -34,7 +34,7 @@ void __cpuinit init_messaging(void)
                panic("hv_register_message_state: error %d", rc);
 
        /* Make sure downcall interrupts will be enabled. */
-       raw_local_irq_unmask(INT_INTCTRL_K);
+       arch_local_irq_unmask(INT_INTCTRL_K);
 }
 
 void hv_message_intr(struct pt_regs *regs, int intnum)
index 9cd29884c09f2bfec1cddbacb67579bbd1e821c6..e92e40527d6dcb9855625cafa13a83f08f56df9c 100644 (file)
@@ -50,10 +50,10 @@ long arch_ptrace(struct task_struct *child, long request,
 {
        unsigned long __user *datap = (long __user __force *)data;
        unsigned long tmp;
-       int i;
        long ret = -EIO;
-       unsigned long *childregs;
        char *childreg;
+       struct pt_regs copyregs;
+       int ex1_offset;
 
        switch (request) {
 
@@ -80,6 +80,16 @@ long arch_ptrace(struct task_struct *child, long request,
                if (addr >= PTREGS_SIZE)
                        break;
                childreg = (char *)task_pt_regs(child) + addr;
+
+               /* Guard against overwrites of the privilege level. */
+               ex1_offset = PTREGS_OFFSET_EX1;
+#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
+               if (is_compat_task())   /* point at low word */
+                       ex1_offset += sizeof(compat_long_t);
+#endif
+               if (addr == ex1_offset)
+                       data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
+
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -96,26 +106,19 @@ long arch_ptrace(struct task_struct *child, long request,
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
-               if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __put_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_to_user(datap, task_pt_regs(child),
+                                sizeof(struct pt_regs)) == 0) {
+                       ret = 0;
                }
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
-               if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __get_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_from_user(&copyregs, datap,
+                                  sizeof(struct pt_regs)) == 0) {
+                       copyregs.ex1 =
+                               PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
+                       *task_pt_regs(child) = copyregs;
+                       ret = 0;
                }
                break;
 
index acd86d20beba7ab75aed0f484c3b980a836af282..baa3d905fee21c9fc2ef403449f7e4d671ad7e1e 100644 (file)
@@ -27,7 +27,7 @@
 void machine_halt(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_halt();
 }
@@ -35,14 +35,14 @@ void machine_halt(void)
 void machine_power_off(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_power_off();
 }
 
 void machine_restart(char *cmd)
 {
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
 }
index ae51cad12da0d6b445666d1796925816b8e7e285..fb0b3cbeae149081a5b3011f0230fbd48f4d56dd 100644 (file)
@@ -868,14 +868,14 @@ void __cpuinit setup_cpu(int boot)
 
        /* Allow asynchronous TLB interrupts. */
 #if CHIP_HAS_TILE_DMA()
-       raw_local_irq_unmask(INT_DMATLB_MISS);
-       raw_local_irq_unmask(INT_DMATLB_ACCESS);
+       arch_local_irq_unmask(INT_DMATLB_MISS);
+       arch_local_irq_unmask(INT_DMATLB_ACCESS);
 #endif
 #if CHIP_HAS_SN_PROC()
-       raw_local_irq_unmask(INT_SNITLB_MISS);
+       arch_local_irq_unmask(INT_SNITLB_MISS);
 #endif
 #ifdef __tilegx__
-       raw_local_irq_unmask(INT_SINGLE_STEP_K);
+       arch_local_irq_unmask(INT_SINGLE_STEP_K);
 #endif
 
        /*
index fb28e85ae3aea3698c7d2cd5da564bb0a5f7fb0d..757407e36696688d59810453b1ffca8da8522a62 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -71,6 +70,9 @@ int restore_sigcontext(struct pt_regs *regs,
        for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
                err |= __get_user(regs->regs[i], &sc->gregs[i]);
 
+       /* Ensure that the PL is always set to USER_PL. */
+       regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1));
+
        regs->faultnum = INT_SWINT_1_SIGRETURN;
 
        err |= __get_user(*pr0, &sc->gregs[0]);
@@ -330,7 +332,7 @@ void do_signal(struct pt_regs *regs)
                        current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                }
 
-               return;
+               goto done;
        }
 
        /* Did we come from a system call? */
@@ -358,4 +360,8 @@ void do_signal(struct pt_regs *regs)
                current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
        }
+
+done:
+       /* Avoid double syscall restart if there are nested signals. */
+       regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
index 75255d90aff309669b110dff32f2254ede9daa27..9575b37a8b75318d57cd061172d7cd09d0cf8049 100644 (file)
@@ -115,7 +115,7 @@ static void smp_start_cpu_interrupt(void)
 static void smp_stop_cpu_interrupt(void)
 {
        set_cpu_online(smp_processor_id(), 0);
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        for (;;)
                asm("nap");
 }
index 74d62d098edf455bddb73852535b69e733d442a0..b949edcec200b60018c7ecf6a9aef049771e0260 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
index 7e764669a0222755db93373089539e18ade539d8..e2187d24a9b41d8ad765f1a383347525dc728a5f 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
index 6bed820e1421ae628c9ad162de3e50eb1f2884bf..f2e156e44692505e620c7e6c1a35e1ca948c3855 100644 (file)
@@ -132,7 +132,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 {
        BUG_ON(ticks > MAX_TICK);
        __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
-       raw_local_irq_unmask_now(INT_TILE_TIMER);
+       arch_local_irq_unmask_now(INT_TILE_TIMER);
        return 0;
 }
 
@@ -143,7 +143,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 static void tile_timer_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
 {
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 }
 
 /*
@@ -172,7 +172,7 @@ void __cpuinit setup_tile_timer(void)
        evt->cpumask = cpumask_of(smp_processor_id());
 
        /* Start out with timer not firing. */
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 
        /* Register tile timer. */
        clockevents_register_device(evt);
@@ -188,7 +188,7 @@ void do_timer_interrupt(struct pt_regs *regs, int fault_num)
         * Mask the timer interrupt here, since we are a oneshot timer
         * and there are now by definition no events pending.
         */
-       raw_local_irq_mask(INT_TILE_TIMER);
+       arch_local_irq_mask(INT_TILE_TIMER);
 
        /* Track time spent here in an interrupt context */
        irq_enter();
index dfedea7b266b5d58e6cd445fa8ed0f8ae8fcaea8..f7d4a6ad61e811356ac6bec2b9f235c94f4355c6 100644 (file)
@@ -54,7 +54,7 @@ typedef unsigned long (*memcpy_t)(void *, const void *, unsigned long);
  * we must run with interrupts disabled to avoid the risk of some
  * other code seeing the incoherent data in our cache.  (Recall that
  * our cache is indexed by PA, so even if the other code doesn't use
- * our KM_MEMCPY virtual addresses, they'll still hit in cache using
+ * our kmap_atomic virtual addresses, they'll still hit in cache using
  * the normal VAs that aren't supposed to hit in cache.)
  */
 static void memcpy_multicache(void *dest, const void *source,
@@ -64,6 +64,7 @@ static void memcpy_multicache(void *dest, const void *source,
        unsigned long flags, newsrc, newdst;
        pmd_t *pmdp;
        pte_t *ptep;
+       int type0, type1;
        int cpu = get_cpu();
 
        /*
@@ -77,7 +78,8 @@ static void memcpy_multicache(void *dest, const void *source,
        sim_allow_multiple_caching(1);
 
        /* Set up the new dest mapping */
-       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + KM_MEMCPY0;
+       type0 = kmap_atomic_idx_push();
+       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + type0;
        newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1));
        pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst);
        ptep = pte_offset_kernel(pmdp, newdst);
@@ -87,7 +89,8 @@ static void memcpy_multicache(void *dest, const void *source,
        }
 
        /* Set up the new source mapping */
-       idx += (KM_MEMCPY0 - KM_MEMCPY1);
+       type1 = kmap_atomic_idx_push();
+       idx += (type0 - type1);
        src_pte = hv_pte_set_nc(src_pte);
        src_pte = hv_pte_clear_writable(src_pte);  /* be paranoid */
        newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
@@ -119,6 +122,8 @@ static void memcpy_multicache(void *dest, const void *source,
         * We're done: notify the simulator that all is back to normal,
         * and re-enable interrupts and pre-emption.
         */
+       kmap_atomic_idx_pop();
+       kmap_atomic_idx_pop();
        sim_allow_multiple_caching(0);
        local_irq_restore(flags);
        put_cpu();
index f295b4ac941de22b760651f5ac019361e00802d2..dcebfc831cd6e94a23571681cd341db358d8d807 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/tty.h>
index abb57331cf6e1b25fdeccfd295e25ea7464ebbf5..31dbbd9afe47d5cb32590b96e1d7065e2ff5bf24 100644 (file)
@@ -227,7 +227,7 @@ EXPORT_SYMBOL(kmap_atomic_prot);
 void *__kmap_atomic(struct page *page)
 {
        /* PAGE_NONE is a magic value that tells us to check immutability. */
-       return kmap_atomic_prot(page, type, PAGE_NONE);
+       return kmap_atomic_prot(page, PAGE_NONE);
 }
 EXPORT_SYMBOL(__kmap_atomic);
 
index 24688b697a8d92e48284daff0643b61cfd11c281..201a582c413752c40ec6fc87bfc87ca3e73bb8d2 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sysctl.h>
index 78e1982cb6c9dc0385e258b81bfc233f23baaaac..0b9ce69b0ee5e755ea6186e1093269507cae156d 100644 (file)
@@ -988,8 +988,12 @@ static long __write_once initfree = 1;
 /* Select whether to free (1) or mark unusable (0) the __init pages. */
 static int __init set_initfree(char *str)
 {
-       strict_strtol(str, 0, &initfree);
-       pr_info("initfree: %s free init pages\n", initfree ? "will" : "won't");
+       long val;
+       if (strict_strtol(str, 0, &val)) {
+               initfree = val;
+               pr_info("initfree: %s free init pages\n",
+                       initfree ? "will" : "won't");
+       }
        return 1;
 }
 __setup("initfree=", set_initfree);
index 335c24621c418b1a7bffdacc2723bbcee665c8e2..1f5430c53d0db4cf62c992c656de7e1b2e9769e6 100644 (file)
@@ -134,9 +134,9 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 }
 
 #if defined(CONFIG_HIGHPTE)
-pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type)
+pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
 {
-       pte_t *pte = kmap_atomic(pmd_page(*dir), type) +
+       pte_t *pte = kmap_atomic(pmd_page(*dir)) +
                (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK;
        return &pte[pte_index(address)];
 }
index 2cd899f75a3cc21f2e53e2f6b8d9b46368f496cc..b7c5bab9bd774db16b8eaaa31441a8aa45e45aea 100644 (file)
@@ -38,8 +38,8 @@ struct pt_regs {
 
 struct task_struct;
 
-extern long subarch_ptrace(struct task_struct *child, long request, long addr,
-                          long data);
+extern long subarch_ptrace(struct task_struct *child, long request,
+       unsigned long addr, unsigned long data);
 extern unsigned long getreg(struct task_struct *child, int regno);
 extern int putreg(struct task_struct *child, int regno, unsigned long value);
 extern int get_fpregs(struct user_i387_struct __user *buf,
index 340268be00b5a934f6fc3ac632c26e53b58623ec..09bd7b585726cdcd2109a5a70250a8871bbdcaf7 100644 (file)
@@ -5,7 +5,6 @@
 
 #include "linux/stddef.h"
 #include "linux/fs.h"
-#include "linux/smp_lock.h"
 #include "linux/ptrace.h"
 #include "linux/sched.h"
 #include "linux/slab.h"
index a5e33f29bbeb7ef71e9a25697e5c8bfd3e664370..701b672c11225aaf6ffcdd9fe9485bccacbd4726 100644 (file)
@@ -122,7 +122,7 @@ long arch_ptrace(struct task_struct *child, long request,
                break;
 
        case PTRACE_SET_THREAD_AREA:
-               ret = ptrace_set_thread_area(child, addr, datavp);
+               ret = ptrace_set_thread_area(child, addr, vp);
                break;
 
        case PTRACE_FAULTINFO: {
index 849813f398e75e8f699b5a5e999efad7df1a76a8..5852519b2d0f94005d688159c045b52b69c8766b 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/syscalls.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/uio.h>
 #include <linux/poll.h>
index 286de34b0ed6773c6ccb2b7b052023394b93396f..f6ce0bda3b98a74906cb1c8297f4ba150430699d 100644 (file)
@@ -141,13 +141,13 @@ static inline void native_apic_msr_write(u32 reg, u32 v)
 
 static inline u32 native_apic_msr_read(u32 reg)
 {
-       u32 low, high;
+       u64 msr;
 
        if (reg == APIC_DFR)
                return -1;
 
-       rdmsr(APIC_BASE_MSR + (reg >> 4), low, high);
-       return low;
+       rdmsrl(APIC_BASE_MSR + (reg >> 4), msr);
+       return (u32)msr;
 }
 
 static inline void native_x2apic_wait_icr_idle(void)
@@ -181,12 +181,12 @@ extern void enable_x2apic(void);
 extern void x2apic_icr_write(u32 low, u32 id);
 static inline int x2apic_enabled(void)
 {
-       int msr, msr2;
+       u64 msr;
 
        if (!cpu_has_x2apic)
                return 0;
 
-       rdmsr(MSR_IA32_APICBASE, msr, msr2);
+       rdmsrl(MSR_IA32_APICBASE, msr);
        if (msr & X2APIC_ENABLE)
                return 1;
        return 0;
index b2f2d2e05cec4eba8195b60ae053d4f81a5992ee..6d90adf4428a03d90d183dcd1a77cb2b630fc8e2 100644 (file)
@@ -805,6 +805,78 @@ union uvh_node_present_table_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
+
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_alias210_overlay_config_0_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_alias210_overlay_config_0_mmr_s {
+       unsigned long   rsvd_0_23: 24;  /*    */
+       unsigned long   base    :  8;  /* RW */
+       unsigned long   rsvd_32_47: 16;  /*    */
+       unsigned long   m_alias :  5;  /* RW */
+       unsigned long   rsvd_53_62: 10;  /*    */
+       unsigned long   enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
+
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_alias210_overlay_config_1_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_alias210_overlay_config_1_mmr_s {
+       unsigned long   rsvd_0_23: 24;  /*    */
+       unsigned long   base    :  8;  /* RW */
+       unsigned long   rsvd_32_47: 16;  /*    */
+       unsigned long   m_alias :  5;  /* RW */
+       unsigned long   rsvd_53_62: 10;  /*    */
+       unsigned long   enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
+
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_alias210_overlay_config_2_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_alias210_overlay_config_2_mmr_s {
+       unsigned long   rsvd_0_23: 24;  /*    */
+       unsigned long   base    :  8;  /* RW */
+       unsigned long   rsvd_32_47: 16;  /*    */
+       unsigned long   m_alias :  5;  /* RW */
+       unsigned long   rsvd_53_62: 10;  /*    */
+       unsigned long   enable  :  1;  /* RW */
+    } s;
+};
+
 /* ========================================================================= */
 /*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR                  */
 /* ========================================================================= */
@@ -856,6 +928,29 @@ union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
     } s;
 };
 
+/* ========================================================================= */
+/*                          UVH_RH_GAM_CONFIG_MMR                            */
+/* ========================================================================= */
+#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL
+
+#define UVH_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
+#define UVH_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
+#define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
+#define UVH_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
+#define UVH_RH_GAM_CONFIG_MMR_MMIOL_CFG_SHFT 12
+#define UVH_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL
+
+union uvh_rh_gam_config_mmr_u {
+    unsigned long      v;
+    struct uvh_rh_gam_config_mmr_s {
+       unsigned long   m_skt     :  6;  /* RW */
+       unsigned long   n_skt     :  4;  /* RW */
+       unsigned long   rsvd_10_11:  2;  /*    */
+       unsigned long   mmiol_cfg :  1;  /* RW */
+       unsigned long   rsvd_13_63: 51;  /*    */
+    } s;
+};
+
 /* ========================================================================= */
 /*                    UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR                      */
 /* ========================================================================= */
@@ -987,97 +1082,5 @@ union uvh_rtc1_int_config_u {
     } s;
 };
 
-/* ========================================================================= */
-/*                          UVH_SI_ADDR_MAP_CONFIG                           */
-/* ========================================================================= */
-#define UVH_SI_ADDR_MAP_CONFIG 0xc80000UL
-
-#define UVH_SI_ADDR_MAP_CONFIG_M_SKT_SHFT 0
-#define UVH_SI_ADDR_MAP_CONFIG_M_SKT_MASK 0x000000000000003fUL
-#define UVH_SI_ADDR_MAP_CONFIG_N_SKT_SHFT 8
-#define UVH_SI_ADDR_MAP_CONFIG_N_SKT_MASK 0x0000000000000f00UL
-
-union uvh_si_addr_map_config_u {
-    unsigned long      v;
-    struct uvh_si_addr_map_config_s {
-       unsigned long   m_skt :  6;  /* RW */
-       unsigned long   rsvd_6_7:  2;  /*    */
-       unsigned long   n_skt :  4;  /* RW */
-       unsigned long   rsvd_12_63: 52;  /*    */
-    } s;
-};
-
-/* ========================================================================= */
-/*                       UVH_SI_ALIAS0_OVERLAY_CONFIG                        */
-/* ========================================================================= */
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG 0xc80008UL
-
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_BASE_SHFT 24
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_M_ALIAS_SHFT 48
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_ENABLE_SHFT 63
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
-
-union uvh_si_alias0_overlay_config_u {
-    unsigned long      v;
-    struct uvh_si_alias0_overlay_config_s {
-       unsigned long   rsvd_0_23: 24;  /*    */
-       unsigned long   base    :  8;  /* RW */
-       unsigned long   rsvd_32_47: 16;  /*    */
-       unsigned long   m_alias :  5;  /* RW */
-       unsigned long   rsvd_53_62: 10;  /*    */
-       unsigned long   enable  :  1;  /* RW */
-    } s;
-};
-
-/* ========================================================================= */
-/*                       UVH_SI_ALIAS1_OVERLAY_CONFIG                        */
-/* ========================================================================= */
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG 0xc80010UL
-
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_BASE_SHFT 24
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_M_ALIAS_SHFT 48
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_ENABLE_SHFT 63
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
-
-union uvh_si_alias1_overlay_config_u {
-    unsigned long      v;
-    struct uvh_si_alias1_overlay_config_s {
-       unsigned long   rsvd_0_23: 24;  /*    */
-       unsigned long   base    :  8;  /* RW */
-       unsigned long   rsvd_32_47: 16;  /*    */
-       unsigned long   m_alias :  5;  /* RW */
-       unsigned long   rsvd_53_62: 10;  /*    */
-       unsigned long   enable  :  1;  /* RW */
-    } s;
-};
-
-/* ========================================================================= */
-/*                       UVH_SI_ALIAS2_OVERLAY_CONFIG                        */
-/* ========================================================================= */
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG 0xc80018UL
-
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_BASE_SHFT 24
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_M_ALIAS_SHFT 48
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_ENABLE_SHFT 63
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
-
-union uvh_si_alias2_overlay_config_u {
-    unsigned long      v;
-    struct uvh_si_alias2_overlay_config_s {
-       unsigned long   rsvd_0_23: 24;  /*    */
-       unsigned long   base    :  8;  /* RW */
-       unsigned long   rsvd_32_47: 16;  /*    */
-       unsigned long   m_alias :  5;  /* RW */
-       unsigned long   rsvd_53_62: 10;  /*    */
-       unsigned long   enable  :  1;  /* RW */
-    } s;
-};
-
 
-#endif /* _ASM_X86_UV_UV_MMRS_H */
+#endif /* __ASM_UV_MMRS_X86_H__ */
index e8506c1f0c55115e8282ef5b8177b824f88df282..1c10c88ee4e1a5154168b4b35a6ba34857687fc9 100644 (file)
@@ -61,9 +61,9 @@ DEFINE_GUEST_HANDLE(void);
 #define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
 #endif
 
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
+#define MACH2PHYS_VIRT_START  mk_unsigned_long(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END    mk_unsigned_long(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_NR_ENTRIES  ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT)
 
 /* Maximum number of virtual CPUs in multi-processor guests. */
 #define MAX_VIRT_CPUS 32
index 42a7e004ae5ca5372553fec8a9059378ab6a55c4..8413688b2571d760f77d918713b758345bdece0a 100644 (file)
 /* And the trap vector is... */
 #define TRAP_INSTR "int $0x82"
 
+#define __MACH2PHYS_VIRT_START 0xF5800000
+#define __MACH2PHYS_VIRT_END   0xF6800000
+
+#define __MACH2PHYS_SHIFT      2
+
 /*
  * Virtual addresses beyond this are not modifiable by guest OSes. The
  * machine->physical mapping table starts at this address, read-only.
index 100d2662b97c3c8a821fc6039e93a06b7a2924c7..839a4811cf983630faa5b724277aafacfefe36cb 100644 (file)
 #define __HYPERVISOR_VIRT_END   0xFFFF880000000000
 #define __MACH2PHYS_VIRT_START  0xFFFF800000000000
 #define __MACH2PHYS_VIRT_END    0xFFFF804000000000
-
-#ifndef HYPERVISOR_VIRT_START
-#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
-#define HYPERVISOR_VIRT_END   mk_unsigned_long(__HYPERVISOR_VIRT_END)
-#endif
-
-#define MACH2PHYS_VIRT_START  mk_unsigned_long(__MACH2PHYS_VIRT_START)
-#define MACH2PHYS_VIRT_END    mk_unsigned_long(__MACH2PHYS_VIRT_END)
-#define MACH2PHYS_NR_ENTRIES  ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
+#define __MACH2PHYS_SHIFT       3
 
 /*
  * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
index dd8c1414b3d57540d374fee9d923947aaa57ceb1..8760cc60a21c8af5bcc7be1993bdf0b67c0eeb06 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/pfn.h>
+#include <linux/mm.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -35,6 +36,8 @@ typedef struct xpaddr {
 #define MAX_DOMAIN_PAGES                                               \
     ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
 
+extern unsigned long *machine_to_phys_mapping;
+extern unsigned int   machine_to_phys_order;
 
 extern unsigned long get_phys_to_machine(unsigned long pfn);
 extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
@@ -69,10 +72,8 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return mfn;
 
-#if 0
        if (unlikely((mfn >> machine_to_phys_order) != 0))
-               return max_mapnr;
-#endif
+               return ~0;
 
        pfn = 0;
        /*
index 850657d1b0ed573e23552913d7aae230df30fe9a..3f838d537392b4ddb6d061e82bbf1ce8a2a3b9d2 100644 (file)
@@ -52,7 +52,6 @@
 #include <asm/mce.h>
 #include <asm/kvm_para.h>
 #include <asm/tsc.h>
-#include <asm/atomic.h>
 
 unsigned int num_processors;
 
index ed4118de249ef0d3a72e08865ea5e949ee2d80fe..194539aea1757d79058e3ec17acbeaa68ae6432f 100644 (file)
@@ -379,14 +379,14 @@ struct redir_addr {
 #define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT
 
 static __initdata struct redir_addr redir_addrs[] = {
-       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_SI_ALIAS0_OVERLAY_CONFIG},
-       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_SI_ALIAS1_OVERLAY_CONFIG},
-       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_SI_ALIAS2_OVERLAY_CONFIG},
+       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR},
+       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR},
+       {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR},
 };
 
 static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 {
-       union uvh_si_alias0_overlay_config_u alias;
+       union uvh_rh_gam_alias210_overlay_config_2_mmr_u alias;
        union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect;
        int i;
 
@@ -660,7 +660,7 @@ void uv_nmi_init(void)
 
 void __init uv_system_init(void)
 {
-       union uvh_si_addr_map_config_u m_n_config;
+       union uvh_rh_gam_config_mmr_u  m_n_config;
        union uvh_node_id_u node_id;
        unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
        int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
@@ -670,7 +670,7 @@ void __init uv_system_init(void)
 
        map_low_mmrs();
 
-       m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
+       m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
        m_val = m_n_config.s.m_skt;
        n_val = m_n_config.s.n_skt;
        mmr_base =
index 46d58448c3aff9039fdf0b909d069d00d80ef75e..e421b8cd6944af860c4b28a1a176a14320ac9f79 100644 (file)
@@ -280,11 +280,11 @@ static struct amd_nb *amd_alloc_nb(int cpu, int nb_id)
        struct amd_nb *nb;
        int i;
 
-       nb = kmalloc(sizeof(struct amd_nb), GFP_KERNEL);
+       nb = kmalloc_node(sizeof(struct amd_nb), GFP_KERNEL | __GFP_ZERO,
+                         cpu_to_node(cpu));
        if (!nb)
                return NULL;
 
-       memset(nb, 0, sizeof(*nb));
        nb->nb_id = nb_id;
 
        /*
index 1b7b31ab7d86536ecde1d68034cf882216ac32a6..212a6a42527c5fcbd0a79f05e4ed7d1cff077cf7 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/device.h>
index ec592caac4b4e11b5d7ac0bc2986d6617ac4b90b..cd21b654dec6c70382b68ab29f4364ab60ff4e88 100644 (file)
@@ -315,14 +315,18 @@ static void kgdb_remove_all_hw_break(void)
                if (!breakinfo[i].enabled)
                        continue;
                bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
-               if (bp->attr.disabled == 1)
+               if (!bp->attr.disabled) {
+                       arch_uninstall_hw_breakpoint(bp);
+                       bp->attr.disabled = 1;
                        continue;
+               }
                if (dbg_is_early)
                        early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
                                                 breakinfo[i].type);
-               else
-                       arch_uninstall_hw_breakpoint(bp);
-               bp->attr.disabled = 1;
+               else if (hw_break_release_slot(i))
+                       printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n",
+                              breakinfo[i].addr);
+               breakinfo[i].enabled = 0;
        }
 }
 
index e1af7c055c7d0c86c7e3a1fe789e597825185892..ce0cb4721c9ac9eec8869e64c1fcd1a1ef0fd379 100644 (file)
@@ -212,7 +212,7 @@ static int install_equiv_cpu_table(const u8 *buf)
                return 0;
        }
 
-       equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+       equiv_cpu_table = vmalloc(size);
        if (!equiv_cpu_table) {
                pr_err("failed to allocate equivalent CPU table\n");
                return 0;
index 71825806cd44f14cf49e8381e22b5dbd3ac0b29d..6da143c2a6b8b27f03a611bad88047879c80f3bf 100644 (file)
@@ -217,13 +217,13 @@ void __cpuinit fam10h_check_enable_mmcfg(void)
        wrmsrl(address, val);
 }
 
-static int __devinit set_check_enable_amd_mmconf(const struct dmi_system_id *d)
+static int __init set_check_enable_amd_mmconf(const struct dmi_system_id *d)
 {
         pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
         return 0;
 }
 
-static const struct dmi_system_id __cpuinitconst mmconf_dmi_table[] = {
+static const struct dmi_system_id __initconst mmconf_dmi_table[] = {
         {
                 .callback = set_check_enable_amd_mmconf,
                 .ident = "Sun Microsystems Machine",
@@ -234,7 +234,8 @@ static const struct dmi_system_id __cpuinitconst mmconf_dmi_table[] = {
        {}
 };
 
-void __cpuinit check_enable_amd_mmconf_dmi(void)
+/* Called from a __cpuinit function, but only on the BSP. */
+void __ref check_enable_amd_mmconf_dmi(void)
 {
        dmi_check_system(mmconf_dmi_table);
 }
index 7bf2dc4c8f701de8965fc1e124126863c7384552..12fcbe2c143e5e3c7a9e62f58981a78f5355bd64 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/device.h>
index bab3b9e6f66d0d4919f5f035848037ce5ccf7639..008b91eefa188139f57f7b77de6c7aef6240ef08 100644 (file)
@@ -41,44 +41,6 @@ void pvclock_set_flags(u8 flags)
        valid_flags = flags;
 }
 
-/*
- * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
- * yielding a 64-bit result.
- */
-static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
-{
-       u64 product;
-#ifdef __i386__
-       u32 tmp1, tmp2;
-#endif
-
-       if (shift < 0)
-               delta >>= -shift;
-       else
-               delta <<= shift;
-
-#ifdef __i386__
-       __asm__ (
-               "mul  %5       ; "
-               "mov  %4,%%eax ; "
-               "mov  %%edx,%4 ; "
-               "mul  %5       ; "
-               "xor  %5,%5    ; "
-               "add  %4,%%eax ; "
-               "adc  %5,%%edx ; "
-               : "=A" (product), "=r" (tmp1), "=r" (tmp2)
-               : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
-#elif defined(__x86_64__)
-       __asm__ (
-               "mul %%rdx ; shrd $32,%%rdx,%%rax"
-               : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
-#else
-#error implement me!
-#endif
-
-       return product;
-}
-
 static u64 pvclock_get_nsec_offset(struct pvclock_shadow_time *shadow)
 {
        u64 delta = native_read_tsc() - shadow->tsc_timestamp;
index 908ea5464a518097958083156eb5b0b94f4d021c..fb8b376bf28cb3e04a6bb903900f32838ab02a14 100644 (file)
@@ -720,7 +720,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
        }
 }
 
-static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+static int set_spte_track_bits(u64 *sptep, u64 new_spte)
 {
        pfn_t pfn;
        u64 old_spte = *sptep;
@@ -731,19 +731,20 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte)
                old_spte = __xchg_spte(sptep, new_spte);
 
        if (!is_rmap_spte(old_spte))
-               return;
+               return 0;
 
        pfn = spte_to_pfn(old_spte);
        if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
                kvm_set_pfn_accessed(pfn);
        if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
                kvm_set_pfn_dirty(pfn);
+       return 1;
 }
 
 static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
 {
-       set_spte_track_bits(sptep, new_spte);
-       rmap_remove(kvm, sptep);
+       if (set_spte_track_bits(sptep, new_spte))
+               rmap_remove(kvm, sptep);
 }
 
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
index 82e144a4e514249c140f5c28a8bd0df00869b5ca..1ca12298ffc74f2d783effb35da0953163bbb314 100644 (file)
@@ -3395,6 +3395,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
        load_host_msrs(vcpu);
+       kvm_load_ldt(ldt_selector);
        loadsegment(fs, fs_selector);
 #ifdef CONFIG_X86_64
        load_gs_index(gs_selector);
@@ -3402,7 +3403,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
 #else
        loadsegment(gs, gs_selector);
 #endif
-       kvm_load_ldt(ldt_selector);
 
        reload_tss(vcpu);
 
index 8da0e45ff7c9cde22d424583adbb2786cf78a72a..ff21fdda0c53b6dbf2ca84b1e4e2300e2a659b90 100644 (file)
@@ -821,10 +821,9 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 #endif
 
 #ifdef CONFIG_X86_64
-       if (is_long_mode(&vmx->vcpu)) {
-               rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+       rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+       if (is_long_mode(&vmx->vcpu))
                wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
-       }
 #endif
        for (i = 0; i < vmx->save_nmsrs; ++i)
                kvm_set_shared_msr(vmx->guest_msrs[i].index,
@@ -839,23 +838,23 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
 
        ++vmx->vcpu.stat.host_state_reload;
        vmx->host_state.loaded = 0;
-       if (vmx->host_state.fs_reload_needed)
-               loadsegment(fs, vmx->host_state.fs_sel);
+#ifdef CONFIG_X86_64
+       if (is_long_mode(&vmx->vcpu))
+               rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+#endif
        if (vmx->host_state.gs_ldt_reload_needed) {
                kvm_load_ldt(vmx->host_state.ldt_sel);
 #ifdef CONFIG_X86_64
                load_gs_index(vmx->host_state.gs_sel);
-               wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
 #else
                loadsegment(gs, vmx->host_state.gs_sel);
 #endif
        }
+       if (vmx->host_state.fs_reload_needed)
+               loadsegment(fs, vmx->host_state.fs_sel);
        reload_tss();
 #ifdef CONFIG_X86_64
-       if (is_long_mode(&vmx->vcpu)) {
-               rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
-               wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
-       }
+       wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
 #endif
        if (current_thread_info()->status & TS_USEDFPU)
                clts();
index 2288ad829b327bb68d0efa65c104dcc7f2bbe7b5..cdac9e592aa53ee84b7e184900601ab4730354e5 100644 (file)
@@ -2560,6 +2560,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
                !kvm_exception_is_soft(vcpu->arch.exception.nr);
        events->exception.nr = vcpu->arch.exception.nr;
        events->exception.has_error_code = vcpu->arch.exception.has_error_code;
+       events->exception.pad = 0;
        events->exception.error_code = vcpu->arch.exception.error_code;
 
        events->interrupt.injected =
@@ -2573,12 +2574,14 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
        events->nmi.injected = vcpu->arch.nmi_injected;
        events->nmi.pending = vcpu->arch.nmi_pending;
        events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
+       events->nmi.pad = 0;
 
        events->sipi_vector = vcpu->arch.sipi_vector;
 
        events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
                         | KVM_VCPUEVENT_VALID_SIPI_VECTOR
                         | KVM_VCPUEVENT_VALID_SHADOW);
+       memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2623,6 +2626,7 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
        dbgregs->dr6 = vcpu->arch.dr6;
        dbgregs->dr7 = vcpu->arch.dr7;
        dbgregs->flags = 0;
+       memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -3106,6 +3110,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
                sizeof(ps->channels));
        ps->flags = kvm->arch.vpit->pit_state.flags;
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+       memset(&ps->reserved, 0, sizeof(ps->reserved));
        return r;
 }
 
@@ -3169,10 +3174,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                struct kvm_memslots *slots, *old_slots;
                unsigned long *dirty_bitmap;
 
-               spin_lock(&kvm->mmu_lock);
-               kvm_mmu_slot_remove_write_access(kvm, log->slot);
-               spin_unlock(&kvm->mmu_lock);
-
                r = -ENOMEM;
                dirty_bitmap = vmalloc(n);
                if (!dirty_bitmap)
@@ -3194,6 +3195,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
                kfree(old_slots);
 
+               spin_lock(&kvm->mmu_lock);
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               spin_unlock(&kvm->mmu_lock);
+
                r = -EFAULT;
                if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
                        vfree(dirty_bitmap);
@@ -3486,6 +3491,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
                local_irq_enable();
                user_ns.flags = 0;
+               memset(&user_ns.pad, 0, sizeof(user_ns.pad));
 
                r = -EFAULT;
                if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
@@ -3972,8 +3978,10 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
                return X86EMUL_CONTINUE;
 
        if (kvm_x86_ops->has_wbinvd_exit()) {
+               preempt_disable();
                smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
                                wbinvd_ipi, NULL, 1);
+               preempt_enable();
                cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
        }
        wbinvd();
index 49358481c733235918cde7c576a3332fba50c364..12cdbb17ad181dfac805d60f4991ee1eacfb935c 100644 (file)
@@ -251,7 +251,7 @@ static void __cpuinit calculate_tlb_offset(void)
        }
 }
 
-static int tlb_cpuhp_notify(struct notifier_block *n,
+static int __cpuinit tlb_cpuhp_notify(struct notifier_block *n,
                unsigned long action, void *hcpu)
 {
        switch (action & 0xf) {
index 15466c096ba5f56fabc7f174eabd1c40996e4b6d..0972315c3860c40c719f1b03081b892c3e8f20bf 100644 (file)
@@ -138,7 +138,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        struct acpi_resource_address64 addr;
        acpi_status status;
        unsigned long flags;
-       struct resource *root, *conflict;
        u64 start, end;
 
        status = resource_to_addr(acpi_res, &addr);
@@ -146,12 +145,10 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
                return AE_OK;
 
        if (addr.resource_type == ACPI_MEMORY_RANGE) {
-               root = &iomem_resource;
                flags = IORESOURCE_MEM;
                if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
                        flags |= IORESOURCE_PREFETCH;
        } else if (addr.resource_type == ACPI_IO_RANGE) {
-               root = &ioport_resource;
                flags = IORESOURCE_IO;
        } else
                return AE_OK;
@@ -172,25 +169,90 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
                return AE_OK;
        }
 
-       conflict = insert_resource_conflict(root, res);
-       if (conflict) {
-               dev_err(&info->bridge->dev,
-                       "address space collision: host bridge window %pR "
-                       "conflicts with %s %pR\n",
-                       res, conflict->name, conflict);
-       } else {
-               pci_bus_add_resource(info->bus, res, 0);
-               info->res_num++;
-               if (addr.translation_offset)
-                       dev_info(&info->bridge->dev, "host bridge window %pR "
-                                "(PCI address [%#llx-%#llx])\n",
-                                res, res->start - addr.translation_offset,
-                                res->end - addr.translation_offset);
+       info->res_num++;
+       if (addr.translation_offset)
+               dev_info(&info->bridge->dev, "host bridge window %pR "
+                        "(PCI address [%#llx-%#llx])\n",
+                        res, res->start - addr.translation_offset,
+                        res->end - addr.translation_offset);
+       else
+               dev_info(&info->bridge->dev, "host bridge window %pR\n", res);
+
+       return AE_OK;
+}
+
+static bool resource_contains(struct resource *res, resource_size_t point)
+{
+       if (res->start <= point && point <= res->end)
+               return true;
+       return false;
+}
+
+static void coalesce_windows(struct pci_root_info *info, int type)
+{
+       int i, j;
+       struct resource *res1, *res2;
+
+       for (i = 0; i < info->res_num; i++) {
+               res1 = &info->res[i];
+               if (!(res1->flags & type))
+                       continue;
+
+               for (j = i + 1; j < info->res_num; j++) {
+                       res2 = &info->res[j];
+                       if (!(res2->flags & type))
+                               continue;
+
+                       /*
+                        * I don't like throwing away windows because then
+                        * our resources no longer match the ACPI _CRS, but
+                        * the kernel resource tree doesn't allow overlaps.
+                        */
+                       if (resource_contains(res1, res2->start) ||
+                           resource_contains(res1, res2->end) ||
+                           resource_contains(res2, res1->start) ||
+                           resource_contains(res2, res1->end)) {
+                               res1->start = min(res1->start, res2->start);
+                               res1->end = max(res1->end, res2->end);
+                               dev_info(&info->bridge->dev,
+                                        "host bridge window expanded to %pR; %pR ignored\n",
+                                        res1, res2);
+                               res2->flags = 0;
+                       }
+               }
+       }
+}
+
+static void add_resources(struct pci_root_info *info)
+{
+       int i;
+       struct resource *res, *root, *conflict;
+
+       if (!pci_use_crs)
+               return;
+
+       coalesce_windows(info, IORESOURCE_MEM);
+       coalesce_windows(info, IORESOURCE_IO);
+
+       for (i = 0; i < info->res_num; i++) {
+               res = &info->res[i];
+
+               if (res->flags & IORESOURCE_MEM)
+                       root = &iomem_resource;
+               else if (res->flags & IORESOURCE_IO)
+                       root = &ioport_resource;
                else
-                       dev_info(&info->bridge->dev,
-                                "host bridge window %pR\n", res);
+                       continue;
+
+               conflict = insert_resource_conflict(root, res);
+               if (conflict)
+                       dev_err(&info->bridge->dev,
+                               "address space collision: host bridge window %pR "
+                               "conflicts with %s %pR\n",
+                               res, conflict->name, conflict);
+               else
+                       pci_bus_add_resource(info->bus, res, 0);
        }
-       return AE_OK;
 }
 
 static void
@@ -224,6 +286,7 @@ get_current_resources(struct acpi_device *device, int busnum,
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
                                &info);
 
+       add_resources(&info);
        return;
 
 name_alloc_fail:
index 117f5b8daf7515bf8ac03deb5522a011c286280d..d7b5109f7a9c28b05e120da3eec295b1716f543e 100644 (file)
@@ -147,8 +147,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                irq = xen_allocate_pirq(v[i], 0, /* not sharable */
                        (type == PCI_CAP_ID_MSIX) ?
                        "pcifront-msi-x" : "pcifront-msi");
-               if (irq < 0)
-                       return -1;
+               if (irq < 0) {
+                       ret = -1;
+                       goto free;
+               }
 
                ret = set_irq_msi(irq, msidesc);
                if (ret)
@@ -164,7 +166,7 @@ error:
        if (ret == -ENODEV)
                dev_err(&dev->dev, "Xen PCI frontend has not registered" \
                        " MSI/MSI-X support!\n");
-
+free:
        kfree(v);
        return ret;
 }
index 20ea20a39e2a2f4b2a0012edd532ebff368f3e5a..a318194002b56c3a953df57a9664c5f02745d2ba 100644 (file)
@@ -1343,8 +1343,8 @@ uv_activation_descriptor_init(int node, int pnode)
         * each bau_desc is 64 bytes; there are 8 (UV_ITEMS_PER_DESCRIPTOR)
         * per cpu; and up to 32 (UV_ADP_SIZE) cpu's per uvhub
         */
-       bau_desc = (struct bau_desc *)kmalloc_node(sizeof(struct bau_desc)*
-               UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node);
+       bau_desc = kmalloc_node(sizeof(struct bau_desc) * UV_ADP_SIZE
+                               * UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node);
        BUG_ON(!bau_desc);
 
        pa = uv_gpa(bau_desc); /* need the real nasid*/
@@ -1402,9 +1402,9 @@ uv_payload_queue_init(int node, int pnode)
        struct bau_payload_queue_entry *pqp_malloc;
        struct bau_control *bcp;
 
-       pqp = (struct bau_payload_queue_entry *) kmalloc_node(
-               (DEST_Q_SIZE + 1) * sizeof(struct bau_payload_queue_entry),
-               GFP_KERNEL, node);
+       pqp = kmalloc_node((DEST_Q_SIZE + 1)
+                          * sizeof(struct bau_payload_queue_entry),
+                          GFP_KERNEL, node);
        BUG_ON(!pqp);
        pqp_malloc = pqp;
 
@@ -1520,8 +1520,7 @@ static void __init uv_init_per_cpu(int nuvhubs)
 
        timeout_us = calculate_destination_timeout();
 
-       uvhub_descs = (struct uvhub_desc *)
-               kmalloc(nuvhubs * sizeof(struct uvhub_desc), GFP_KERNEL);
+       uvhub_descs = kmalloc(nuvhubs * sizeof(struct uvhub_desc), GFP_KERNEL);
        memset(uvhub_descs, 0, nuvhubs * sizeof(struct uvhub_desc));
        uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL);
        for_each_present_cpu(cpu) {
index 235c0f4d3861da6f1c9d64ded710c7c2176cf895..7250bef7f49eb0105063862443d1a5d9ba1c6118 100644 (file)
@@ -75,6 +75,11 @@ DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
 enum xen_domain_type xen_domain_type = XEN_NATIVE;
 EXPORT_SYMBOL_GPL(xen_domain_type);
 
+unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
+EXPORT_SYMBOL(machine_to_phys_mapping);
+unsigned int   machine_to_phys_order;
+EXPORT_SYMBOL(machine_to_phys_order);
+
 struct start_info *xen_start_info;
 EXPORT_SYMBOL_GPL(xen_start_info);
 
@@ -1090,6 +1095,8 @@ static void __init xen_setup_stackprotector(void)
 /* First C function to be called on Xen boot */
 asmlinkage void __init xen_start_kernel(void)
 {
+       struct physdev_set_iopl set_iopl;
+       int rc;
        pgd_t *pgd;
 
        if (!xen_start_info)
@@ -1097,6 +1104,8 @@ asmlinkage void __init xen_start_kernel(void)
 
        xen_domain_type = XEN_PV_DOMAIN;
 
+       xen_setup_machphys_mapping();
+
        /* Install Xen paravirt ops */
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
@@ -1202,10 +1211,18 @@ asmlinkage void __init xen_start_kernel(void)
 #else
        pv_info.kernel_rpl = 0;
 #endif
-
        /* set the limit of our address space */
        xen_reserve_top();
 
+       /* We used to do this in xen_arch_setup, but that is too late on AMD
+        * were early_cpu_init (run before ->arch_setup()) calls early_amd_init
+        * which pokes 0xcf8 port.
+        */
+       set_iopl.iopl = 1;
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+       if (rc != 0)
+               xen_raw_printk("physdev_op failed %d\n", rc);
+
 #ifdef CONFIG_X86_32
        /* set up basic CPUID stuff */
        cpu_detect(&new_cpu_data);
index c237b810b03ff8871e1291f149b3ca379b2af48c..790af908284e56424ce3c3b0c851b53eb1443b63 100644 (file)
@@ -2034,6 +2034,20 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
        set_page_prot(pmd, PAGE_KERNEL_RO);
 }
 
+void __init xen_setup_machphys_mapping(void)
+{
+       struct xen_machphys_mapping mapping;
+       unsigned long machine_to_phys_nr_ents;
+
+       if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
+               machine_to_phys_mapping = (unsigned long *)mapping.v_start;
+               machine_to_phys_nr_ents = mapping.max_mfn + 1;
+       } else {
+               machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+       }
+       machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+}
+
 #ifdef CONFIG_X86_64
 static void convert_pfn_mfn(void *v)
 {
@@ -2126,7 +2140,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 {
        pmd_t *kernel_pmd;
 
-       level2_kernel_pgt = extend_brk(sizeof(pmd_t *) * PTRS_PER_PMD, PAGE_SIZE);
+       level2_kernel_pgt = extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
 
        max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
                                  xen_start_info->nr_pt_frames * PAGE_SIZE +
@@ -2627,7 +2641,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
 
        prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
 
-       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+       BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
+                               (VM_PFNMAP | VM_RESERVED | VM_IO)));
 
        rmd.mfn = mfn;
        rmd.prot = prot;
index b1dbdaa23ecc2a632003382c0c9e4e1d6819e386..38fdffaa71d3347defe9fc871f7cc29acf374d3b 100644 (file)
@@ -118,16 +118,18 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
                                                     const struct e820map *e820)
 {
        phys_addr_t max_addr = PFN_PHYS(max_pfn);
-       phys_addr_t last_end = 0;
+       phys_addr_t last_end = ISA_END_ADDRESS;
        unsigned long released = 0;
        int i;
 
+       /* Free any unused memory above the low 1Mbyte. */
        for (i = 0; i < e820->nr_map && last_end < max_addr; i++) {
                phys_addr_t end = e820->map[i].addr;
                end = min(max_addr, end);
 
-               released += xen_release_chunk(last_end, end);
-               last_end = e820->map[i].addr + e820->map[i].size;
+               if (last_end < end)
+                       released += xen_release_chunk(last_end, end);
+               last_end = max(last_end, e820->map[i].addr + e820->map[i].size);
        }
 
        if (last_end < max_addr)
@@ -164,6 +166,7 @@ char * __init xen_memory_setup(void)
                XENMEM_memory_map;
        rc = HYPERVISOR_memory_op(op, &memmap);
        if (rc == -ENOSYS) {
+               BUG_ON(xen_initial_domain());
                memmap.nr_entries = 1;
                map[0].addr = 0ULL;
                map[0].size = mem_end;
@@ -201,12 +204,13 @@ char * __init xen_memory_setup(void)
        }
 
        /*
-        * Even though this is normal, usable memory under Xen, reserve
-        * ISA memory anyway because too many things think they can poke
+        * In domU, the ISA region is normal, usable memory, but we
+        * reserve ISA memory anyway because too many things poke
         * about in there.
         *
-        * In a dom0 kernel, this region is identity mapped with the
-        * hardware ISA area, so it really is out of bounds.
+        * In Dom0, the host E820 information can leave gaps in the
+        * ISA range, which would cause us to release those pages.  To
+        * avoid this, we unconditionally reserve them here.
         */
        e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS,
                        E820_RESERVED);
@@ -244,8 +248,7 @@ char * __init xen_memory_setup(void)
        else
                extra_pages = 0;
 
-       if (!xen_initial_domain())
-               xen_add_extra_mem(extra_pages);
+       xen_add_extra_mem(extra_pages);
 
        return "Xen";
 }
@@ -333,9 +336,6 @@ void __cpuinit xen_enable_syscall(void)
 
 void __init xen_arch_setup(void)
 {
-       struct physdev_set_iopl set_iopl;
-       int rc;
-
        xen_panic_handler_init();
 
        HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
@@ -352,11 +352,6 @@ void __init xen_arch_setup(void)
        xen_enable_sysenter();
        xen_enable_syscall();
 
-       set_iopl.iopl = 1;
-       rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
-       if (rc != 0)
-               printk(KERN_INFO "physdev_op failed %d\n", rc);
-
 #ifdef CONFIG_ACPI
        if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
                printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
index f0834e2f57275d8903f65b655645f66a9b2016ee..4ce953f1b3909f38f213adcc0a39251a34875330 100644 (file)
@@ -1194,13 +1194,6 @@ static int __make_request(struct request_queue *q, struct bio *bio)
        int where = ELEVATOR_INSERT_SORT;
        int rw_flags;
 
-       /* REQ_HARDBARRIER is no more */
-       if (WARN_ONCE(bio->bi_rw & REQ_HARDBARRIER,
-               "block: HARDBARRIER is deprecated, use FLUSH/FUA instead\n")) {
-               bio_endio(bio, -EOPNOTSUPP);
-               return 0;
-       }
-
        /*
         * low level driver can indicate that it wants pages above a
         * certain limit bounced to low memory (ie for highmem, or even
@@ -1351,7 +1344,7 @@ static void handle_bad_sector(struct bio *bio)
                        bdevname(bio->bi_bdev, b),
                        bio->bi_rw,
                        (unsigned long long)bio->bi_sector + bio_sectors(bio),
-                       (long long)(bio->bi_bdev->bd_inode->i_size >> 9));
+                       (long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9));
 
        set_bit(BIO_EOF, &bio->bi_flags);
 }
@@ -1404,7 +1397,7 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors)
                return 0;
 
        /* Test device or partition size, when known. */
-       maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
+       maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
        if (maxsector) {
                sector_t sector = bio->bi_sector;
 
index d22c4c55c40689c23b7d275fbb76af17c0b23efa..3c7a339fe3813483155f31b05ea5aa5cd3224a36 100644 (file)
@@ -153,20 +153,6 @@ struct io_context *get_io_context(gfp_t gfp_flags, int node)
 }
 EXPORT_SYMBOL(get_io_context);
 
-void copy_io_context(struct io_context **pdst, struct io_context **psrc)
-{
-       struct io_context *src = *psrc;
-       struct io_context *dst = *pdst;
-
-       if (src) {
-               BUG_ON(atomic_long_read(&src->refcount) == 0);
-               atomic_long_inc(&src->refcount);
-               put_io_context(dst);
-               *pdst = src;
-       }
-}
-EXPORT_SYMBOL(copy_io_context);
-
 static int __init blk_ioc_init(void)
 {
        iocontext_cachep = kmem_cache_create("blkdev_ioc",
index d4a586d8691ec5ed37311d1e3fc76aa0c310828f..5d5dbe47c2285ee7ccb5f3ca784f9cdb8cb6df3e 100644 (file)
@@ -205,6 +205,8 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                        unaligned = 1;
                        break;
                }
+               if (!iov[i].iov_len)
+                       return -EINVAL;
        }
 
        if (unaligned || (q->dma_pad_mask & len) || map_data)
index 119f07b74dc0c41d99c282c1299a80f5f0dfc8c0..cc3eb78e333acaf14eb27a4ae8e54737d816f255 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/hdreg.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
 
@@ -744,13 +743,13 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
                return 0;
        case BLKGETSIZE:
-               size = bdev->bd_inode->i_size;
+               size = i_size_read(bdev->bd_inode);
                if ((size >> 9) > ~0UL)
                        return -EFBIG;
                return compat_put_ulong(arg, size >> 9);
 
        case BLKGETSIZE64_32:
-               return compat_put_u64(arg, bdev->bd_inode->i_size);
+               return compat_put_u64(arg, i_size_read(bdev->bd_inode));
 
        case BLKTRACESETUP32:
        case BLKTRACESTART: /* compatible */
index 282e8308f7e2bbab837375daf5ad81cfae97ca5e..2569512830d3e65a8a73213879b591917bdd91c4 100644 (file)
@@ -429,7 +429,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
        q->nr_sorted--;
 
        boundary = q->end_sector;
-       stop_flags = REQ_SOFTBARRIER | REQ_HARDBARRIER | REQ_STARTED;
+       stop_flags = REQ_SOFTBARRIER | REQ_STARTED;
        list_for_each_prev(entry, &q->queue_head) {
                struct request *pos = list_entry_rq(entry);
 
@@ -691,7 +691,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
 void __elv_add_request(struct request_queue *q, struct request *rq, int where,
                       int plug)
 {
-       if (rq->cmd_flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
+       if (rq->cmd_flags & REQ_SOFTBARRIER) {
                /* barriers are scheduling boundary, update end_sector */
                if (rq->cmd_type == REQ_TYPE_FS ||
                    (rq->cmd_flags & REQ_DISCARD)) {
index d724ceb1d46535fee2fa3e65ca57cb09cb88997d..a9a302eba01e6a78b46e3af154c4f1b2a1c2c510 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/hdreg.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include <linux/blktrace_api.h>
 #include <asm/uaccess.h>
 
@@ -125,7 +124,7 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
        start >>= 9;
        len >>= 9;
 
-       if (start + len > (bdev->bd_inode->i_size >> 9))
+       if (start + len > (i_size_read(bdev->bd_inode) >> 9))
                return -EINVAL;
        if (secure)
                flags |= BLKDEV_DISCARD_SECURE;
@@ -242,6 +241,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                 * We need to set the startsect first, the driver may
                 * want to override it.
                 */
+               memset(&geo, 0, sizeof(geo));
                geo.start = get_start_sect(bdev);
                ret = disk->fops->getgeo(bdev, &geo);
                if (ret)
@@ -307,12 +307,12 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                ret = blkdev_reread_part(bdev);
                break;
        case BLKGETSIZE:
-               size = bdev->bd_inode->i_size;
+               size = i_size_read(bdev->bd_inode);
                if ((size >> 9) > ~0UL)
                        return -EFBIG;
                return put_ulong(arg, size >> 9);
        case BLKGETSIZE64:
-               return put_u64(arg, bdev->bd_inode->i_size);
+               return put_u64(arg, i_size_read(bdev->bd_inode));
        case BLKTRACESTART:
        case BLKTRACESTOP:
        case BLKTRACESETUP:
index a8b5a10eb5b04cc15cdd8ddd26ed23fe7c55bc78..4f4230b79bb6ee3c8164e462e40d4bdea3dc1fcd 100644 (file)
@@ -321,33 +321,47 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
        if (hdr->iovec_count) {
                const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
                size_t iov_data_len;
-               struct sg_iovec *iov;
+               struct sg_iovec *sg_iov;
+               struct iovec *iov;
+               int i;
 
-               iov = kmalloc(size, GFP_KERNEL);
-               if (!iov) {
+               sg_iov = kmalloc(size, GFP_KERNEL);
+               if (!sg_iov) {
                        ret = -ENOMEM;
                        goto out;
                }
 
-               if (copy_from_user(iov, hdr->dxferp, size)) {
-                       kfree(iov);
+               if (copy_from_user(sg_iov, hdr->dxferp, size)) {
+                       kfree(sg_iov);
                        ret = -EFAULT;
                        goto out;
                }
 
+               /*
+                * Sum up the vecs, making sure they don't overflow
+                */
+               iov = (struct iovec *) sg_iov;
+               iov_data_len = 0;
+               for (i = 0; i < hdr->iovec_count; i++) {
+                       if (iov_data_len + iov[i].iov_len < iov_data_len) {
+                               kfree(sg_iov);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       iov_data_len += iov[i].iov_len;
+               }
+
                /* SG_IO howto says that the shorter of the two wins */
-               iov_data_len = iov_length((struct iovec *)iov,
-                                         hdr->iovec_count);
                if (hdr->dxfer_len < iov_data_len) {
-                       hdr->iovec_count = iov_shorten((struct iovec *)iov,
+                       hdr->iovec_count = iov_shorten(iov,
                                                       hdr->iovec_count,
                                                       hdr->dxfer_len);
                        iov_data_len = hdr->dxfer_len;
                }
 
-               ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count,
+               ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count,
                                          iov_data_len, GFP_KERNEL);
-               kfree(iov);
+               kfree(sg_iov);
        } else if (hdr->dxfer_len)
                ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,
                                      GFP_KERNEL);
index de3078215fe6eadd89f31bfd3a86f426a4a18015..75586f1f86e7b27632b1250b2e4572135bf03e1c 100644 (file)
@@ -504,7 +504,6 @@ err:
 
 static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
 {
-       kobject_put(&pcrypt->pinst->kobj);
        free_cpumask_var(pcrypt->cb_cpumask->mask);
        kfree(pcrypt->cb_cpumask);
 
index 14cf9077bb2bcf4f01025518b11b0e87e072e9b5..f3ebb30f1b7fd9c7ed93d6328dbe4d8c54b1fd87 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_REGULATOR)               += regulator/
 
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
+obj-y                          += tty/
 obj-y                          += char/
 
 # gpu/ comes after char for AGP vs DRM startup
index 6355b575ee5ac22498b32953e0955cb2811e81ba..5df67f1d6c612537f10ac2fd84b6720911d16723 100644 (file)
@@ -80,7 +80,7 @@ int __init acpi_debugfs_init(void)
        if (!acpi_dir)
                goto err;
 
-       cm_dentry = debugfs_create_file("custom_method", S_IWUGO,
+       cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
                                        acpi_dir, NULL, &cm_fops);
        if (!cm_dentry)
                goto err;
index d050e073e57035a99b969c50205a4227ed6a8812..66aa4bee80a659712b75e8b3949678d56e8bd5a3 100644 (file)
@@ -2552,8 +2552,11 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
                 *
                 * If door lock fails, always clear sdev->locked to
                 * avoid this infinite loop.
+                *
+                * This may happen before SCSI scan is complete.  Make
+                * sure qc->dev->sdev isn't NULL before dereferencing.
                 */
-               if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+               if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
                        qc->dev->sdev->locked = 0;
 
                qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
@@ -3163,8 +3166,8 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
 
 /**
  *     ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ *     @shost: SCSI host of command to be sent
  *     @cmd: SCSI command to be sent
- *     @done: Completion function, called when command is complete
  *
  *     In some cases, this function translates SCSI commands into
  *     ATA taskfiles, and queues the taskfiles to be sent to
@@ -3174,37 +3177,36 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
  *     ATA and ATAPI devices appearing as SCSI devices.
  *
  *     LOCKING:
- *     Releases scsi-layer-held lock, and obtains host lock.
+ *     ATA host lock
  *
  *     RETURNS:
  *     Return value from __ata_scsi_queuecmd() if @cmd can be queued,
  *     0 otherwise.
  */
-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 {
        struct ata_port *ap;
        struct ata_device *dev;
        struct scsi_device *scsidev = cmd->device;
-       struct Scsi_Host *shost = scsidev->host;
        int rc = 0;
+       unsigned long irq_flags;
 
        ap = ata_shost_to_port(shost);
 
-       spin_unlock(shost->host_lock);
-       spin_lock(ap->lock);
+       spin_lock_irqsave(ap->lock, irq_flags);
 
        ata_scsi_dump_cdb(ap, cmd);
 
        dev = ata_scsi_find_dev(ap, scsidev);
        if (likely(dev))
-               rc = __ata_scsi_queuecmd(cmd, done, dev);
+               rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev);
        else {
                cmd->result = (DID_BAD_TARGET << 16);
-               done(cmd);
+               cmd->scsi_done(cmd);
        }
 
-       spin_unlock(ap->lock);
-       spin_lock(shost->host_lock);
+       spin_unlock_irqrestore(ap->lock, irq_flags);
+
        return rc;
 }
 
index eaf194138f219f187e819fd56f4cce86b0cc90f7..6bd9425ba5ab593ab11372fb6e2e966bf43ecd81 100644 (file)
@@ -142,7 +142,7 @@ static int autospeed;               /* Chip present which snoops speed changes */
 static int pio_mask = ATA_PIO4;        /* PIO range for autospeed devices */
 static int iordy_mask = 0xFFFFFFFF;    /* Use iordy if available */
 
-#ifdef PATA_WINBOND_VLB_MODULE
+#ifdef CONFIG_PATA_WINBOND_VLB_MODULE
 static int winbond = 1;                /* Set to probe Winbond controllers,
                                        give I/O port if non standard */
 #else
index 74b829817891de507178d868807ed981f8027635..fa1b95a9a7ff3268e6893877ac35718063368875 100644 (file)
@@ -652,8 +652,6 @@ static irqreturn_t octeon_cf_interrupt(int irq, void *dev_instance)
                struct octeon_cf_data *ocd;
 
                ap = host->ports[i];
-               ocd = ap->dev->platform_data;
-
                ocd = ap->dev->platform_data;
                cf_port = ap->private_data;
                dma_int.u64 =
index c21589986c695f38756d1ced8a13422acfa3cac9..8b677bbf2d37be97d37e89c57441e26807a55e87 100644 (file)
@@ -538,7 +538,7 @@ static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        return 0;
 }
 
-static void svia_configure(struct pci_dev *pdev)
+static void svia_configure(struct pci_dev *pdev, int board_id)
 {
        u8 tmp8;
 
@@ -577,7 +577,7 @@ static void svia_configure(struct pci_dev *pdev)
        }
 
        /*
-        * vt6421 has problems talking to some drives.  The following
+        * vt6420/1 has problems talking to some drives.  The following
         * is the fix from Joseph Chan <JosephChan@via.com.tw>.
         *
         * When host issues HOLD, device may send up to 20DW of data
@@ -596,8 +596,9 @@ static void svia_configure(struct pci_dev *pdev)
         *
         * https://bugzilla.kernel.org/show_bug.cgi?id=15173
         * http://article.gmane.org/gmane.linux.ide/46352
+        * http://thread.gmane.org/gmane.linux.kernel/1062139
         */
-       if (pdev->device == 0x3249) {
+       if (board_id == vt6420 || board_id == vt6421) {
                pci_read_config_byte(pdev, 0x52, &tmp8);
                tmp8 |= 1 << 2;
                pci_write_config_byte(pdev, 0x52, tmp8);
@@ -652,7 +653,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       svia_configure(pdev);
+       svia_configure(pdev, board_id);
 
        pci_set_master(pdev);
        return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
index 1a9332e4efe0847aea86548b2e58e9fcd77b1268..9a676ee308249c038757e5fba35b29847e4fb538 100644 (file)
@@ -1,6 +1,7 @@
 SOLOS_ATTR_RO(DriverVersion)
 SOLOS_ATTR_RO(APIVersion)
 SOLOS_ATTR_RO(FirmwareVersion)
+SOLOS_ATTR_RO(Version)
 // SOLOS_ATTR_RO(DspVersion)
 // SOLOS_ATTR_RO(CommonHandshake)
 SOLOS_ATTR_RO(Connected)
index f46138ab38b6c310fffc589681f727840a05c646..2e08c996fd30a6156e8a0a19e46966824d3d89df 100644 (file)
@@ -1161,6 +1161,14 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
                 major_ver, minor_ver, fpga_ver);
 
+       if (fpga_ver < 37 && (fpga_upgrade || firmware_upgrade ||
+                             db_fpga_upgrade || db_firmware_upgrade)) {
+               dev_warn(&dev->dev,
+                        "FPGA too old; cannot upgrade flash. Use JTAG.\n");
+               fpga_upgrade = firmware_upgrade = 0;
+               db_fpga_upgrade = db_firmware_upgrade = 0;
+       }
+
        if (card->fpga_version >= DMA_SUPPORTED){
                card->using_dma = 1;
        } else {
index 31b526661ec4d78346c3b6edd04b733705285797..ead3e79d6fcf10f684f8d8f55a30d7254356ff42 100644 (file)
@@ -475,20 +475,33 @@ End:
  */
 void dpm_resume_noirq(pm_message_t state)
 {
-       struct device *dev;
+       struct list_head list;
        ktime_t starttime = ktime_get();
 
+       INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        transition_started = false;
-       list_for_each_entry(dev, &dpm_list, power.entry)
+       while (!list_empty(&dpm_list)) {
+               struct device *dev = to_device(dpm_list.next);
+
+               get_device(dev);
                if (dev->power.status > DPM_OFF) {
                        int error;
 
                        dev->power.status = DPM_OFF;
+                       mutex_unlock(&dpm_list_mtx);
+
                        error = device_resume_noirq(dev, state);
+
+                       mutex_lock(&dpm_list_mtx);
                        if (error)
                                pm_dev_err(dev, state, " early", error);
                }
+               if (!list_empty(&dev->power.entry))
+                       list_move_tail(&dev->power.entry, &list);
+               put_device(dev);
+       }
+       list_splice(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
        dpm_show_time(starttime, state, "early");
        resume_device_irqs();
@@ -789,20 +802,33 @@ End:
  */
 int dpm_suspend_noirq(pm_message_t state)
 {
-       struct device *dev;
+       struct list_head list;
        ktime_t starttime = ktime_get();
        int error = 0;
 
+       INIT_LIST_HEAD(&list);
        suspend_device_irqs();
        mutex_lock(&dpm_list_mtx);
-       list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
+       while (!list_empty(&dpm_list)) {
+               struct device *dev = to_device(dpm_list.prev);
+
+               get_device(dev);
+               mutex_unlock(&dpm_list_mtx);
+
                error = device_suspend_noirq(dev, state);
+
+               mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, " late", error);
+                       put_device(dev);
                        break;
                }
                dev->power.status = DPM_OFF_IRQ;
+               if (!list_empty(&dev->power.entry))
+                       list_move(&dev->power.entry, &list);
+               put_device(dev);
        }
+       list_splice_tail(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
        if (error)
                dpm_resume_noirq(resume_event(state));
index 541e18879965d01e74081701b50f3e70c78fb1b5..528f6318ded155f03d464f611f20240dd1a90c95 100644 (file)
@@ -180,9 +180,6 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
                BUG();
                bio_endio(bio, -ENXIO);
                return 0;
-       } else if (bio->bi_rw & REQ_HARDBARRIER) {
-               bio_endio(bio, -EOPNOTSUPP);
-               return 0;
        } else if (bio->bi_io_vec == NULL) {
                printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
                BUG();
index 2cc4dda462794a3b2f304b0590880237511505b6..a67d0a611a8ac1d53ee16a00963ef19ade3487c8 100644 (file)
@@ -113,6 +113,8 @@ static struct board_type products[] = {
        {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
        {0x40910E11, "Smart Array 6i", &SA5_access},
        {0x3225103C, "Smart Array P600", &SA5_access},
+       {0x3223103C, "Smart Array P800", &SA5_access},
+       {0x3234103C, "Smart Array P400", &SA5_access},
        {0x3235103C, "Smart Array P400i", &SA5_access},
        {0x3211103C, "Smart Array E200i", &SA5_access},
        {0x3212103C, "Smart Array E200", &SA5_access},
@@ -3753,7 +3755,7 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
        for (i = 0; i < MAX_CONFIG_WAIT; i++) {
                if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
                        break;
-               msleep(10);
+               usleep_range(10000, 20000);
        }
 }
 
@@ -3937,10 +3939,9 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
        *board_id = ((subsystem_device_id << 16) & 0xffff0000) |
                        subsystem_vendor_id;
 
-       for (i = 0; i < ARRAY_SIZE(products); i++) {
+       for (i = 0; i < ARRAY_SIZE(products); i++)
                if (*board_id == products[i].board_id)
                        return i;
-       }
        dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
                *board_id);
        return -ENODEV;
@@ -3971,18 +3972,31 @@ static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
+static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
+       void __iomem *vaddr, int wait_for_ready)
+#define BOARD_READY 1
+#define BOARD_NOT_READY 0
 {
-       int i;
+       int i, iterations;
        u32 scratchpad;
 
-       for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
-               scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-               if (scratchpad == CCISS_FIRMWARE_READY)
-                       return 0;
+       if (wait_for_ready)
+               iterations = CCISS_BOARD_READY_ITERATIONS;
+       else
+               iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
+
+       for (i = 0; i < iterations; i++) {
+               scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+               if (wait_for_ready) {
+                       if (scratchpad == CCISS_FIRMWARE_READY)
+                               return 0;
+               } else {
+                       if (scratchpad != CCISS_FIRMWARE_READY)
+                               return 0;
+               }
                msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
        }
-       dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+       dev_warn(&pdev->dev, "board not ready, timed out.\n");
        return -ENODEV;
 }
 
@@ -4031,6 +4045,11 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
 static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
 {
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+
+       /* Limit commands in memory limited kdump scenario. */
+       if (reset_devices && h->max_commands > 32)
+               h->max_commands = 32;
+
        if (h->max_commands < 16) {
                dev_warn(&h->pdev->dev, "Controller reports "
                        "max supported commands of %d, an obvious lie. "
@@ -4148,7 +4167,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *h)
                err = -ENOMEM;
                goto err_out_free_res;
        }
-       err = cciss_wait_for_board_ready(h);
+       err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
        if (err)
                goto err_out_free_res;
        err = cciss_find_cfgtables(h);
@@ -4313,36 +4332,6 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
 #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
 #define cciss_noop(p) cciss_message(p, 3, 0)
 
-static __devinit int cciss_reset_msi(struct pci_dev *pdev)
-{
-/* the #defines are stolen from drivers/pci/msi.h. */
-#define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE          (1 << 15)
-
-       int pos;
-       u16 control = 0;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSI_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
-               }
-       }
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSIX_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI-X\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
-               }
-       }
-
-       return 0;
-}
-
 static int cciss_controller_hard_reset(struct pci_dev *pdev,
        void * __iomem vaddr, bool use_doorbell)
 {
@@ -4397,17 +4386,17 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
  * states or using the doorbell register. */
 static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
 {
-       u16 saved_config_space[32];
        u64 cfg_offset;
        u32 cfg_base_addr;
        u64 cfg_base_addr_index;
        void __iomem *vaddr;
        unsigned long paddr;
        u32 misc_fw_support, active_transport;
-       int rc, i;
+       int rc;
        CfgTable_struct __iomem *cfgtable;
        bool use_doorbell;
        u32 board_id;
+       u16 command_register;
 
        /* For controllers as old a the p600, this is very nearly
         * the same thing as
@@ -4417,14 +4406,6 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
         * pci_set_power_state(pci_dev, PCI_D0);
         * pci_restore_state(pci_dev);
         *
-        * but we can't use these nice canned kernel routines on
-        * kexec, because they also check the MSI/MSI-X state in PCI
-        * configuration space and do the wrong thing when it is
-        * set/cleared.  Also, the pci_save/restore_state functions
-        * violate the ordering requirements for restoring the
-        * configuration space from the CCISS document (see the
-        * comment below).  So we roll our own ....
-        *
         * For controllers newer than the P600, the pci power state
         * method of resetting doesn't work so we have another way
         * using the doorbell register.
@@ -4443,8 +4424,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
                return -ENODEV;
        }
 
-       for (i = 0; i < 32; i++)
-               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+       /* Save the PCI command register */
+       pci_read_config_word(pdev, 4, &command_register);
+       /* Turn the board off.  This is so that later pci_restore_state()
+        * won't turn the board on before the rest of config space is ready.
+        */
+       pci_disable_device(pdev);
+       pci_save_state(pdev);
 
        /* find the first memory BAR, so we can find the cfg table */
        rc = cciss_pci_find_memory_BAR(pdev, &paddr);
@@ -4479,26 +4465,32 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
        rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
        if (rc)
                goto unmap_cfgtable;
-
-       /* Restore the PCI configuration space.  The Open CISS
-        * Specification says, "Restore the PCI Configuration
-        * Registers, offsets 00h through 60h. It is important to
-        * restore the command register, 16-bits at offset 04h,
-        * last. Do not restore the configuration status register,
-        * 16-bits at offset 06h."  Note that the offset is 2*i.
-        */
-       for (i = 0; i < 32; i++) {
-               if (i == 2 || i == 3)
-                       continue;
-               pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+       pci_restore_state(pdev);
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "failed to enable device.\n");
+               goto unmap_cfgtable;
        }
-       wmb();
-       pci_write_config_word(pdev, 4, saved_config_space[2]);
+       pci_write_config_word(pdev, 4, command_register);
 
        /* Some devices (notably the HP Smart Array 5i Controller)
           need a little pause here */
        msleep(CCISS_POST_RESET_PAUSE_MSECS);
 
+       /* Wait for board to become not ready, then ready. */
+       dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+       rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+       if (rc) /* Don't bail, might be E500, etc. which can't be reset */
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become not ready\n");
+       rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
+       if (rc) {
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become ready\n");
+               goto unmap_cfgtable;
+       }
+       dev_info(&pdev->dev, "board ready.\n");
+
        /* Controller should be in simple mode at this point.  If it's not,
         * It means we're on one of those controllers which doesn't support
         * the doorbell reset method and on which the PCI power management reset
@@ -4539,8 +4531,6 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
                return 0; /* just try to do the kdump anyhow. */
        if (rc)
                return -ENODEV;
-       if (cciss_reset_msi(pdev))
-               return -ENODEV;
 
        /* Now try to get the controller to respond to a no-op */
        for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
@@ -4936,7 +4926,8 @@ static void __exit cciss_cleanup(void)
                }
        }
        kthread_stop(cciss_scan_thread);
-       remove_proc_entry("driver/cciss", NULL);
+       if (proc_cciss)
+               remove_proc_entry("driver/cciss", NULL);
        bus_unregister(&cciss_bus_type);
 }
 
index ae340ffc8f815de7cf1fdae7518890556826852d..4b8933d778f154169e191938d83c3b4115d291cc 100644 (file)
@@ -200,10 +200,14 @@ struct ctlr_info
  * the above.
  */
 #define CCISS_BOARD_READY_WAIT_SECS (120)
+#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
 #define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
 #define CCISS_BOARD_READY_ITERATIONS \
        ((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
                CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
+#define CCISS_BOARD_NOT_READY_ITERATIONS \
+       ((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
+               CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
 #define CCISS_POST_RESET_PAUSE_MSECS (3000)
 #define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
 #define CCISS_POST_RESET_NOOP_RETRIES (12)
index 575495f3c4b870d2085347f5015f72efc32adb2b..727d0225b7d049e9f529655c081c513267d248bc 100644 (file)
@@ -62,8 +62,8 @@ static int cciss_scsi_proc_info(
                int length,        /* length of data in buffer */
                int func);         /* 0 == read, 1 == write */
 
-static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
-               void (* done)(struct scsi_cmnd *));
+static int cciss_scsi_queue_command (struct Scsi_Host *h,
+                                    struct scsi_cmnd *cmd);
 static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
 static int cciss_eh_abort_handler(struct scsi_cmnd *);
 
@@ -1406,7 +1406,7 @@ static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *c,
 
 
 static int
-cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+cciss_scsi_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        ctlr_info_t *h;
        int rc;
@@ -1504,6 +1504,8 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
        return 0;
 }
 
+static DEF_SCSI_QCMD(cciss_scsi_queue_command)
+
 static void cciss_unregister_scsi(ctlr_info_t *h)
 {
        struct cciss_scsi_adapter_data_t *sa;
index ac04ef97eac29a0203e38d08a942c1733e5d9285..ba95cba192be8d1d00f7b7e9b47f1cb05d460470 100644 (file)
@@ -78,11 +78,10 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
        init_completion(&md_io.event);
        md_io.error = 0;
 
-       if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
-               rw |= REQ_HARDBARRIER;
+       if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
+               rw |= REQ_FUA;
        rw |= REQ_UNPLUG | REQ_SYNC;
 
- retry:
        bio = bio_alloc(GFP_NOIO, 1);
        bio->bi_bdev = bdev->md_bdev;
        bio->bi_sector = sector;
@@ -100,17 +99,6 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
        wait_for_completion(&md_io.event);
        ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
 
-       /* check for unsupported barrier op.
-        * would rather check on EOPNOTSUPP, but that is not reliable.
-        * don't try again for ANY return value != 0 */
-       if (unlikely((bio->bi_rw & REQ_HARDBARRIER) && !ok)) {
-               /* Try again with no barrier */
-               dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
-               set_bit(MD_NO_BARRIER, &mdev->flags);
-               rw &= ~REQ_HARDBARRIER;
-               bio_put(bio);
-               goto retry;
-       }
  out:
        bio_put(bio);
        return ok;
@@ -284,18 +272,32 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
        u32 xor_sum = 0;
 
        if (!get_ldev(mdev)) {
-               dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
+               dev_err(DEV,
+                       "disk is %s, cannot start al transaction (-%d +%d)\n",
+                       drbd_disk_str(mdev->state.disk), evicted, new_enr);
                complete(&((struct update_al_work *)w)->event);
                return 1;
        }
        /* do we have to do a bitmap write, first?
         * TODO reduce maximum latency:
         * submit both bios, then wait for both,
-        * instead of doing two synchronous sector writes. */
+        * instead of doing two synchronous sector writes.
+        * For now, we must not write the transaction,
+        * if we cannot write out the bitmap of the evicted extent. */
        if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
                drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
 
-       mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
+       /* The bitmap write may have failed, causing a state change. */
+       if (mdev->state.disk < D_INCONSISTENT) {
+               dev_err(DEV,
+                       "disk is %s, cannot write al transaction (-%d +%d)\n",
+                       drbd_disk_str(mdev->state.disk), evicted, new_enr);
+               complete(&((struct update_al_work *)w)->event);
+               put_ldev(mdev);
+               return 1;
+       }
+
+       mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */
        buffer = (struct al_transaction *)page_address(mdev->md_io_page);
 
        buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
@@ -739,7 +741,7 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
        unsigned int enr;
        unsigned long add = 0;
        char ppb[10];
-       int i;
+       int i, tmp;
 
        wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
 
@@ -747,7 +749,9 @@ void drbd_al_apply_to_bm(struct drbd_conf *mdev)
                enr = lc_element_by_index(mdev->act_log, i)->lc_number;
                if (enr == LC_FREE)
                        continue;
-               add += drbd_bm_ALe_set_all(mdev, enr);
+               tmp = drbd_bm_ALe_set_all(mdev, enr);
+               dynamic_dev_dbg(DEV, "AL: set %d bits in extent %u\n", tmp, enr);
+               add += tmp;
        }
 
        lc_unlock(mdev->act_log);
index 9bdcf4393c0aa9525c9c7918355cb9b985809a73..1ea1a34e78b281d8ff8658028b38e2f423716917 100644 (file)
@@ -114,11 +114,11 @@ struct drbd_conf;
 #define D_ASSERT(exp)  if (!(exp)) \
         dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
 
-#define ERR_IF(exp) if (({                             \
-       int _b = (exp) != 0;                            \
-       if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n",     \
-               __func__, #exp, __FILE__, __LINE__);    \
-        _b;                                            \
+#define ERR_IF(exp) if (({                                             \
+       int _b = (exp) != 0;                                            \
+       if (_b) dev_err(DEV, "ASSERT FAILED: %s: (%s) in %s:%d\n",      \
+                       __func__, #exp, __FILE__, __LINE__);            \
+       _b;                                                             \
        }))
 
 /* Defines to control fault insertion */
@@ -749,17 +749,12 @@ struct drbd_epoch {
 
 /* drbd_epoch flag bits */
 enum {
-       DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
-       DE_BARRIER_IN_NEXT_EPOCH_DONE,
-       DE_CONTAINS_A_BARRIER,
        DE_HAVE_BARRIER_NUMBER,
-       DE_IS_FINISHING,
 };
 
 enum epoch_event {
        EV_PUT,
        EV_GOT_BARRIER_NR,
-       EV_BARRIER_DONE,
        EV_BECAME_LAST,
        EV_CLEANUP = 32, /* used as flag */
 };
@@ -801,11 +796,6 @@ enum {
        __EE_CALL_AL_COMPLETE_IO,
        __EE_MAY_SET_IN_SYNC,
 
-       /* This epoch entry closes an epoch using a barrier.
-        * On sucessful completion, the epoch is released,
-        * and the P_BARRIER_ACK send. */
-       __EE_IS_BARRIER,
-
        /* In case a barrier failed,
         * we need to resubmit without the barrier flag. */
        __EE_RESUBMITTED,
@@ -820,7 +810,6 @@ enum {
 };
 #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
 #define EE_MAY_SET_IN_SYNC     (1<<__EE_MAY_SET_IN_SYNC)
-#define EE_IS_BARRIER          (1<<__EE_IS_BARRIER)
 #define        EE_RESUBMITTED         (1<<__EE_RESUBMITTED)
 #define EE_WAS_ERROR           (1<<__EE_WAS_ERROR)
 #define EE_HAS_DIGEST          (1<<__EE_HAS_DIGEST)
@@ -843,16 +832,15 @@ enum {
                                 * Gets cleared when the state.conn
                                 * goes into C_CONNECTED state. */
        WRITE_BM_AFTER_RESYNC,  /* A kmalloc() during resync failed */
-       NO_BARRIER_SUPP,        /* underlying block device doesn't implement barriers */
        CONSIDER_RESYNC,
 
-       MD_NO_BARRIER,          /* meta data device does not support barriers,
-                                  so don't even try */
+       MD_NO_FUA,              /* Users wants us to not use FUA/FLUSH on meta data dev */
        SUSPEND_IO,             /* suspend application io */
        BITMAP_IO,              /* suspend application io;
                                   once no more io in flight, start bitmap io */
        BITMAP_IO_QUEUED,       /* Started bitmap IO */
-       GO_DISKLESS,            /* Disk failed, local_cnt reached zero, we are going diskless */
+       GO_DISKLESS,            /* Disk is being detached, on io-error or admin request. */
+       WAS_IO_ERROR,           /* Local disk failed returned IO error */
        RESYNC_AFTER_NEG,       /* Resync after online grow after the attach&negotiate finished. */
        NET_CONGESTED,          /* The data socket is congested */
 
@@ -947,7 +935,6 @@ enum write_ordering_e {
        WO_none,
        WO_drain_io,
        WO_bdev_flush,
-       WO_bio_barrier
 };
 
 struct fifo_buffer {
@@ -1281,6 +1268,7 @@ extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
 extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
 extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
 extern void drbd_go_diskless(struct drbd_conf *mdev);
+extern void drbd_ldev_destroy(struct drbd_conf *mdev);
 
 
 /* Meta data layout
@@ -1798,17 +1786,17 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
        case EP_PASS_ON:
                if (!forcedetach) {
                        if (__ratelimit(&drbd_ratelimit_state))
-                               dev_err(DEV, "Local IO failed in %s."
-                                            "Passing error on...\n", where);
+                               dev_err(DEV, "Local IO failed in %s.\n", where);
                        break;
                }
                /* NOTE fall through to detach case if forcedetach set */
        case EP_DETACH:
        case EP_CALL_HELPER:
+               set_bit(WAS_IO_ERROR, &mdev->flags);
                if (mdev->state.disk > D_FAILED) {
                        _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
-                       dev_err(DEV, "Local IO failed in %s."
-                                    "Detaching...\n", where);
+                       dev_err(DEV,
+                               "Local IO failed in %s. Detaching...\n", where);
                }
                break;
        }
@@ -1874,7 +1862,7 @@ static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
 static inline sector_t drbd_get_capacity(struct block_device *bdev)
 {
        /* return bdev ? get_capacity(bdev->bd_disk) : 0; */
-       return bdev ? bdev->bd_inode->i_size >> 9 : 0;
+       return bdev ? i_size_read(bdev->bd_inode) >> 9 : 0;
 }
 
 /**
@@ -2127,7 +2115,11 @@ static inline void put_ldev(struct drbd_conf *mdev)
        __release(local);
        D_ASSERT(i >= 0);
        if (i == 0) {
+               if (mdev->state.disk == D_DISKLESS)
+                       /* even internal references gone, safe to destroy */
+                       drbd_ldev_destroy(mdev);
                if (mdev->state.disk == D_FAILED)
+                       /* all application IO references gone. */
                        drbd_go_diskless(mdev);
                wake_up(&mdev->misc_wait);
        }
@@ -2138,6 +2130,10 @@ static inline int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_stat
 {
        int io_allowed;
 
+       /* never get a reference while D_DISKLESS */
+       if (mdev->state.disk == D_DISKLESS)
+               return 0;
+
        atomic_inc(&mdev->local_cnt);
        io_allowed = (mdev->state.disk >= mins);
        if (!io_allowed)
@@ -2406,12 +2402,12 @@ static inline void drbd_md_flush(struct drbd_conf *mdev)
 {
        int r;
 
-       if (test_bit(MD_NO_BARRIER, &mdev->flags))
+       if (test_bit(MD_NO_FUA, &mdev->flags))
                return;
 
        r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL);
        if (r) {
-               set_bit(MD_NO_BARRIER, &mdev->flags);
+               set_bit(MD_NO_FUA, &mdev->flags);
                dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
        }
 }
index 25c7a73c50621734cf22fda0654e93825e08e0ca..6be5401d0e88fd193b1af75c303c8140d4f6ccd3 100644 (file)
@@ -835,6 +835,15 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state
            ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN)
                ns.conn = os.conn;
 
+       /* we cannot fail (again) if we already detached */
+       if (ns.disk == D_FAILED && os.disk == D_DISKLESS)
+               ns.disk = D_DISKLESS;
+
+       /* if we are only D_ATTACHING yet,
+        * we can (and should) go directly to D_DISKLESS. */
+       if (ns.disk == D_FAILED && os.disk == D_ATTACHING)
+               ns.disk = D_DISKLESS;
+
        /* After C_DISCONNECTING only C_STANDALONE may follow */
        if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
                ns.conn = os.conn;
@@ -1056,7 +1065,15 @@ int __drbd_set_state(struct drbd_conf *mdev,
            !test_and_set_bit(CONFIG_PENDING, &mdev->flags))
                set_bit(DEVICE_DYING, &mdev->flags);
 
-       mdev->state.i = ns.i;
+       /* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
+        * on the ldev here, to be sure the transition -> D_DISKLESS resp.
+        * drbd_ldev_destroy() won't happen before our corresponding
+        * after_state_ch works run, where we put_ldev again. */
+       if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
+           (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
+               atomic_inc(&mdev->local_cnt);
+
+       mdev->state = ns;
        wake_up(&mdev->misc_wait);
        wake_up(&mdev->state_wait);
 
@@ -1268,7 +1285,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
                        if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
                                drbd_uuid_new_current(mdev);
                                clear_bit(NEW_CUR_UUID, &mdev->flags);
-                               drbd_md_sync(mdev);
                        }
                        spin_lock_irq(&mdev->req_lock);
                        _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
@@ -1365,63 +1381,64 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
            os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
                drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
 
-       /* first half of local IO error */
-       if (os.disk > D_FAILED && ns.disk == D_FAILED) {
-               enum drbd_io_error_p eh = EP_PASS_ON;
+       /* first half of local IO error, failure to attach,
+        * or administrative detach */
+       if (os.disk != D_FAILED && ns.disk == D_FAILED) {
+               enum drbd_io_error_p eh;
+               int was_io_error;
+               /* corresponding get_ldev was in __drbd_set_state, to serialize
+                * our cleanup here with the transition to D_DISKLESS,
+                * so it is safe to dreference ldev here. */
+               eh = mdev->ldev->dc.on_io_error;
+               was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
+
+               /* current state still has to be D_FAILED,
+                * there is only one way out: to D_DISKLESS,
+                * and that may only happen after our put_ldev below. */
+               if (mdev->state.disk != D_FAILED)
+                       dev_err(DEV,
+                               "ASSERT FAILED: disk is %s during detach\n",
+                               drbd_disk_str(mdev->state.disk));
 
                if (drbd_send_state(mdev))
-                       dev_warn(DEV, "Notified peer that my disk is broken.\n");
+                       dev_warn(DEV, "Notified peer that I am detaching my disk\n");
                else
-                       dev_err(DEV, "Sending state for drbd_io_error() failed\n");
+                       dev_err(DEV, "Sending state for detaching disk failed\n");
 
                drbd_rs_cancel_all(mdev);
 
-               if (get_ldev_if_state(mdev, D_FAILED)) {
-                       eh = mdev->ldev->dc.on_io_error;
-                       put_ldev(mdev);
-               }
-               if (eh == EP_CALL_HELPER)
+               /* In case we want to get something to stable storage still,
+                * this may be the last chance.
+                * Following put_ldev may transition to D_DISKLESS. */
+               drbd_md_sync(mdev);
+               put_ldev(mdev);
+
+               if (was_io_error && eh == EP_CALL_HELPER)
                        drbd_khelper(mdev, "local-io-error");
        }
 
+        /* second half of local IO error, failure to attach,
+         * or administrative detach,
+         * after local_cnt references have reached zero again */
+        if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
+                /* We must still be diskless,
+                 * re-attach has to be serialized with this! */
+                if (mdev->state.disk != D_DISKLESS)
+                        dev_err(DEV,
+                                "ASSERT FAILED: disk is %s while going diskless\n",
+                                drbd_disk_str(mdev->state.disk));
 
-       /* second half of local IO error handling,
-        * after local_cnt references have reached zero: */
-       if (os.disk == D_FAILED && ns.disk == D_DISKLESS) {
-               mdev->rs_total = 0;
-               mdev->rs_failed = 0;
-               atomic_set(&mdev->rs_pending_cnt, 0);
-       }
-
-       if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
-               /* We must still be diskless,
-                * re-attach has to be serialized with this! */
-               if (mdev->state.disk != D_DISKLESS)
-                       dev_err(DEV,
-                               "ASSERT FAILED: disk is %s while going diskless\n",
-                               drbd_disk_str(mdev->state.disk));
+                mdev->rs_total = 0;
+                mdev->rs_failed = 0;
+                atomic_set(&mdev->rs_pending_cnt, 0);
 
-               /* we cannot assert local_cnt == 0 here, as get_ldev_if_state
-                * will inc/dec it frequently. Since we became D_DISKLESS, no
-                * one has touched the protected members anymore, though, so we
-                * are safe to free them here. */
                if (drbd_send_state(mdev))
-                       dev_warn(DEV, "Notified peer that I detached my disk.\n");
+                       dev_warn(DEV, "Notified peer that I'm now diskless.\n");
                else
-                       dev_err(DEV, "Sending state for detach failed\n");
-
-               lc_destroy(mdev->resync);
-               mdev->resync = NULL;
-               lc_destroy(mdev->act_log);
-               mdev->act_log = NULL;
-               __no_warn(local,
-                       drbd_free_bc(mdev->ldev);
-                       mdev->ldev = NULL;);
-
-               if (mdev->md_io_tmpp) {
-                       __free_page(mdev->md_io_tmpp);
-                       mdev->md_io_tmpp = NULL;
-               }
+                       dev_err(DEV, "Sending state for being diskless failed\n");
+               /* corresponding get_ldev in __drbd_set_state
+                * this may finaly trigger drbd_ldev_destroy. */
+               put_ldev(mdev);
        }
 
        /* Disks got bigger while they were detached */
@@ -2772,11 +2789,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
 
        drbd_set_defaults(mdev);
 
-       /* for now, we do NOT yet support it,
-        * even though we start some framework
-        * to eventually support barriers */
-       set_bit(NO_BARRIER_SUPP, &mdev->flags);
-
        atomic_set(&mdev->ap_bio_cnt, 0);
        atomic_set(&mdev->ap_pending_cnt, 0);
        atomic_set(&mdev->rs_pending_cnt, 0);
@@ -2842,7 +2854,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
        drbd_thread_init(mdev, &mdev->asender, drbd_asender);
 
        mdev->agreed_pro_version = PRO_VERSION_MAX;
-       mdev->write_ordering = WO_bio_barrier;
+       mdev->write_ordering = WO_bdev_flush;
        mdev->resync_wenr = LC_FREE;
 }
 
@@ -2899,7 +2911,6 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev)
        D_ASSERT(list_empty(&mdev->resync_work.list));
        D_ASSERT(list_empty(&mdev->unplug_work.list));
        D_ASSERT(list_empty(&mdev->go_diskless.list));
-
 }
 
 
@@ -3660,6 +3671,8 @@ void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local)
 
        get_random_bytes(&val, sizeof(u64));
        _drbd_uuid_set(mdev, UI_CURRENT, val);
+       /* get it to stable storage _now_ */
+       drbd_md_sync(mdev);
 }
 
 void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
@@ -3756,19 +3769,31 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused)
        return 1;
 }
 
+void drbd_ldev_destroy(struct drbd_conf *mdev)
+{
+       lc_destroy(mdev->resync);
+       mdev->resync = NULL;
+       lc_destroy(mdev->act_log);
+       mdev->act_log = NULL;
+       __no_warn(local,
+               drbd_free_bc(mdev->ldev);
+               mdev->ldev = NULL;);
+
+       if (mdev->md_io_tmpp) {
+               __free_page(mdev->md_io_tmpp);
+               mdev->md_io_tmpp = NULL;
+       }
+       clear_bit(GO_DISKLESS, &mdev->flags);
+}
+
 static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused)
 {
        D_ASSERT(mdev->state.disk == D_FAILED);
        /* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
         * inc/dec it frequently. Once we are D_DISKLESS, no one will touch
-        * the protected members anymore, though, so in the after_state_ch work
-        * it will be safe to free them. */
+        * the protected members anymore, though, so once put_ldev reaches zero
+        * again, it will be safe to free them. */
        drbd_force_state(mdev, NS(disk, D_DISKLESS));
-       /* We need to wait for return of references checked out while we still
-        * have been D_FAILED, though (drbd_md_sync, bitmap io). */
-       wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
-
-       clear_bit(GO_DISKLESS, &mdev->flags);
        return 1;
 }
 
@@ -3777,9 +3802,6 @@ void drbd_go_diskless(struct drbd_conf *mdev)
        D_ASSERT(mdev->state.disk == D_FAILED);
        if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
                drbd_queue_work(&mdev->data.work, &mdev->go_diskless);
-               /* don't drbd_queue_work_front,
-                * we need to serialize with the after_state_ch work
-                * of the -> D_FAILED transition. */
 }
 
 /**
index 87925e97e613ac34de1bc6edad9d54b8de5c47bf..29e5c70e4e26c7f6e35b8bb1bec0b7f65442f3a0 100644 (file)
@@ -870,6 +870,11 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
                retcode = ERR_DISK_CONFIGURED;
                goto fail;
        }
+       /* It may just now have detached because of IO error.  Make sure
+        * drbd_ldev_destroy is done already, we may end up here very fast,
+        * e.g. if someone calls attach from the on-io-error handler,
+        * to realize a "hot spare" feature (not that I'd recommend that) */
+       wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
 
        /* allocation not in the IO path, cqueue thread context */
        nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
@@ -1098,9 +1103,9 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        /* Reset the "barriers don't work" bits here, then force meta data to
         * be written, to ensure we determine if barriers are supported. */
        if (nbc->dc.no_md_flush)
-               set_bit(MD_NO_BARRIER, &mdev->flags);
+               set_bit(MD_NO_FUA, &mdev->flags);
        else
-               clear_bit(MD_NO_BARRIER, &mdev->flags);
+               clear_bit(MD_NO_FUA, &mdev->flags);
 
        /* Point of no return reached.
         * Devices and memory are no longer released by error cleanup below.
@@ -1112,8 +1117,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        nbc = NULL;
        resync_lru = NULL;
 
-       mdev->write_ordering = WO_bio_barrier;
-       drbd_bump_write_ordering(mdev, WO_bio_barrier);
+       mdev->write_ordering = WO_bdev_flush;
+       drbd_bump_write_ordering(mdev, WO_bdev_flush);
 
        if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
                set_bit(CRASHED_PRIMARY, &mdev->flags);
@@ -1262,7 +1267,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
  force_diskless_dec:
        put_ldev(mdev);
  force_diskless:
-       drbd_force_state(mdev, NS(disk, D_DISKLESS));
+       drbd_force_state(mdev, NS(disk, D_FAILED));
        drbd_md_sync(mdev);
  release_bdev2_fail:
        if (nbc)
@@ -1285,10 +1290,19 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        return 0;
 }
 
+/* Detaching the disk is a process in multiple stages.  First we need to lock
+ * out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
+ * Then we transition to D_DISKLESS, and wait for put_ldev() to return all
+ * internal references as well.
+ * Only then we have finally detached. */
 static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
                          struct drbd_nl_cfg_reply *reply)
 {
+       drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
        reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
+       if (mdev->state.disk == D_DISKLESS)
+               wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+       drbd_resume_io(mdev);
        return 0;
 }
 
@@ -1953,7 +1967,6 @@ static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
                drbd_uuid_new_current(mdev);
                clear_bit(NEW_CUR_UUID, &mdev->flags);
-               drbd_md_sync(mdev);
        }
        drbd_suspend_io(mdev);
        reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
index ad325c5d0ce19c48612b68cc22f096bf602319c0..7e6ac307e2dec3ba1c9de2f825d0b1c9cbbbf9af 100644 (file)
@@ -158,7 +158,6 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
                [WO_none] = 'n',
                [WO_drain_io] = 'd',
                [WO_bdev_flush] = 'f',
-               [WO_bio_barrier] = 'b',
        };
 
        seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
index efd6169acf2f04bf758c68ceee419549351c7e64..89d8a7cc4054ba627b670a8786e05b1824f5a8b3 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/memcontrol.h>
 #include <linux/mm_inline.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/pkt_sched.h>
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
 #include "drbd_vli.h"
 
-struct flush_work {
-       struct drbd_work w;
-       struct drbd_epoch *epoch;
-};
-
 enum finish_epoch {
        FE_STILL_LIVE,
        FE_DESTROYED,
@@ -66,16 +60,6 @@ static int drbd_do_auth(struct drbd_conf *mdev);
 static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
 static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
 
-static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
-{
-       struct drbd_epoch *prev;
-       spin_lock(&mdev->epoch_lock);
-       prev = list_entry(epoch->list.prev, struct drbd_epoch, list);
-       if (prev == epoch || prev == mdev->current_epoch)
-               prev = NULL;
-       spin_unlock(&mdev->epoch_lock);
-       return prev;
-}
 
 #define GFP_TRY        (__GFP_HIGHMEM | __GFP_NOWARN)
 
@@ -981,7 +965,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi
        return TRUE;
 }
 
-static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+static void drbd_flush(struct drbd_conf *mdev)
 {
        int rv;
 
@@ -997,24 +981,6 @@ static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct d
                }
                put_ldev(mdev);
        }
-
-       return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
-}
-
-static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
-       struct flush_work *fw = (struct flush_work *)w;
-       struct drbd_epoch *epoch = fw->epoch;
-
-       kfree(w);
-
-       if (!test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags))
-               drbd_flush_after_epoch(mdev, epoch);
-
-       drbd_may_finish_epoch(mdev, epoch, EV_PUT |
-                             (mdev->state.conn < C_CONNECTED ? EV_CLEANUP : 0));
-
-       return 1;
 }
 
 /**
@@ -1027,15 +993,13 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
                                               struct drbd_epoch *epoch,
                                               enum epoch_event ev)
 {
-       int finish, epoch_size;
+       int epoch_size;
        struct drbd_epoch *next_epoch;
-       int schedule_flush = 0;
        enum finish_epoch rv = FE_STILL_LIVE;
 
        spin_lock(&mdev->epoch_lock);
        do {
                next_epoch = NULL;
-               finish = 0;
 
                epoch_size = atomic_read(&epoch->epoch_size);
 
@@ -1045,16 +1009,6 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
                        break;
                case EV_GOT_BARRIER_NR:
                        set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
-
-                       /* Special case: If we just switched from WO_bio_barrier to
-                          WO_bdev_flush we should not finish the current epoch */
-                       if (test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) && epoch_size == 1 &&
-                           mdev->write_ordering != WO_bio_barrier &&
-                           epoch == mdev->current_epoch)
-                               clear_bit(DE_CONTAINS_A_BARRIER, &epoch->flags);
-                       break;
-               case EV_BARRIER_DONE:
-                       set_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags);
                        break;
                case EV_BECAME_LAST:
                        /* nothing to do*/
@@ -1063,23 +1017,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
 
                if (epoch_size != 0 &&
                    atomic_read(&epoch->active) == 0 &&
-                   test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) &&
-                   epoch->list.prev == &mdev->current_epoch->list &&
-                   !test_bit(DE_IS_FINISHING, &epoch->flags)) {
-                       /* Nearly all conditions are met to finish that epoch... */
-                       if (test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ||
-                           mdev->write_ordering == WO_none ||
-                           (epoch_size == 1 && test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) ||
-                           ev & EV_CLEANUP) {
-                               finish = 1;
-                               set_bit(DE_IS_FINISHING, &epoch->flags);
-                       } else if (!test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) &&
-                                mdev->write_ordering == WO_bio_barrier) {
-                               atomic_inc(&epoch->active);
-                               schedule_flush = 1;
-                       }
-               }
-               if (finish) {
+                   test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags)) {
                        if (!(ev & EV_CLEANUP)) {
                                spin_unlock(&mdev->epoch_lock);
                                drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
@@ -1102,6 +1040,7 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
                                /* atomic_set(&epoch->active, 0); is already zero */
                                if (rv == FE_STILL_LIVE)
                                        rv = FE_RECYCLED;
+                               wake_up(&mdev->ee_wait);
                        }
                }
 
@@ -1113,22 +1052,6 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev,
 
        spin_unlock(&mdev->epoch_lock);
 
-       if (schedule_flush) {
-               struct flush_work *fw;
-               fw = kmalloc(sizeof(*fw), GFP_ATOMIC);
-               if (fw) {
-                       fw->w.cb = w_flush;
-                       fw->epoch = epoch;
-                       drbd_queue_work(&mdev->data.work, &fw->w);
-               } else {
-                       dev_warn(DEV, "Could not kmalloc a flush_work obj\n");
-                       set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
-                       /* That is not a recursion, only one level */
-                       drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
-                       drbd_may_finish_epoch(mdev, epoch, EV_PUT);
-               }
-       }
-
        return rv;
 }
 
@@ -1144,19 +1067,16 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo)
                [WO_none] = "none",
                [WO_drain_io] = "drain",
                [WO_bdev_flush] = "flush",
-               [WO_bio_barrier] = "barrier",
        };
 
        pwo = mdev->write_ordering;
        wo = min(pwo, wo);
-       if (wo == WO_bio_barrier && mdev->ldev->dc.no_disk_barrier)
-               wo = WO_bdev_flush;
        if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
                wo = WO_drain_io;
        if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
                wo = WO_none;
        mdev->write_ordering = wo;
-       if (pwo != mdev->write_ordering || wo == WO_bio_barrier)
+       if (pwo != mdev->write_ordering || wo == WO_bdev_flush)
                dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
 }
 
@@ -1192,7 +1112,7 @@ next_bio:
        bio->bi_sector = sector;
        bio->bi_bdev = mdev->ldev->backing_bdev;
        /* we special case some flags in the multi-bio case, see below
-        * (REQ_UNPLUG, REQ_HARDBARRIER) */
+        * (REQ_UNPLUG) */
        bio->bi_rw = rw;
        bio->bi_private = e;
        bio->bi_end_io = drbd_endio_sec;
@@ -1226,11 +1146,6 @@ next_bio:
                        bio->bi_rw &= ~REQ_UNPLUG;
 
                drbd_generic_make_request(mdev, fault_type, bio);
-
-               /* strip off REQ_HARDBARRIER,
-                * unless it is the first or last bio */
-               if (bios && bios->bi_next)
-                       bios->bi_rw &= ~REQ_HARDBARRIER;
        } while (bios);
        maybe_kick_lo(mdev);
        return 0;
@@ -1244,45 +1159,9 @@ fail:
        return -ENOMEM;
 }
 
-/**
- * w_e_reissue() - Worker callback; Resubmit a bio, without REQ_HARDBARRIER set
- * @mdev:      DRBD device.
- * @w:         work object.
- * @cancel:    The connection will be closed anyways (unused in this callback)
- */
-int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __releases(local)
-{
-       struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
-       /* We leave DE_CONTAINS_A_BARRIER and EE_IS_BARRIER in place,
-          (and DE_BARRIER_IN_NEXT_EPOCH_ISSUED in the previous Epoch)
-          so that we can finish that epoch in drbd_may_finish_epoch().
-          That is necessary if we already have a long chain of Epochs, before
-          we realize that REQ_HARDBARRIER is actually not supported */
-
-       /* As long as the -ENOTSUPP on the barrier is reported immediately
-          that will never trigger. If it is reported late, we will just
-          print that warning and continue correctly for all future requests
-          with WO_bdev_flush */
-       if (previous_epoch(mdev, e->epoch))
-               dev_warn(DEV, "Write ordering was not enforced (one time event)\n");
-
-       /* we still have a local reference,
-        * get_ldev was done in receive_Data. */
-
-       e->w.cb = e_end_block;
-       if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_DT_WR) != 0) {
-               /* drbd_submit_ee fails for one reason only:
-                * if was not able to allocate sufficient bios.
-                * requeue, try again later. */
-               e->w.cb = w_e_reissue;
-               drbd_queue_work(&mdev->data.work, &e->w);
-       }
-       return 1;
-}
-
 static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-       int rv, issue_flush;
+       int rv;
        struct p_barrier *p = &mdev->data.rbuf.barrier;
        struct drbd_epoch *epoch;
 
@@ -1300,44 +1179,40 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign
         * Therefore we must send the barrier_ack after the barrier request was
         * completed. */
        switch (mdev->write_ordering) {
-       case WO_bio_barrier:
        case WO_none:
                if (rv == FE_RECYCLED)
                        return TRUE;
-               break;
+
+               /* receiver context, in the writeout path of the other node.
+                * avoid potential distributed deadlock */
+               epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+               if (epoch)
+                       break;
+               else
+                       dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
+                       /* Fall through */
 
        case WO_bdev_flush:
        case WO_drain_io:
-               if (rv == FE_STILL_LIVE) {
-                       set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
-                       drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
-                       rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
-               }
-               if (rv == FE_RECYCLED)
-                       return TRUE;
-
-               /* The asender will send all the ACKs and barrier ACKs out, since
-                  all EEs moved from the active_ee to the done_ee. We need to
-                  provide a new epoch object for the EEs that come in soon */
-               break;
-       }
-
-       /* receiver context, in the writeout path of the other node.
-        * avoid potential distributed deadlock */
-       epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
-       if (!epoch) {
-               dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
-               issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
                drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
-               if (issue_flush) {
-                       rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
-                       if (rv == FE_RECYCLED)
-                               return TRUE;
+               drbd_flush(mdev);
+
+               if (atomic_read(&mdev->current_epoch->epoch_size)) {
+                       epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+                       if (epoch)
+                               break;
                }
 
-               drbd_wait_ee_list_empty(mdev, &mdev->done_ee);
+               epoch = mdev->current_epoch;
+               wait_event(mdev->ee_wait, atomic_read(&epoch->epoch_size) == 0);
+
+               D_ASSERT(atomic_read(&epoch->active) == 0);
+               D_ASSERT(epoch->flags == 0);
 
                return TRUE;
+       default:
+               dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering);
+               return FALSE;
        }
 
        epoch->flags = 0;
@@ -1652,15 +1527,8 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
        sector_t sector = e->sector;
-       struct drbd_epoch *epoch;
        int ok = 1, pcmd;
 
-       if (e->flags & EE_IS_BARRIER) {
-               epoch = previous_epoch(mdev, e->epoch);
-               if (epoch)
-                       drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + (cancel ? EV_CLEANUP : 0));
-       }
-
        if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
                if (likely((e->flags & EE_WAS_ERROR) == 0)) {
                        pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
@@ -1817,27 +1685,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
        e->epoch = mdev->current_epoch;
        atomic_inc(&e->epoch->epoch_size);
        atomic_inc(&e->epoch->active);
-
-       if (mdev->write_ordering == WO_bio_barrier && atomic_read(&e->epoch->epoch_size) == 1) {
-               struct drbd_epoch *epoch;
-               /* Issue a barrier if we start a new epoch, and the previous epoch
-                  was not a epoch containing a single request which already was
-                  a Barrier. */
-               epoch = list_entry(e->epoch->list.prev, struct drbd_epoch, list);
-               if (epoch == e->epoch) {
-                       set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
-                       rw |= REQ_HARDBARRIER;
-                       e->flags |= EE_IS_BARRIER;
-               } else {
-                       if (atomic_read(&epoch->epoch_size) > 1 ||
-                           !test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) {
-                               set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
-                               set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
-                               rw |= REQ_HARDBARRIER;
-                               e->flags |= EE_IS_BARRIER;
-                       }
-               }
-       }
        spin_unlock(&mdev->epoch_lock);
 
        dp_flags = be32_to_cpu(p->dp_flags);
@@ -1995,10 +1842,11 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                break;
        }
 
-       if (mdev->state.pdsk == D_DISKLESS) {
+       if (mdev->state.pdsk < D_INCONSISTENT) {
                /* In case we have the only disk of the cluster, */
                drbd_set_out_of_sync(mdev, e->sector, e->size);
                e->flags |= EE_CALL_AL_COMPLETE_IO;
+               e->flags &= ~EE_MAY_SET_IN_SYNC;
                drbd_al_begin_io(mdev, e->sector);
        }
 
@@ -3362,7 +3210,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                if (ns.conn == C_MASK) {
                        ns.conn = C_CONNECTED;
                        if (mdev->state.disk == D_NEGOTIATING) {
-                               drbd_force_state(mdev, NS(disk, D_DISKLESS));
+                               drbd_force_state(mdev, NS(disk, D_FAILED));
                        } else if (peer_state.disk == D_NEGOTIATING) {
                                dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
                                peer_state.disk = D_DISKLESS;
index 9e91a2545fc869273d39ca9737904e56d5f203b9..11a75d32a2e27f0d78c26b511921780f4d336264 100644 (file)
@@ -258,7 +258,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
                if (!hlist_unhashed(&req->colision))
                        hlist_del(&req->colision);
                else
-                       D_ASSERT((s & RQ_NET_MASK) == 0);
+                       D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
 
                /* for writes we need to do some extra housekeeping */
                if (rw == WRITE)
@@ -813,7 +813,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)
                             mdev->state.conn >= C_CONNECTED));
 
        if (!(local || remote) && !is_susp(mdev->state)) {
-               dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+               if (__ratelimit(&drbd_ratelimit_state))
+                       dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
                goto fail_free_complete;
        }
 
@@ -942,12 +943,21 @@ allocate_barrier:
        if (local) {
                req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
 
-               if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
-                                    : rw == READ  ? DRBD_FAULT_DT_RD
-                                    :               DRBD_FAULT_DT_RA))
+               /* State may have changed since we grabbed our reference on the
+                * mdev->ldev member. Double check, and short-circuit to endio.
+                * In case the last activity log transaction failed to get on
+                * stable storage, and this is a WRITE, we may not even submit
+                * this bio. */
+               if (get_ldev(mdev)) {
+                       if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
+                                            : rw == READ  ? DRBD_FAULT_DT_RD
+                                            :               DRBD_FAULT_DT_RA))
+                               bio_endio(req->private_bio, -EIO);
+                       else
+                               generic_make_request(req->private_bio);
+                       put_ldev(mdev);
+               } else
                        bio_endio(req->private_bio, -EIO);
-               else
-                       generic_make_request(req->private_bio);
        }
 
        /* we need to plug ALWAYS since we possibly need to kick lo_dev.
@@ -1022,20 +1032,6 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio)
                return 0;
        }
 
-       /* Reject barrier requests if we know the underlying device does
-        * not support them.
-        * XXX: Need to get this info from peer as well some how so we
-        * XXX: reject if EITHER side/data/metadata area does not support them.
-        *
-        * because of those XXX, this is not yet enabled,
-        * i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit.
-        */
-       if (unlikely(bio->bi_rw & REQ_HARDBARRIER) && test_bit(NO_BARRIER_SUPP, &mdev->flags)) {
-               /* dev_warn(DEV, "Rejecting barrier request as underlying device does not support\n"); */
-               bio_endio(bio, -EOPNOTSUPP);
-               return 0;
-       }
-
        /*
         * what we "blindly" assume:
         */
index 108d58015cd119a6e85873095acab12ab011a6cc..47d223c2409c8cebbd233103d8ff1790dfae833c 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/drbd.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
 #include <linux/memcontrol.h>
@@ -102,12 +101,6 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local)
        put_ldev(mdev);
 }
 
-static int is_failed_barrier(int ee_flags)
-{
-       return (ee_flags & (EE_IS_BARRIER|EE_WAS_ERROR|EE_RESUBMITTED))
-                       == (EE_IS_BARRIER|EE_WAS_ERROR);
-}
-
 /* writes on behalf of the partner, or resync writes,
  * "submitted" by the receiver, final stage.  */
 static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(local)
@@ -119,21 +112,6 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
        int is_syncer_req;
        int do_al_complete_io;
 
-       /* if this is a failed barrier request, disable use of barriers,
-        * and schedule for resubmission */
-       if (is_failed_barrier(e->flags)) {
-               drbd_bump_write_ordering(mdev, WO_bdev_flush);
-               spin_lock_irqsave(&mdev->req_lock, flags);
-               list_del(&e->w.list);
-               e->flags = (e->flags & ~EE_WAS_ERROR) | EE_RESUBMITTED;
-               e->w.cb = w_e_reissue;
-               /* put_ldev actually happens below, once we come here again. */
-               __release(local);
-               spin_unlock_irqrestore(&mdev->req_lock, flags);
-               drbd_queue_work(&mdev->data.work, &e->w);
-               return;
-       }
-
        D_ASSERT(e->block_id != ID_VACANT);
 
        /* after we moved e to done_ee,
@@ -925,7 +903,7 @@ out:
        drbd_md_sync(mdev);
 
        if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
-               dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n");
+               dev_info(DEV, "Writing the whole bitmap\n");
                drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
        }
 
index 767107cce982bfdcb651797eb2fb634dde4f2356..3951020e494ac803001083b186a5b7614eb6d42f 100644 (file)
@@ -4363,9 +4363,9 @@ out_unreg_blkdev:
 out_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
-               put_disk(disks[dr]);
                if (disks[dr]->queue)
                        blk_cleanup_queue(disks[dr]->queue);
+               put_disk(disks[dr]);
        }
        return err;
 }
@@ -4573,8 +4573,8 @@ static void __exit floppy_module_exit(void)
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
-               put_disk(disks[drive]);
                blk_cleanup_queue(disks[drive]->queue);
+               put_disk(disks[drive]);
        }
 
        del_timer_sync(&fd_timeout);
index 1e5284ef65fa47313d4a6609526b6dfecf00615e..7ea0bea2f7e3f7a0ecc2a2d4b5df15a9b5a7cccc 100644 (file)
@@ -481,12 +481,6 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
        if (bio_rw(bio) == WRITE) {
                struct file *file = lo->lo_backing_file;
 
-               /* REQ_HARDBARRIER is deprecated */
-               if (bio->bi_rw & REQ_HARDBARRIER) {
-                       ret = -EOPNOTSUPP;
-                       goto out;
-               }
-
                if (bio->bi_rw & REQ_FLUSH) {
                        ret = vfs_fsync(file, 0);
                        if (unlikely(ret && ret != -EINVAL)) {
index 06e2812ba12405dc0a63eea531943b53c4aa067b..255035cfc88ab8ff3a279578487facd6d17a113f 100644 (file)
@@ -289,8 +289,6 @@ static int blkif_queue_request(struct request *req)
 
        ring_req->operation = rq_data_dir(req) ?
                BLKIF_OP_WRITE : BLKIF_OP_READ;
-       if (req->cmd_flags & REQ_HARDBARRIER)
-               ring_req->operation = BLKIF_OP_WRITE_BARRIER;
 
        ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
        BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
index d120a5c1c0939b1061aae61b6c983da76cf37446..ab3894f742c3002a90a98b89f116ab30c75cdb28 100644 (file)
@@ -68,6 +68,9 @@ static struct usb_device_id btusb_table[] = {
        /* Apple MacBookPro6,2 */
        { USB_DEVICE(0x05ac, 0x8218) },
 
+       /* Apple MacBookAir3,1, MacBookAir3,2 */
+       { USB_DEVICE(0x05ac, 0x821b) },
+
        /* AVM BlueFRITZ! USB v2.0 */
        { USB_DEVICE(0x057c, 0x3800) },
 
@@ -1029,6 +1032,8 @@ static int btusb_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, data);
 
+       usb_enable_autosuspend(interface_to_usbdev(intf));
+
        return 0;
 }
 
diff --git a/drivers/char/.gitignore b/drivers/char/.gitignore
deleted file mode 100644 (file)
index 83683a2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-consolemap_deftbl.c
-defkeymap.c
index 3a9c01416839ebc785abcdec1405135fce3df817..ba53ec956c95627ff03695a3bbb363f9f5f2f400 100644 (file)
@@ -2,24 +2,10 @@
 # Makefile for the kernel character device drivers.
 #
 
-#
-# This file contains the font map for the default (hardware) font
-#
-FONTMAPFILE = cp437.uni
-
-obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
-
-obj-y                          += tty_mutex.o
-obj-$(CONFIG_LEGACY_PTYS)      += pty.o
-obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-y                          += mem.o random.o
 obj-$(CONFIG_TTY_PRINTK)       += ttyprintk.o
 obj-y                          += misc.o
-obj-$(CONFIG_VT)               += vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)   += bfin_jtag_comm.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE)       += vt.o defkeymap.o
-obj-$(CONFIG_AUDIT)            += tty_audit.o
-obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
 obj-$(CONFIG_MVME147_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC)     += generic_serial.o vme_scc.o
@@ -41,8 +27,6 @@ obj-$(CONFIG_ISI)             += isicom.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
 obj-$(CONFIG_SYNCLINKMP)       += synclinkmp.o
 obj-$(CONFIG_SYNCLINK_GT)      += synclink_gt.o
-obj-$(CONFIG_N_HDLC)           += n_hdlc.o
-obj-$(CONFIG_N_GSM)            += n_gsm.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
@@ -74,7 +58,6 @@ obj-$(CONFIG_PRINTER)         += lp.o
 obj-$(CONFIG_APM_EMULATION)    += apm-emulation.o
 
 obj-$(CONFIG_DTLK)             += dtlk.o
-obj-$(CONFIG_R3964)            += n_r3964.o
 obj-$(CONFIG_APPLICOM)         += applicom.o
 obj-$(CONFIG_SONYPI)           += sonypi.o
 obj-$(CONFIG_RTC)              += rtc.o
@@ -115,28 +98,3 @@ obj-$(CONFIG_RAMOOPS)               += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
-
-# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
-
-quiet_cmd_conmk = CONMK   $@
-      cmd_conmk = scripts/conmakehash $< > $@
-
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
-       $(call cmd,conmk)
-
-$(obj)/defkeymap.o:  $(obj)/defkeymap.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
-       loadkeys --mktable $< > $@.tmp
-       sed -e 's/^static *//' $@.tmp > $@
-       rm $@.tmp
-
-endif
index 43412c03969e14d0d0b92f1323109128bdb22a35..3cb4539a98b2f56d3a32509cd2ae951160a2d3d4 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include "agp.h"
index 6b6760ea2435bac1865325aec74d579f9687f87e..9272c38dd3c6ce8a66e9e0d2b0a5085ddd2973a7 100644 (file)
@@ -1210,14 +1210,14 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
        unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
        u32 pte_flags;
 
-       if (type_mask == AGP_USER_UNCACHED_MEMORY)
+       if (type_mask == AGP_USER_MEMORY)
                pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
        else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
-               pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
+               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_MLC | I810_PTE_VALID;
+               pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
                if (gfdt)
                        pte_flags |= GEN6_PTE_GFDT;
        }
index b0a70461a12c9c19269b8fe6c443251960c131b1..6ee3348bc3e4c922c3f9733830905c199ef85c29 100644 (file)
@@ -81,7 +81,6 @@ static char *serial_version = "4.30";
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
@@ -1299,7 +1298,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 {
        struct async_struct * info = tty->driver_data;
        struct async_icount cprev, cnow;        /* kernel counter temps */
-       struct serial_icounter_struct icount;
        void __user *argp = (void __user *)arg;
        unsigned long flags;
 
index f6718f05dad4a4ca16465967dd8779984637238e..095ab90535cea7519cce26cdc948a48c38dec02f 100644 (file)
@@ -6,7 +6,6 @@
 
 #include <linux/module.h>
 
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
deleted file mode 100644 (file)
index 45d3e80..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * consolemap.c
- *
- * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
- * to font positions.
- *
- * aeb, 950210
- *
- * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
- *
- * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
- */
-
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <asm/uaccess.h>
-#include <linux/consolemap.h>
-#include <linux/vt_kern.h>
-
-static unsigned short translations[][256] = {
-  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  }, 
-  /* VT100 graphics mapped to Unicode */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
-    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
-    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
-    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
-    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
-    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  },
-  /* IBM Codepage 437 mapped to Unicode */
-  {
-    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
-    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
-    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
-    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
-    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
-    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
-    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
-    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
-    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
-    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
-    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
-    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
-    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
-    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
-    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
-    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
-    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
-    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
-  }, 
-  /* User mapping -- default to codes for direct font mapping */
-  {
-    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
-    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
-    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
-    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
-    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
-    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
-    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
-    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
-    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
-    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
-    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
-    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
-    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
-    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
-    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
-    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
-    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
-    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
-    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
-    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
-    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
-    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
-    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
-    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
-    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
-    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
-    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
-    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
-    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
-    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
-    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
-    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
-  }
-};
-
-/* The standard kernel character-to-font mappings are not invertible
-   -- this is just a best effort. */
-
-#define MAX_GLYPH 512          /* Max possible glyph value */
-
-static int inv_translate[MAX_NR_CONSOLES];
-
-struct uni_pagedir {
-       u16             **uni_pgdir[32];
-       unsigned long   refcount;
-       unsigned long   sum;
-       unsigned char   *inverse_translations[4];
-       u16             *inverse_trans_unicode;
-       int             readonly;
-};
-
-static struct uni_pagedir *dflt;
-
-static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
-{
-       int j, glyph;
-       unsigned short *t = translations[i];
-       unsigned char *q;
-       
-       if (!p) return;
-       q = p->inverse_translations[i];
-
-       if (!q) {
-               q = p->inverse_translations[i] = (unsigned char *) 
-                       kmalloc(MAX_GLYPH, GFP_KERNEL);
-               if (!q) return;
-       }
-       memset(q, 0, MAX_GLYPH);
-
-       for (j = 0; j < E_TABSZ; j++) {
-               glyph = conv_uni_to_pc(conp, t[j]);
-               if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
-                       /* prefer '-' above SHY etc. */
-                       q[glyph] = j;
-               }
-       }
-}
-
-static void set_inverse_trans_unicode(struct vc_data *conp,
-                                     struct uni_pagedir *p)
-{
-       int i, j, k, glyph;
-       u16 **p1, *p2;
-       u16 *q;
-
-       if (!p) return;
-       q = p->inverse_trans_unicode;
-       if (!q) {
-               q = p->inverse_trans_unicode =
-                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
-               if (!q)
-                       return;
-       }
-       memset(q, 0, MAX_GLYPH * sizeof(u16));
-
-       for (i = 0; i < 32; i++) {
-               p1 = p->uni_pgdir[i];
-               if (!p1)
-                       continue;
-               for (j = 0; j < 32; j++) {
-                       p2 = p1[j];
-                       if (!p2)
-                               continue;
-                       for (k = 0; k < 64; k++) {
-                               glyph = p2[k];
-                               if (glyph >= 0 && glyph < MAX_GLYPH
-                                              && q[glyph] < 32)
-                                       q[glyph] = (i << 11) + (j << 6) + k;
-                       }
-               }
-       }
-}
-
-unsigned short *set_translate(int m, struct vc_data *vc)
-{
-       inv_translate[vc->vc_num] = m;
-       return translations[m];
-}
-
-/*
- * Inverse translation is impossible for several reasons:
- * 1. The font<->character maps are not 1-1.
- * 2. The text may have been written while a different translation map
- *    was active.
- * Still, it is now possible to a certain extent to cut and paste non-ASCII.
- */
-u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
-{
-       struct uni_pagedir *p;
-       int m;
-       if (glyph < 0 || glyph >= MAX_GLYPH)
-               return 0;
-       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
-               return glyph;
-       else if (use_unicode) {
-               if (!p->inverse_trans_unicode)
-                       return glyph;
-               else
-                       return p->inverse_trans_unicode[glyph];
-       } else {
-               m = inv_translate[conp->vc_num];
-               if (!p->inverse_translations[m])
-                       return glyph;
-               else
-                       return p->inverse_translations[m][glyph];
-       }
-}
-EXPORT_SYMBOL_GPL(inverse_translate);
-
-static void update_user_maps(void)
-{
-       int i;
-       struct uni_pagedir *p, *q = NULL;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (!vc_cons_allocated(i))
-                       continue;
-               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-               if (p && p != q) {
-                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
-                       set_inverse_trans_unicode(vc_cons[i].d, p);
-                       q = p;
-               }
-       }
-}
-
-/*
- * Load customizable translation table
- * arg points to a 256 byte translation table.
- *
- * The "old" variants are for translation directly to font (using the
- * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
- * Unicodes explicitly.
- */
-int con_set_trans_old(unsigned char __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_READ, arg, E_TABSZ))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++) {
-               unsigned char uc;
-               __get_user(uc, arg+i);
-               p[i] = UNI_DIRECT_BASE | uc;
-       }
-
-       update_user_maps();
-       return 0;
-}
-
-int con_get_trans_old(unsigned char __user * arg)
-{
-       int i, ch;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++)
-         {
-           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
-           __put_user((ch & ~0xff) ? 0 : ch, arg+i);
-         }
-       return 0;
-}
-
-int con_set_trans_new(ushort __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++) {
-               unsigned short us;
-               __get_user(us, arg+i);
-               p[i] = us;
-       }
-
-       update_user_maps();
-       return 0;
-}
-
-int con_get_trans_new(ushort __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++)
-         __put_user(p[i], arg+i);
-       
-       return 0;
-}
-
-/*
- * Unicode -> current font conversion 
- *
- * A font has at most 512 chars, usually 256.
- * But one font position may represent several Unicode chars.
- * A hashtable is somewhat of a pain to deal with, so use a
- * "paged table" instead.  Simulation has shown the memory cost of
- * this 3-level paged table scheme to be comparable to a hash table.
- */
-
-extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
-extern u16 dfont_unitable[];
-
-static void con_release_unimap(struct uni_pagedir *p)
-{
-       u16 **p1;
-       int i, j;
-
-       if (p == dflt) dflt = NULL;  
-       for (i = 0; i < 32; i++) {
-               if ((p1 = p->uni_pgdir[i]) != NULL) {
-                       for (j = 0; j < 32; j++)
-                               kfree(p1[j]);
-                       kfree(p1);
-               }
-               p->uni_pgdir[i] = NULL;
-       }
-       for (i = 0; i < 4; i++) {
-               kfree(p->inverse_translations[i]);
-               p->inverse_translations[i] = NULL;
-       }
-       if (p->inverse_trans_unicode) {
-               kfree(p->inverse_trans_unicode);
-               p->inverse_trans_unicode = NULL;
-       }
-}
-
-void con_free_unimap(struct vc_data *vc)
-{
-       struct uni_pagedir *p;
-
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (!p)
-               return;
-       *vc->vc_uni_pagedir_loc = 0;
-       if (--p->refcount)
-               return;
-       con_release_unimap(p);
-       kfree(p);
-}
-  
-static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
-{
-       int i, j, k;
-       struct uni_pagedir *q;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (!vc_cons_allocated(i))
-                       continue;
-               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-               if (!q || q == p || q->sum != p->sum)
-                       continue;
-               for (j = 0; j < 32; j++) {
-                       u16 **p1, **q1;
-                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
-                       if (!p1 && !q1)
-                               continue;
-                       if (!p1 || !q1)
-                               break;
-                       for (k = 0; k < 32; k++) {
-                               if (!p1[k] && !q1[k])
-                                       continue;
-                               if (!p1[k] || !q1[k])
-                                       break;
-                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
-                                       break;
-                       }
-                       if (k < 32)
-                               break;
-               }
-               if (j == 32) {
-                       q->refcount++;
-                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
-                       con_release_unimap(p);
-                       kfree(p);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static int
-con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
-{
-       int i, n;
-       u16 **p1, *p2;
-
-       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
-               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
-               if (!p1) return -ENOMEM;
-               for (i = 0; i < 32; i++)
-                       p1[i] = NULL;
-       }
-
-       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
-               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
-               if (!p2) return -ENOMEM;
-               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
-       }
-
-       p2[unicode & 0x3f] = fontpos;
-       
-       p->sum += (fontpos << 20) + unicode;
-
-       return 0;
-}
-
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
-{
-       struct uni_pagedir *p, *q;
-  
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (p && p->readonly) return -EIO;
-       if (!p || --p->refcount) {
-               q = kzalloc(sizeof(*p), GFP_KERNEL);
-               if (!q) {
-                       if (p) p->refcount++;
-                       return -ENOMEM;
-               }
-               q->refcount=1;
-               *vc->vc_uni_pagedir_loc = (unsigned long)q;
-       } else {
-               if (p == dflt) dflt = NULL;
-               p->refcount++;
-               p->sum = 0;
-               con_release_unimap(p);
-       }
-       return 0;
-}
-
-int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
-{
-       int err = 0, err1, i;
-       struct uni_pagedir *p, *q;
-
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (p->readonly) return -EIO;
-       
-       if (!ct) return 0;
-       
-       if (p->refcount > 1) {
-               int j, k;
-               u16 **p1, *p2, l;
-               
-               err1 = con_clear_unimap(vc, NULL);
-               if (err1) return err1;
-               
-               q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0, l = 0; i < 32; i++)
-               if ((p1 = p->uni_pgdir[i]))
-                       for (j = 0; j < 32; j++)
-                       if ((p2 = p1[j]))
-                               for (k = 0; k < 64; k++, l++)
-                               if (p2[k] != 0xffff) {
-                                       err1 = con_insert_unipair(q, l, p2[k]);
-                                       if (err1) {
-                                               p->refcount++;
-                                               *vc->vc_uni_pagedir_loc = (unsigned long)p;
-                                               con_release_unimap(q);
-                                               kfree(q);
-                                               return err1; 
-                                       }
-                               }
-               p = q;
-       } else if (p == dflt)
-               dflt = NULL;
-       
-       while (ct--) {
-               unsigned short unicode, fontpos;
-               __get_user(unicode, &list->unicode);
-               __get_user(fontpos, &list->fontpos);
-               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
-                       err = err1;
-               list++;
-       }
-       
-       if (con_unify_unimap(vc, p))
-               return err;
-
-       for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i); /* Update all inverse translations */
-       set_inverse_trans_unicode(vc, p);
-  
-       return err;
-}
-
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
-   The representation used was the most compact I could come up
-   with.  This routine is executed at sys_setup time, and when the
-   PIO_FONTRESET ioctl is called. */
-
-int con_set_default_unimap(struct vc_data *vc)
-{
-       int i, j, err = 0, err1;
-       u16 *q;
-       struct uni_pagedir *p;
-
-       if (dflt) {
-               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               if (p == dflt)
-                       return 0;
-               dflt->refcount++;
-               *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
-               if (p && --p->refcount) {
-                       con_release_unimap(p);
-                       kfree(p);
-               }
-               return 0;
-       }
-       
-       /* The default font is always 256 characters */
-
-       err = con_clear_unimap(vc, NULL);
-       if (err) return err;
-    
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       q = dfont_unitable;
-       
-       for (i = 0; i < 256; i++)
-               for (j = dfont_unicount[i]; j; j--) {
-                       err1 = con_insert_unipair(p, *(q++), i);
-                       if (err1)
-                               err = err1;
-               }
-                       
-       if (con_unify_unimap(vc, p)) {
-               dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               return err;
-       }
-
-       for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i);   /* Update all inverse translations */
-       set_inverse_trans_unicode(vc, p);
-       dflt = p;
-       return err;
-}
-EXPORT_SYMBOL(con_set_default_unimap);
-
-int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
-{
-       struct uni_pagedir *q;
-
-       if (!*src_vc->vc_uni_pagedir_loc)
-               return -EINVAL;
-       if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
-               return 0;
-       con_free_unimap(dst_vc);
-       q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
-       q->refcount++;
-       *dst_vc->vc_uni_pagedir_loc = (long)q;
-       return 0;
-}
-
-int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
-{
-       int i, j, k, ect;
-       u16 **p1, *p2;
-       struct uni_pagedir *p;
-
-       ect = 0;
-       if (*vc->vc_uni_pagedir_loc) {
-               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0; i < 32; i++)
-               if ((p1 = p->uni_pgdir[i]))
-                       for (j = 0; j < 32; j++)
-                       if ((p2 = *(p1++)))
-                               for (k = 0; k < 64; k++) {
-                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
-                                               __put_user((u_short)((i<<11)+(j<<6)+k),
-                                                          &list->unicode);
-                                               __put_user((u_short) *p2, 
-                                                          &list->fontpos);
-                                               list++;
-                                       }
-                                       p2++;
-                               }
-       }
-       __put_user(ect, uct);
-       return ((ect <= ct) ? 0 : -ENOMEM);
-}
-
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
-       struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       
-       if (p)
-               p->readonly = rdonly;
-}
-
-/*
- * Always use USER_MAP. These functions are used by the keyboard,
- * which shouldn't be affected by G0/G1 switching, etc.
- * If the user map still contains default values, i.e. the
- * direct-to-font mapping, then assume user is using Latin1.
- */
-/* may be called during an interrupt */
-u32 conv_8bit_to_uni(unsigned char c)
-{
-       unsigned short uni = translations[USER_MAP][c];
-       return uni == (0xf000 | c) ? c : uni;
-}
-
-int conv_uni_to_8bit(u32 uni)
-{
-       int c;
-       for (c = 0; c < 0x100; c++)
-               if (translations[USER_MAP][c] == uni ||
-                  (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
-                       return c;
-       return -1;
-}
-
-int
-conv_uni_to_pc(struct vc_data *conp, long ucs) 
-{
-       int h;
-       u16 **p1, *p2;
-       struct uni_pagedir *p;
-  
-       /* Only 16-bit codes supported at this time */
-       if (ucs > 0xffff)
-               return -4;              /* Not found */
-       else if (ucs < 0x20)
-               return -1;              /* Not a printable character */
-       else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
-               return -2;                      /* Zero-width space */
-       /*
-        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
-        * which always has a 1:1 mapping to the currently loaded font.  The
-        * UNI_DIRECT_MASK indicates the bit span of the region.
-        */
-       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
-               return ucs & UNI_DIRECT_MASK;
-  
-       if (!*conp->vc_uni_pagedir_loc)
-               return -3;
-
-       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
-       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
-           (p2 = p1[(ucs >> 6) & 0x1f]) &&
-           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
-               return h;
-
-       return -4;              /* not found */
-}
-
-/*
- * This is called at sys_setup time, after memory and the console are
- * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
- * from this function, hence the call from sys_setup.
- */
-void __init 
-console_map_init(void)
-{
-       int i;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
-                       con_set_default_unimap(vc_cons[i].d);
-}
-
-EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/char/cp437.uni b/drivers/char/cp437.uni
deleted file mode 100644 (file)
index bc61634..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-#
-# Unicode table for IBM Codepage 437.  Note that there are many more
-# substitutions that could be conceived (for example, thick-line
-# graphs probably should be replaced with double-line ones, accented
-# Latin characters should replaced with their nonaccented versions,
-# and some upper case Greek characters could be replaced by Latin), however,
-# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
-# DEC VT, and IBM CP 437 tables.
-#
-# --------------------------------
-#
-# Basic IBM dingbats, some of which will never have a purpose clear
-# to mankind
-#
-0x00   U+0000
-0x01   U+263a
-0x02   U+263b
-0x03   U+2665
-0x04   U+2666 U+25c6
-0x05   U+2663
-0x06   U+2660
-0x07   U+2022
-0x08   U+25d8
-0x09   U+25cb
-0x0a   U+25d9
-0x0b   U+2642
-0x0c   U+2640
-0x0d   U+266a
-0x0e   U+266b
-0x0f   U+263c U+00a4
-0x10   U+25b6 U+25ba
-0x11   U+25c0 U+25c4
-0x12   U+2195
-0x13   U+203c
-0x14   U+00b6
-0x15   U+00a7
-0x16   U+25ac
-0x17   U+21a8
-0x18   U+2191
-0x19   U+2193
-0x1a   U+2192
-0x1b   U+2190
-0x1c   U+221f
-0x1d   U+2194
-0x1e   U+25b2
-0x1f   U+25bc
-#
-# The ASCII range is identity-mapped, but some of the characters also
-# have to act as substitutes, especially the upper-case characters.
-#
-0x20   U+0020
-0x21   U+0021
-0x22   U+0022 U+00a8
-0x23   U+0023
-0x24   U+0024
-0x25   U+0025
-0x26   U+0026
-0x27   U+0027 U+00b4
-0x28   U+0028
-0x29   U+0029
-0x2a   U+002a
-0x2b   U+002b
-0x2c   U+002c U+00b8
-0x2d   U+002d U+00ad
-0x2e   U+002e
-0x2f   U+002f
-0x30   U+0030
-0x31   U+0031
-0x32   U+0032
-0x33   U+0033
-0x34   U+0034
-0x35   U+0035
-0x36   U+0036
-0x37   U+0037
-0x38   U+0038
-0x39   U+0039
-0x3a   U+003a
-0x3b   U+003b
-0x3c   U+003c
-0x3d   U+003d
-0x3e   U+003e
-0x3f   U+003f
-0x40   U+0040
-0x41   U+0041 U+00c0 U+00c1 U+00c2 U+00c3
-0x42   U+0042
-0x43   U+0043 U+00a9
-0x44   U+0044 U+00d0
-0x45   U+0045 U+00c8 U+00ca U+00cb
-0x46   U+0046
-0x47   U+0047
-0x48   U+0048
-0x49   U+0049 U+00cc U+00cd U+00ce U+00cf
-0x4a   U+004a
-0x4b   U+004b U+212a
-0x4c   U+004c
-0x4d   U+004d
-0x4e   U+004e
-0x4f   U+004f U+00d2 U+00d3 U+00d4 U+00d5
-0x50   U+0050
-0x51   U+0051
-0x52   U+0052 U+00ae
-0x53   U+0053
-0x54   U+0054
-0x55   U+0055 U+00d9 U+00da U+00db
-0x56   U+0056
-0x57   U+0057
-0x58   U+0058
-0x59   U+0059 U+00dd
-0x5a   U+005a
-0x5b   U+005b
-0x5c   U+005c
-0x5d   U+005d
-0x5e   U+005e
-0x5f   U+005f U+23bd U+f804
-0x60   U+0060
-0x61   U+0061 U+00e3
-0x62   U+0062
-0x63   U+0063
-0x64   U+0064
-0x65   U+0065
-0x66   U+0066
-0x67   U+0067
-0x68   U+0068
-0x69   U+0069
-0x6a   U+006a
-0x6b   U+006b
-0x6c   U+006c
-0x6d   U+006d
-0x6e   U+006e
-0x6f   U+006f U+00f5
-0x70   U+0070
-0x71   U+0071
-0x72   U+0072
-0x73   U+0073
-0x74   U+0074
-0x75   U+0075
-0x76   U+0076
-0x77   U+0077
-0x78   U+0078 U+00d7
-0x79   U+0079 U+00fd
-0x7a   U+007a
-0x7b   U+007b
-0x7c   U+007c U+00a6
-0x7d   U+007d
-0x7e   U+007e
-#
-# Okay, what on Earth is this one supposed to be used for?
-#
-0x7f   U+2302
-#
-# Non-English characters, mostly lower case letters...
-#
-0x80   U+00c7
-0x81   U+00fc
-0x82   U+00e9
-0x83   U+00e2
-0x84   U+00e4
-0x85   U+00e0
-0x86   U+00e5
-0x87   U+00e7
-0x88   U+00ea
-0x89   U+00eb
-0x8a   U+00e8
-0x8b   U+00ef
-0x8c   U+00ee
-0x8d   U+00ec
-0x8e   U+00c4
-0x8f   U+00c5 U+212b
-0x90   U+00c9
-0x91   U+00e6
-0x92   U+00c6
-0x93   U+00f4
-0x94   U+00f6
-0x95   U+00f2
-0x96   U+00fb
-0x97   U+00f9
-0x98   U+00ff
-0x99   U+00d6
-0x9a   U+00dc
-0x9b   U+00a2
-0x9c   U+00a3
-0x9d   U+00a5
-0x9e   U+20a7
-0x9f   U+0192
-0xa0   U+00e1
-0xa1   U+00ed
-0xa2   U+00f3
-0xa3   U+00fa
-0xa4   U+00f1
-0xa5   U+00d1
-0xa6   U+00aa
-0xa7   U+00ba
-0xa8   U+00bf
-0xa9   U+2310
-0xaa   U+00ac
-0xab   U+00bd
-0xac   U+00bc
-0xad   U+00a1
-0xae   U+00ab
-0xaf   U+00bb
-#
-# Block graphics
-#
-0xb0   U+2591
-0xb1   U+2592
-0xb2   U+2593
-0xb3   U+2502
-0xb4   U+2524
-0xb5   U+2561
-0xb6   U+2562
-0xb7   U+2556
-0xb8   U+2555
-0xb9   U+2563
-0xba   U+2551
-0xbb   U+2557
-0xbc   U+255d
-0xbd   U+255c
-0xbe   U+255b
-0xbf   U+2510
-0xc0   U+2514
-0xc1   U+2534
-0xc2   U+252c
-0xc3   U+251c
-0xc4   U+2500
-0xc5   U+253c
-0xc6   U+255e
-0xc7   U+255f
-0xc8   U+255a
-0xc9   U+2554
-0xca   U+2569
-0xcb   U+2566
-0xcc   U+2560
-0xcd   U+2550
-0xce   U+256c
-0xcf   U+2567
-0xd0   U+2568
-0xd1   U+2564
-0xd2   U+2565
-0xd3   U+2559
-0xd4   U+2558
-0xd5   U+2552
-0xd6   U+2553
-0xd7   U+256b
-0xd8   U+256a
-0xd9   U+2518
-0xda   U+250c
-0xdb   U+2588
-0xdc   U+2584
-0xdd   U+258c
-0xde   U+2590
-0xdf   U+2580
-#
-# Greek letters and mathematical symbols
-#
-0xe0   U+03b1
-0xe1   U+03b2 U+00df
-0xe2   U+0393
-0xe3   U+03c0
-0xe4   U+03a3
-0xe5   U+03c3
-0xe6   U+00b5 U+03bc
-0xe7   U+03c4
-0xe8   U+03a6 U+00d8
-0xe9   U+0398
-0xea   U+03a9 U+2126
-0xeb   U+03b4 U+00f0
-0xec   U+221e
-0xed   U+03c6 U+00f8
-0xee   U+03b5 U+2208
-0xef   U+2229
-0xf0   U+2261
-0xf1   U+00b1
-0xf2   U+2265
-0xf3   U+2264
-0xf4   U+2320
-0xf5   U+2321
-0xf6   U+00f7
-0xf7   U+2248
-0xf8   U+00b0
-0xf9   U+2219
-0xfa   U+00b7
-0xfb   U+221a
-0xfc   U+207f
-0xfd   U+00b2
-#
-# Square bullet, non-spacing blank
-# Mapping U+fffd to the square bullet means it is the substitution
-# character
-# 
-0xfe   U+25a0 U+fffd
-0xff   U+00a0
diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped
deleted file mode 100644 (file)
index d2208df..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
-       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
-       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
-       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
-       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
-       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
-       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
-       0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
-       0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
-       0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
-       0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
-       0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
-       0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
-       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
-       0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
-       0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
-       0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
-       0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
-       0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
-       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
-       0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
-       0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
-       0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
-       0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
-       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
-       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-       0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
-       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
-       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
-       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-       0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
-       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
-       0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
-       0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
-       0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
-       0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
-       0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
-       0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
-       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
-       0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
-       0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
-       0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
-       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
-       0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
-       0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
-       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
-       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-       plain_map, shift_map, altgr_map, NULL,
-       ctrl_map, shift_ctrl_map, NULL, NULL,
-       alt_map, NULL, NULL, NULL,
-       ctrl_alt_map, NULL
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-       '\033', '[', '[', 'A', 0, 
-       '\033', '[', '[', 'B', 0, 
-       '\033', '[', '[', 'C', 0, 
-       '\033', '[', '[', 'D', 0, 
-       '\033', '[', '[', 'E', 0, 
-       '\033', '[', '1', '7', '~', 0, 
-       '\033', '[', '1', '8', '~', 0, 
-       '\033', '[', '1', '9', '~', 0, 
-       '\033', '[', '2', '0', '~', 0, 
-       '\033', '[', '2', '1', '~', 0, 
-       '\033', '[', '2', '3', '~', 0, 
-       '\033', '[', '2', '4', '~', 0, 
-       '\033', '[', '2', '5', '~', 0, 
-       '\033', '[', '2', '6', '~', 0, 
-       '\033', '[', '2', '8', '~', 0, 
-       '\033', '[', '2', '9', '~', 0, 
-       '\033', '[', '3', '1', '~', 0, 
-       '\033', '[', '3', '2', '~', 0, 
-       '\033', '[', '3', '3', '~', 0, 
-       '\033', '[', '3', '4', '~', 0, 
-       '\033', '[', '1', '~', 0, 
-       '\033', '[', '2', '~', 0, 
-       '\033', '[', '3', '~', 0, 
-       '\033', '[', '4', '~', 0, 
-       '\033', '[', '5', '~', 0, 
-       '\033', '[', '6', '~', 0, 
-       '\033', '[', 'M', 0, 
-       '\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-       func_buf + 0,
-       func_buf + 5,
-       func_buf + 10,
-       func_buf + 15,
-       func_buf + 20,
-       func_buf + 25,
-       func_buf + 31,
-       func_buf + 37,
-       func_buf + 43,
-       func_buf + 49,
-       func_buf + 55,
-       func_buf + 61,
-       func_buf + 67,
-       func_buf + 73,
-       func_buf + 79,
-       func_buf + 85,
-       func_buf + 91,
-       func_buf + 97,
-       func_buf + 103,
-       func_buf + 109,
-       func_buf + 115,
-       func_buf + 120,
-       func_buf + 125,
-       func_buf + 130,
-       func_buf + 135,
-       func_buf + 140,
-       func_buf + 145,
-       NULL,
-       NULL,
-       func_buf + 149,
-       NULL,
-};
-
-struct kbdiacruc accent_table[MAX_DIACR] = {
-       {'`', 'A', 0300},       {'`', 'a', 0340},
-       {'\'', 'A', 0301},      {'\'', 'a', 0341},
-       {'^', 'A', 0302},       {'^', 'a', 0342},
-       {'~', 'A', 0303},       {'~', 'a', 0343},
-       {'"', 'A', 0304},       {'"', 'a', 0344},
-       {'O', 'A', 0305},       {'o', 'a', 0345},
-       {'0', 'A', 0305},       {'0', 'a', 0345},
-       {'A', 'A', 0305},       {'a', 'a', 0345},
-       {'A', 'E', 0306},       {'a', 'e', 0346},
-       {',', 'C', 0307},       {',', 'c', 0347},
-       {'`', 'E', 0310},       {'`', 'e', 0350},
-       {'\'', 'E', 0311},      {'\'', 'e', 0351},
-       {'^', 'E', 0312},       {'^', 'e', 0352},
-       {'"', 'E', 0313},       {'"', 'e', 0353},
-       {'`', 'I', 0314},       {'`', 'i', 0354},
-       {'\'', 'I', 0315},      {'\'', 'i', 0355},
-       {'^', 'I', 0316},       {'^', 'i', 0356},
-       {'"', 'I', 0317},       {'"', 'i', 0357},
-       {'-', 'D', 0320},       {'-', 'd', 0360},
-       {'~', 'N', 0321},       {'~', 'n', 0361},
-       {'`', 'O', 0322},       {'`', 'o', 0362},
-       {'\'', 'O', 0323},      {'\'', 'o', 0363},
-       {'^', 'O', 0324},       {'^', 'o', 0364},
-       {'~', 'O', 0325},       {'~', 'o', 0365},
-       {'"', 'O', 0326},       {'"', 'o', 0366},
-       {'/', 'O', 0330},       {'/', 'o', 0370},
-       {'`', 'U', 0331},       {'`', 'u', 0371},
-       {'\'', 'U', 0332},      {'\'', 'u', 0372},
-       {'^', 'U', 0333},       {'^', 'u', 0373},
-       {'"', 'U', 0334},       {'"', 'u', 0374},
-       {'\'', 'Y', 0335},      {'\'', 'y', 0375},
-       {'T', 'H', 0336},       {'t', 'h', 0376},
-       {'s', 's', 0337},       {'"', 'y', 0377},
-       {'s', 'z', 0337},       {'i', 'j', 0377},
-};
-
-unsigned int accent_table_size = 68;
diff --git a/drivers/char/defkeymap.map b/drivers/char/defkeymap.map
deleted file mode 100644 (file)
index 50b30ca..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-# Default kernel keymap. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-#      keymaps 0-2,4-6,8,12
-# in case you want the entries
-#      altgr   control keycode  83 = Boot            
-#      altgr   control keycode 111 = Boot            
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode   1 = Escape           Escape          
-       alt     keycode   1 = Meta_Escape     
-keycode   2 = one              exclam          
-       alt     keycode   2 = Meta_one        
-keycode   3 = two              at               at              
-       control keycode   3 = nul             
-       shift   control keycode   3 = nul             
-       alt     keycode   3 = Meta_two        
-keycode   4 = three            numbersign      
-       control keycode   4 = Escape          
-       alt     keycode   4 = Meta_three      
-keycode   5 = four             dollar           dollar          
-       control keycode   5 = Control_backslash
-       alt     keycode   5 = Meta_four       
-keycode   6 = five             percent         
-       control keycode   6 = Control_bracketright
-       alt     keycode   6 = Meta_five       
-keycode   7 = six              asciicircum     
-       control keycode   7 = Control_asciicircum
-       alt     keycode   7 = Meta_six        
-keycode   8 = seven            ampersand        braceleft       
-       control keycode   8 = Control_underscore
-       alt     keycode   8 = Meta_seven      
-keycode   9 = eight            asterisk         bracketleft     
-       control keycode   9 = Delete          
-       alt     keycode   9 = Meta_eight      
-keycode  10 = nine             parenleft        bracketright    
-       alt     keycode  10 = Meta_nine       
-keycode  11 = zero             parenright       braceright      
-       alt     keycode  11 = Meta_zero       
-keycode  12 = minus            underscore       backslash       
-       control keycode  12 = Control_underscore
-       shift   control keycode  12 = Control_underscore
-       alt     keycode  12 = Meta_minus      
-keycode  13 = equal            plus            
-       alt     keycode  13 = Meta_equal      
-keycode  14 = Delete           Delete          
-       control keycode  14 = BackSpace
-       alt     keycode  14 = Meta_Delete     
-keycode  15 = Tab              Tab             
-       alt     keycode  15 = Meta_Tab        
-keycode  16 = q               
-keycode  17 = w               
-keycode  18 = e
-       altgr   keycode  18 = Hex_E   
-keycode  19 = r               
-keycode  20 = t               
-keycode  21 = y               
-keycode  22 = u               
-keycode  23 = i               
-keycode  24 = o               
-keycode  25 = p               
-keycode  26 = bracketleft      braceleft       
-       control keycode  26 = Escape          
-       alt     keycode  26 = Meta_bracketleft
-keycode  27 = bracketright     braceright       asciitilde      
-       control keycode  27 = Control_bracketright
-       alt     keycode  27 = Meta_bracketright
-keycode  28 = Return          
-       alt     keycode  28 = Meta_Control_m  
-keycode  29 = Control         
-keycode  30 = a
-       altgr   keycode  30 = Hex_A
-keycode  31 = s               
-keycode  32 = d
-       altgr   keycode  32 = Hex_D   
-keycode  33 = f
-       altgr   keycode  33 = Hex_F               
-keycode  34 = g               
-keycode  35 = h               
-keycode  36 = j               
-keycode  37 = k               
-keycode  38 = l               
-keycode  39 = semicolon        colon           
-       alt     keycode  39 = Meta_semicolon  
-keycode  40 = apostrophe       quotedbl        
-       control keycode  40 = Control_g       
-       alt     keycode  40 = Meta_apostrophe 
-keycode  41 = grave            asciitilde      
-       control keycode  41 = nul             
-       alt     keycode  41 = Meta_grave      
-keycode  42 = Shift           
-keycode  43 = backslash        bar             
-       control keycode  43 = Control_backslash
-       alt     keycode  43 = Meta_backslash  
-keycode  44 = z               
-keycode  45 = x               
-keycode  46 = c
-       altgr   keycode  46 = Hex_C   
-keycode  47 = v               
-keycode  48 = b
-       altgr   keycode  48 = Hex_B
-keycode  49 = n               
-keycode  50 = m               
-keycode  51 = comma            less            
-       alt     keycode  51 = Meta_comma      
-keycode  52 = period           greater         
-       control keycode  52 = Compose         
-       alt     keycode  52 = Meta_period     
-keycode  53 = slash            question        
-       control keycode  53 = Delete          
-       alt     keycode  53 = Meta_slash      
-keycode  54 = Shift           
-keycode  55 = KP_Multiply     
-keycode  56 = Alt             
-keycode  57 = space            space           
-       control keycode  57 = nul             
-       alt     keycode  57 = Meta_space      
-keycode  58 = Caps_Lock       
-keycode  59 = F1               F11              Console_13      
-       control keycode  59 = F1              
-       alt     keycode  59 = Console_1       
-       control alt     keycode  59 = Console_1       
-keycode  60 = F2               F12              Console_14      
-       control keycode  60 = F2              
-       alt     keycode  60 = Console_2       
-       control alt     keycode  60 = Console_2       
-keycode  61 = F3               F13              Console_15      
-       control keycode  61 = F3              
-       alt     keycode  61 = Console_3       
-       control alt     keycode  61 = Console_3       
-keycode  62 = F4               F14              Console_16      
-       control keycode  62 = F4              
-       alt     keycode  62 = Console_4       
-       control alt     keycode  62 = Console_4       
-keycode  63 = F5               F15              Console_17      
-       control keycode  63 = F5              
-       alt     keycode  63 = Console_5       
-       control alt     keycode  63 = Console_5       
-keycode  64 = F6               F16              Console_18      
-       control keycode  64 = F6              
-       alt     keycode  64 = Console_6       
-       control alt     keycode  64 = Console_6       
-keycode  65 = F7               F17              Console_19      
-       control keycode  65 = F7              
-       alt     keycode  65 = Console_7       
-       control alt     keycode  65 = Console_7       
-keycode  66 = F8               F18              Console_20      
-       control keycode  66 = F8              
-       alt     keycode  66 = Console_8       
-       control alt     keycode  66 = Console_8       
-keycode  67 = F9               F19              Console_21      
-       control keycode  67 = F9              
-       alt     keycode  67 = Console_9       
-       control alt     keycode  67 = Console_9       
-keycode  68 = F10              F20              Console_22      
-       control keycode  68 = F10             
-       alt     keycode  68 = Console_10      
-       control alt     keycode  68 = Console_10      
-keycode  69 = Num_Lock
-       shift   keycode  69 = Bare_Num_Lock
-keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
-       control keycode  70 = Show_State      
-       alt     keycode  70 = Scroll_Lock     
-keycode  71 = KP_7            
-       alt     keycode  71 = Ascii_7         
-       altgr   keycode  71 = Hex_7         
-keycode  72 = KP_8            
-       alt     keycode  72 = Ascii_8         
-       altgr   keycode  72 = Hex_8         
-keycode  73 = KP_9            
-       alt     keycode  73 = Ascii_9         
-       altgr   keycode  73 = Hex_9         
-keycode  74 = KP_Subtract     
-keycode  75 = KP_4            
-       alt     keycode  75 = Ascii_4         
-       altgr   keycode  75 = Hex_4         
-keycode  76 = KP_5            
-       alt     keycode  76 = Ascii_5         
-       altgr   keycode  76 = Hex_5         
-keycode  77 = KP_6            
-       alt     keycode  77 = Ascii_6         
-       altgr   keycode  77 = Hex_6         
-keycode  78 = KP_Add          
-keycode  79 = KP_1            
-       alt     keycode  79 = Ascii_1         
-       altgr   keycode  79 = Hex_1         
-keycode  80 = KP_2            
-       alt     keycode  80 = Ascii_2         
-       altgr   keycode  80 = Hex_2         
-keycode  81 = KP_3            
-       alt     keycode  81 = Ascii_3         
-       altgr   keycode  81 = Hex_3         
-keycode  82 = KP_0            
-       alt     keycode  82 = Ascii_0         
-       altgr   keycode  82 = Hex_0         
-keycode  83 = KP_Period       
-#      altgr   control keycode  83 = Boot            
-       control alt     keycode  83 = Boot            
-keycode  84 = Last_Console    
-keycode  85 =
-keycode  86 = less             greater          bar             
-       alt     keycode  86 = Meta_less       
-keycode  87 = F11              F11              Console_23      
-       control keycode  87 = F11             
-       alt     keycode  87 = Console_11      
-       control alt     keycode  87 = Console_11      
-keycode  88 = F12              F12              Console_24      
-       control keycode  88 = F12             
-       alt     keycode  88 = Console_12      
-       control alt     keycode  88 = Console_12      
-keycode  89 =
-keycode  90 =
-keycode  91 =
-keycode  92 =
-keycode  93 =
-keycode  94 =
-keycode  95 =
-keycode  96 = KP_Enter        
-keycode  97 = Control         
-keycode  98 = KP_Divide       
-keycode  99 = Control_backslash
-       control keycode  99 = Control_backslash
-       alt     keycode  99 = Control_backslash
-keycode 100 = AltGr           
-keycode 101 = Break           
-keycode 102 = Find            
-keycode 103 = Up              
-keycode 104 = Prior           
-       shift   keycode 104 = Scroll_Backward 
-keycode 105 = Left            
-       alt     keycode 105 = Decr_Console
-keycode 106 = Right           
-       alt     keycode 106 = Incr_Console
-keycode 107 = Select          
-keycode 108 = Down            
-keycode 109 = Next            
-       shift   keycode 109 = Scroll_Forward  
-keycode 110 = Insert          
-keycode 111 = Remove          
-#      altgr   control keycode 111 = Boot            
-       control alt     keycode 111 = Boot            
-keycode 112 = Macro           
-keycode 113 = F13             
-keycode 114 = F14             
-keycode 115 = Help            
-keycode 116 = Do              
-keycode 117 = F17             
-keycode 118 = KP_MinPlus      
-keycode 119 = Pause           
-keycode 120 =
-keycode 121 =
-keycode 122 =
-keycode 123 =
-keycode 124 =
-keycode 125 =
-keycode 126 =
-keycode 127 =
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
index 55b8667f739f64a82731ab926738601825cbb00c..7066e801b9d348e9506651e11bf51197b24d2847 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <linux/major.h>
index 788da05190ccf865ab47f0e53848c70faa8f5d33..2016aad85203ac2e868d5be0df20b267ab9e5ecf 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
index 3bc0eef88717136342564976a8e18aa534732284..d72433f2d310deb6cf909cb1feb30e92919887cd 100644 (file)
@@ -120,7 +120,7 @@ static int i8k_smm(struct smm_regs *regs)
        int eax = regs->eax;
 
 #if defined(CONFIG_X86_64)
-       asm("pushq %%rax\n\t"
+       asm volatile("pushq %%rax\n\t"
                "movl 0(%%rax),%%edx\n\t"
                "pushq %%rdx\n\t"
                "movl 4(%%rax),%%ebx\n\t"
@@ -146,7 +146,7 @@ static int i8k_smm(struct smm_regs *regs)
                :    "a"(regs)
                :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
 #else
-       asm("pushl %%eax\n\t"
+       asm volatile("pushl %%eax\n\t"
            "movl 0(%%eax),%%edx\n\t"
            "push %%edx\n\t"
            "movl 4(%%eax),%%ebx\n\t"
@@ -167,7 +167,8 @@ static int i8k_smm(struct smm_regs *regs)
            "movl %%edx,0(%%eax)\n\t"
            "lahf\n\t"
            "shrl $8,%%eax\n\t"
-           "andl $1,%%eax\n":"=a"(rc)
+           "andl $1,%%eax\n"
+           :"=a"(rc)
            :    "a"(regs)
            :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
 #endif
index 667abd23ad6ab91b81fa957f3c80260e9c7735a6..7c6de4c92458ded21561df8d75e6f92e5c6f6945 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
deleted file mode 100644 (file)
index e95d787..0000000
+++ /dev/null
@@ -1,1454 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting,  Sept 1994
- * `Sticky' modifier keys, 951006.
- *
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
- * Modified to provide 'generic' keyboard support by Hamish Macdonald
- * Merge with the m68k keyboard driver and split-off of the PC low-level
- * parts by Geert Uytterhoeven, May 1997
- *
- * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
- * 30-07-98: Dead keys redone, aeb@cwi.nl.
- * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/consolemap.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/vt_kern.h>
-#include <linux/input.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-
-extern void ctrl_alt_del(void);
-
-/*
- * Exported functions/variables
- */
-
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
- * to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
-#else
-#define KBD_DEFLEDS 0
-#endif
-
-#define KBD_DEFLOCK 0
-
-void compute_shiftstate(void);
-
-/*
- * Handler Tables.
- */
-
-#define K_HANDLERS\
-       k_self,         k_fn,           k_spec,         k_pad,\
-       k_dead,         k_cons,         k_cur,          k_shift,\
-       k_meta,         k_ascii,        k_lock,         k_lowercase,\
-       k_slock,        k_dead2,        k_brl,          k_ignore
-
-typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
-                           char up_flag);
-static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
-
-#define FN_HANDLERS\
-       fn_null,        fn_enter,       fn_show_ptregs, fn_show_mem,\
-       fn_show_state,  fn_send_intr,   fn_lastcons,    fn_caps_toggle,\
-       fn_num,         fn_hold,        fn_scroll_forw, fn_scroll_back,\
-       fn_boot_it,     fn_caps_on,     fn_compose,     fn_SAK,\
-       fn_dec_console, fn_inc_console, fn_spawn_con,   fn_bare_num
-
-typedef void (fn_handler_fn)(struct vc_data *vc);
-static fn_handler_fn FN_HANDLERS;
-static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
-
-/*
- * Variables exported for vt_ioctl.c
- */
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-       255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
-       NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-       255, NR_LOCK - 1, 255, NR_BRL - 1
-};
-
-const int NR_TYPES = ARRAY_SIZE(max_vals);
-
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-EXPORT_SYMBOL_GPL(kbd_table);
-static struct kbd_struct *kbd = kbd_table;
-
-struct vt_spawn_console vt_spawn_con = {
-       .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
-       .pid  = NULL,
-       .sig  = 0,
-};
-
-/*
- * Variables exported for vt.c
- */
-
-int shift_state = 0;
-
-/*
- * Internal Data.
- */
-
-static struct input_handler kbd_handler;
-static DEFINE_SPINLOCK(kbd_event_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
-static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
-static bool dead_key_next;
-static int npadch = -1;                                        /* -1 or number assembled on pad */
-static unsigned int diacr;
-static char rep;                                       /* flag telling character repeat */
-
-static unsigned char ledstate = 0xff;                  /* undefined */
-static unsigned char ledioctl;
-
-static struct ledptr {
-       unsigned int *addr;
-       unsigned int mask;
-       unsigned char valid:1;
-} ledptrs[3];
-
-/*
- * Notifier list for console keyboard events
- */
-static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
-
-int register_keyboard_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_keyboard_notifier);
-
-int unregister_keyboard_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
-
-/*
- * Translation of scancodes to keycodes. We set them on only the first
- * keyboard in the list that accepts the scancode and keycode.
- * Explanation for not choosing the first attached keyboard anymore:
- *  USB keyboards for example have two event devices: one for all "normal"
- *  keys and one for extra function keys (like "volume up", "make coffee",
- *  etc.). So this means that scancodes for the extra function keys won't
- *  be valid for the first event device, but will be for the second.
- */
-
-struct getset_keycode_data {
-       struct input_keymap_entry ke;
-       int error;
-};
-
-static int getkeycode_helper(struct input_handle *handle, void *data)
-{
-       struct getset_keycode_data *d = data;
-
-       d->error = input_get_keycode(handle->dev, &d->ke);
-
-       return d->error == 0; /* stop as soon as we successfully get one */
-}
-
-int getkeycode(unsigned int scancode)
-{
-       struct getset_keycode_data d = {
-               .ke     = {
-                       .flags          = 0,
-                       .len            = sizeof(scancode),
-                       .keycode        = 0,
-               },
-               .error  = -ENODEV,
-       };
-
-       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
-
-       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
-
-       return d.error ?: d.ke.keycode;
-}
-
-static int setkeycode_helper(struct input_handle *handle, void *data)
-{
-       struct getset_keycode_data *d = data;
-
-       d->error = input_set_keycode(handle->dev, &d->ke);
-
-       return d->error == 0; /* stop as soon as we successfully set one */
-}
-
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-       struct getset_keycode_data d = {
-               .ke     = {
-                       .flags          = 0,
-                       .len            = sizeof(scancode),
-                       .keycode        = keycode,
-               },
-               .error  = -ENODEV,
-       };
-
-       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
-
-       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
-
-       return d.error;
-}
-
-/*
- * Making beeps and bells. Note that we prefer beeps to bells, but when
- * shutting the sound off we do both.
- */
-
-static int kd_sound_helper(struct input_handle *handle, void *data)
-{
-       unsigned int *hz = data;
-       struct input_dev *dev = handle->dev;
-
-       if (test_bit(EV_SND, dev->evbit)) {
-               if (test_bit(SND_TONE, dev->sndbit)) {
-                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
-                       if (*hz)
-                               return 0;
-               }
-               if (test_bit(SND_BELL, dev->sndbit))
-                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
-       }
-
-       return 0;
-}
-
-static void kd_nosound(unsigned long ignored)
-{
-       static unsigned int zero;
-
-       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
-}
-
-static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
-
-void kd_mksound(unsigned int hz, unsigned int ticks)
-{
-       del_timer_sync(&kd_mksound_timer);
-
-       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
-
-       if (hz && ticks)
-               mod_timer(&kd_mksound_timer, jiffies + ticks);
-}
-EXPORT_SYMBOL(kd_mksound);
-
-/*
- * Setting the keyboard rate.
- */
-
-static int kbd_rate_helper(struct input_handle *handle, void *data)
-{
-       struct input_dev *dev = handle->dev;
-       struct kbd_repeat *rep = data;
-
-       if (test_bit(EV_REP, dev->evbit)) {
-
-               if (rep[0].delay > 0)
-                       input_inject_event(handle,
-                                          EV_REP, REP_DELAY, rep[0].delay);
-               if (rep[0].period > 0)
-                       input_inject_event(handle,
-                                          EV_REP, REP_PERIOD, rep[0].period);
-
-               rep[1].delay = dev->rep[REP_DELAY];
-               rep[1].period = dev->rep[REP_PERIOD];
-       }
-
-       return 0;
-}
-
-int kbd_rate(struct kbd_repeat *rep)
-{
-       struct kbd_repeat data[2] = { *rep };
-
-       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
-       *rep = data[1]; /* Copy currently used settings */
-
-       return 0;
-}
-
-/*
- * Helper Functions.
- */
-static void put_queue(struct vc_data *vc, int ch)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (tty) {
-               tty_insert_flip_char(tty, ch, 0);
-               con_schedule_flip(tty);
-       }
-}
-
-static void puts_queue(struct vc_data *vc, char *cp)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (!tty)
-               return;
-
-       while (*cp) {
-               tty_insert_flip_char(tty, *cp, 0);
-               cp++;
-       }
-       con_schedule_flip(tty);
-}
-
-static void applkey(struct vc_data *vc, int key, char mode)
-{
-       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
-       buf[1] = (mode ? 'O' : '[');
-       buf[2] = key;
-       puts_queue(vc, buf);
-}
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-static void to_utf8(struct vc_data *vc, uint c)
-{
-       if (c < 0x80)
-               /*  0******* */
-               put_queue(vc, c);
-       else if (c < 0x800) {
-               /* 110***** 10****** */
-               put_queue(vc, 0xc0 | (c >> 6));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x10000) {
-               if (c >= 0xD800 && c < 0xE000)
-                       return;
-               if (c == 0xFFFF)
-                       return;
-               /* 1110**** 10****** 10****** */
-               put_queue(vc, 0xe0 | (c >> 12));
-               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x110000) {
-               /* 11110*** 10****** 10****** 10****** */
-               put_queue(vc, 0xf0 | (c >> 18));
-               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
-               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       }
-}
-
-/*
- * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen
- */
-void compute_shiftstate(void)
-{
-       unsigned int i, j, k, sym, val;
-
-       shift_state = 0;
-       memset(shift_down, 0, sizeof(shift_down));
-
-       for (i = 0; i < ARRAY_SIZE(key_down); i++) {
-
-               if (!key_down[i])
-                       continue;
-
-               k = i * BITS_PER_LONG;
-
-               for (j = 0; j < BITS_PER_LONG; j++, k++) {
-
-                       if (!test_bit(k, key_down))
-                               continue;
-
-                       sym = U(key_maps[0][k]);
-                       if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
-                               continue;
-
-                       val = KVAL(sym);
-                       if (val == KVAL(K_CAPSSHIFT))
-                               val = KVAL(K_SHIFT);
-
-                       shift_down[val]++;
-                       shift_state |= (1 << val);
-               }
-       }
-}
-
-/*
- * We have a combining character DIACR here, followed by the character CH.
- * If the combination occurs in the table, return the corresponding value.
- * Otherwise, if CH is a space or equals DIACR, return DIACR.
- * Otherwise, conclude that DIACR was not combining after all,
- * queue it and return CH.
- */
-static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
-{
-       unsigned int d = diacr;
-       unsigned int i;
-
-       diacr = 0;
-
-       if ((d & ~0xff) == BRL_UC_ROW) {
-               if ((ch & ~0xff) == BRL_UC_ROW)
-                       return d | ch;
-       } else {
-               for (i = 0; i < accent_table_size; i++)
-                       if (accent_table[i].diacr == d && accent_table[i].base == ch)
-                               return accent_table[i].result;
-       }
-
-       if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
-               return d;
-
-       if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, d);
-       else {
-               int c = conv_uni_to_8bit(d);
-               if (c != -1)
-                       put_queue(vc, c);
-       }
-
-       return ch;
-}
-
-/*
- * Special function handlers
- */
-static void fn_enter(struct vc_data *vc)
-{
-       if (diacr) {
-               if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, diacr);
-               else {
-                       int c = conv_uni_to_8bit(diacr);
-                       if (c != -1)
-                               put_queue(vc, c);
-               }
-               diacr = 0;
-       }
-
-       put_queue(vc, 13);
-       if (vc_kbd_mode(kbd, VC_CRLF))
-               put_queue(vc, 10);
-}
-
-static void fn_caps_toggle(struct vc_data *vc)
-{
-       if (rep)
-               return;
-
-       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_caps_on(struct vc_data *vc)
-{
-       if (rep)
-               return;
-
-       set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_show_ptregs(struct vc_data *vc)
-{
-       struct pt_regs *regs = get_irq_regs();
-
-       if (regs)
-               show_regs(regs);
-}
-
-static void fn_hold(struct vc_data *vc)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (rep || !tty)
-               return;
-
-       /*
-        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
-        * these routines are also activated by ^S/^Q.
-        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
-        */
-       if (tty->stopped)
-               start_tty(tty);
-       else
-               stop_tty(tty);
-}
-
-static void fn_num(struct vc_data *vc)
-{
-       if (vc_kbd_mode(kbd, VC_APPLIC))
-               applkey(vc, 'P', 1);
-       else
-               fn_bare_num(vc);
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void fn_bare_num(struct vc_data *vc)
-{
-       if (!rep)
-               chg_vc_kbd_led(kbd, VC_NUMLOCK);
-}
-
-static void fn_lastcons(struct vc_data *vc)
-{
-       /* switch to the last used console, ChN */
-       set_console(last_console);
-}
-
-static void fn_dec_console(struct vc_data *vc)
-{
-       int i, cur = fg_console;
-
-       /* Currently switching?  Queue this next switch relative to that. */
-       if (want_console != -1)
-               cur = want_console;
-
-       for (i = cur - 1; i != cur; i--) {
-               if (i == -1)
-                       i = MAX_NR_CONSOLES - 1;
-               if (vc_cons_allocated(i))
-                       break;
-       }
-       set_console(i);
-}
-
-static void fn_inc_console(struct vc_data *vc)
-{
-       int i, cur = fg_console;
-
-       /* Currently switching?  Queue this next switch relative to that. */
-       if (want_console != -1)
-               cur = want_console;
-
-       for (i = cur+1; i != cur; i++) {
-               if (i == MAX_NR_CONSOLES)
-                       i = 0;
-               if (vc_cons_allocated(i))
-                       break;
-       }
-       set_console(i);
-}
-
-static void fn_send_intr(struct vc_data *vc)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (!tty)
-               return;
-       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       con_schedule_flip(tty);
-}
-
-static void fn_scroll_forw(struct vc_data *vc)
-{
-       scrollfront(vc, 0);
-}
-
-static void fn_scroll_back(struct vc_data *vc)
-{
-       scrollback(vc, 0);
-}
-
-static void fn_show_mem(struct vc_data *vc)
-{
-       show_mem();
-}
-
-static void fn_show_state(struct vc_data *vc)
-{
-       show_state();
-}
-
-static void fn_boot_it(struct vc_data *vc)
-{
-       ctrl_alt_del();
-}
-
-static void fn_compose(struct vc_data *vc)
-{
-       dead_key_next = true;
-}
-
-static void fn_spawn_con(struct vc_data *vc)
-{
-       spin_lock(&vt_spawn_con.lock);
-       if (vt_spawn_con.pid)
-               if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
-                       put_pid(vt_spawn_con.pid);
-                       vt_spawn_con.pid = NULL;
-               }
-       spin_unlock(&vt_spawn_con.lock);
-}
-
-static void fn_SAK(struct vc_data *vc)
-{
-       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-       schedule_work(SAK_work);
-}
-
-static void fn_null(struct vc_data *vc)
-{
-       compute_shiftstate();
-}
-
-/*
- * Special key handlers
- */
-static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
-{
-}
-
-static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-       if (value >= ARRAY_SIZE(fn_handler))
-               return;
-       if ((kbd->kbdmode == VC_RAW ||
-            kbd->kbdmode == VC_MEDIUMRAW) &&
-            value != KVAL(K_SAK))
-               return;         /* SAK is allowed even in raw mode */
-       fn_handler[value](vc);
-}
-
-static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       pr_err("k_lowercase was called - impossible\n");
-}
-
-static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-       if (up_flag)
-               return;         /* no action, if this is a key release */
-
-       if (diacr)
-               value = handle_diacr(vc, value);
-
-       if (dead_key_next) {
-               dead_key_next = false;
-               diacr = value;
-               return;
-       }
-       if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, value);
-       else {
-               int c = conv_uni_to_8bit(value);
-               if (c != -1)
-                       put_queue(vc, c);
-       }
-}
-
-/*
- * Handle dead key. Note that we now may have several
- * dead keys modifying the same character. Very useful
- * for Vietnamese.
- */
-static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       diacr = (diacr ? handle_diacr(vc, value) : value);
-}
-
-static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
-}
-
-static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_deadunicode(vc, value, up_flag);
-}
-
-/*
- * Obsolete - for backwards compatibility only
- */
-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
-
-       k_deadunicode(vc, ret_diacr[value], up_flag);
-}
-
-static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       set_console(value);
-}
-
-static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       if ((unsigned)value < ARRAY_SIZE(func_table)) {
-               if (func_table[value])
-                       puts_queue(vc, func_table[value]);
-       } else
-               pr_err("k_fn called with value=%d\n", value);
-}
-
-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const char cur_chars[] = "BDCA";
-
-       if (up_flag)
-               return;
-
-       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
-}
-
-static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const char pad_chars[] = "0123456789+-*/\015,.?()#";
-       static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
-
-       if (up_flag)
-               return;         /* no action, if this is a key release */
-
-       /* kludge... shift forces cursor/number keys */
-       if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
-               applkey(vc, app_map[value], 1);
-               return;
-       }
-
-       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
-
-               switch (value) {
-               case KVAL(K_PCOMMA):
-               case KVAL(K_PDOT):
-                       k_fn(vc, KVAL(K_REMOVE), 0);
-                       return;
-               case KVAL(K_P0):
-                       k_fn(vc, KVAL(K_INSERT), 0);
-                       return;
-               case KVAL(K_P1):
-                       k_fn(vc, KVAL(K_SELECT), 0);
-                       return;
-               case KVAL(K_P2):
-                       k_cur(vc, KVAL(K_DOWN), 0);
-                       return;
-               case KVAL(K_P3):
-                       k_fn(vc, KVAL(K_PGDN), 0);
-                       return;
-               case KVAL(K_P4):
-                       k_cur(vc, KVAL(K_LEFT), 0);
-                       return;
-               case KVAL(K_P6):
-                       k_cur(vc, KVAL(K_RIGHT), 0);
-                       return;
-               case KVAL(K_P7):
-                       k_fn(vc, KVAL(K_FIND), 0);
-                       return;
-               case KVAL(K_P8):
-                       k_cur(vc, KVAL(K_UP), 0);
-                       return;
-               case KVAL(K_P9):
-                       k_fn(vc, KVAL(K_PGUP), 0);
-                       return;
-               case KVAL(K_P5):
-                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
-                       return;
-               }
-       }
-
-       put_queue(vc, pad_chars[value]);
-       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
-               put_queue(vc, 10);
-}
-
-static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       int old_state = shift_state;
-
-       if (rep)
-               return;
-       /*
-        * Mimic typewriter:
-        * a CapsShift key acts like Shift but undoes CapsLock
-        */
-       if (value == KVAL(K_CAPSSHIFT)) {
-               value = KVAL(K_SHIFT);
-               if (!up_flag)
-                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
-       }
-
-       if (up_flag) {
-               /*
-                * handle the case that two shift or control
-                * keys are depressed simultaneously
-                */
-               if (shift_down[value])
-                       shift_down[value]--;
-       } else
-               shift_down[value]++;
-
-       if (shift_down[value])
-               shift_state |= (1 << value);
-       else
-               shift_state &= ~(1 << value);
-
-       /* kludge */
-       if (up_flag && shift_state != old_state && npadch != -1) {
-               if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, npadch);
-               else
-                       put_queue(vc, npadch & 0xff);
-               npadch = -1;
-       }
-}
-
-static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       if (vc_kbd_mode(kbd, VC_META)) {
-               put_queue(vc, '\033');
-               put_queue(vc, value);
-       } else
-               put_queue(vc, value | 0x80);
-}
-
-static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       int base;
-
-       if (up_flag)
-               return;
-
-       if (value < 10) {
-               /* decimal input of code, while Alt depressed */
-               base = 10;
-       } else {
-               /* hexadecimal input of code, while AltGr depressed */
-               value -= 10;
-               base = 16;
-       }
-
-       if (npadch == -1)
-               npadch = value;
-       else
-               npadch = npadch * base + value;
-}
-
-static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag || rep)
-               return;
-
-       chg_vc_kbd_lock(kbd, value);
-}
-
-static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_shift(vc, value, up_flag);
-       if (up_flag || rep)
-               return;
-
-       chg_vc_kbd_slock(kbd, value);
-       /* try to make Alt, oops, AltGr and such work */
-       if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
-               kbd->slockstate = 0;
-               chg_vc_kbd_slock(kbd, value);
-       }
-}
-
-/* by default, 300ms interval for combination release */
-static unsigned brl_timeout = 300;
-MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
-module_param(brl_timeout, uint, 0644);
-
-static unsigned brl_nbchords = 1;
-MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
-module_param(brl_nbchords, uint, 0644);
-
-static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
-{
-       static unsigned long chords;
-       static unsigned committed;
-
-       if (!brl_nbchords)
-               k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
-       else {
-               committed |= pattern;
-               chords++;
-               if (chords == brl_nbchords) {
-                       k_unicode(vc, BRL_UC_ROW | committed, up_flag);
-                       chords = 0;
-                       committed = 0;
-               }
-       }
-}
-
-static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static unsigned pressed, committing;
-       static unsigned long releasestart;
-
-       if (kbd->kbdmode != VC_UNICODE) {
-               if (!up_flag)
-                       pr_warning("keyboard mode must be unicode for braille patterns\n");
-               return;
-       }
-
-       if (!value) {
-               k_unicode(vc, BRL_UC_ROW, up_flag);
-               return;
-       }
-
-       if (value > 8)
-               return;
-
-       if (!up_flag) {
-               pressed |= 1 << (value - 1);
-               if (!brl_timeout)
-                       committing = pressed;
-       } else if (brl_timeout) {
-               if (!committing ||
-                   time_after(jiffies,
-                              releasestart + msecs_to_jiffies(brl_timeout))) {
-                       committing = pressed;
-                       releasestart = jiffies;
-               }
-               pressed &= ~(1 << (value - 1));
-               if (!pressed && committing) {
-                       k_brlcommit(vc, committing, 0);
-                       committing = 0;
-               }
-       } else {
-               if (committing) {
-                       k_brlcommit(vc, committing, 0);
-                       committing = 0;
-               }
-               pressed &= ~(1 << (value - 1));
-       }
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-unsigned char getledstate(void)
-{
-       return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led)
-{
-       if (!(led & ~7)) {
-               ledioctl = led;
-               kbd->ledmode = LED_SHOW_IOCTL;
-       } else
-               kbd->ledmode = LED_SHOW_FLAGS;
-
-       set_leds();
-}
-
-static inline unsigned char getleds(void)
-{
-       struct kbd_struct *kbd = kbd_table + fg_console;
-       unsigned char leds;
-       int i;
-
-       if (kbd->ledmode == LED_SHOW_IOCTL)
-               return ledioctl;
-
-       leds = kbd->ledflagstate;
-
-       if (kbd->ledmode == LED_SHOW_MEM) {
-               for (i = 0; i < 3; i++)
-                       if (ledptrs[i].valid) {
-                               if (*ledptrs[i].addr & ledptrs[i].mask)
-                                       leds |= (1 << i);
-                               else
-                                       leds &= ~(1 << i);
-                       }
-       }
-       return leds;
-}
-
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
-       unsigned char leds = *(unsigned char *)data;
-
-       if (test_bit(EV_LED, handle->dev->evbit)) {
-               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-       }
-
-       return 0;
-}
-
-/*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates form VT to
- * update led state.
- */
-static void kbd_bh(unsigned long dummy)
-{
-       unsigned char leds = getleds();
-
-       if (leds != ledstate) {
-               input_handler_for_each_handle(&kbd_handler, &leds,
-                                             kbd_update_leds_helper);
-               ledstate = leds;
-       }
-}
-
-DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
-
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
-    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
-    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
-    defined(CONFIG_AVR32)
-
-#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
-                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
-
-static const unsigned short x86_keycodes[256] =
-       { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-        80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
-       284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
-       367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
-       360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
-       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
-       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
-       264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
-       377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
-       308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
-       332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
-
-#ifdef CONFIG_SPARC
-static int sparc_l1_a_state;
-extern void sun_do_break(void);
-#endif
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode,
-                      unsigned char up_flag)
-{
-       int code;
-
-       switch (keycode) {
-
-       case KEY_PAUSE:
-               put_queue(vc, 0xe1);
-               put_queue(vc, 0x1d | up_flag);
-               put_queue(vc, 0x45 | up_flag);
-               break;
-
-       case KEY_HANGEUL:
-               if (!up_flag)
-                       put_queue(vc, 0xf2);
-               break;
-
-       case KEY_HANJA:
-               if (!up_flag)
-                       put_queue(vc, 0xf1);
-               break;
-
-       case KEY_SYSRQ:
-               /*
-                * Real AT keyboards (that's what we're trying
-                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
-                * pressing PrtSc/SysRq alone, but simply 0x54
-                * when pressing Alt+PrtSc/SysRq.
-                */
-               if (test_bit(KEY_LEFTALT, key_down) ||
-                   test_bit(KEY_RIGHTALT, key_down)) {
-                       put_queue(vc, 0x54 | up_flag);
-               } else {
-                       put_queue(vc, 0xe0);
-                       put_queue(vc, 0x2a | up_flag);
-                       put_queue(vc, 0xe0);
-                       put_queue(vc, 0x37 | up_flag);
-               }
-               break;
-
-       default:
-               if (keycode > 255)
-                       return -1;
-
-               code = x86_keycodes[keycode];
-               if (!code)
-                       return -1;
-
-               if (code & 0x100)
-                       put_queue(vc, 0xe0);
-               put_queue(vc, (code & 0x7f) | up_flag);
-
-               break;
-       }
-
-       return 0;
-}
-
-#else
-
-#define HW_RAW(dev)    0
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
-{
-       if (keycode > 127)
-               return -1;
-
-       put_queue(vc, keycode | up_flag);
-       return 0;
-}
-#endif
-
-static void kbd_rawcode(unsigned char data)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-
-       kbd = kbd_table + vc->vc_num;
-       if (kbd->kbdmode == VC_RAW)
-               put_queue(vc, data);
-}
-
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       unsigned short keysym, *key_map;
-       unsigned char type;
-       bool raw_mode;
-       struct tty_struct *tty;
-       int shift_final;
-       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
-       int rc;
-
-       tty = vc->port.tty;
-
-       if (tty && (!tty->driver_data)) {
-               /* No driver data? Strange. Okay we fix it then. */
-               tty->driver_data = vc;
-       }
-
-       kbd = kbd_table + vc->vc_num;
-
-#ifdef CONFIG_SPARC
-       if (keycode == KEY_STOP)
-               sparc_l1_a_state = down;
-#endif
-
-       rep = (down == 2);
-
-       raw_mode = (kbd->kbdmode == VC_RAW);
-       if (raw_mode && !hw_raw)
-               if (emulate_raw(vc, keycode, !down << 7))
-                       if (keycode < BTN_MISC && printk_ratelimit())
-                               pr_warning("can't emulate rawmode for keycode %d\n",
-                                          keycode);
-
-#ifdef CONFIG_SPARC
-       if (keycode == KEY_A && sparc_l1_a_state) {
-               sparc_l1_a_state = false;
-               sun_do_break();
-       }
-#endif
-
-       if (kbd->kbdmode == VC_MEDIUMRAW) {
-               /*
-                * This is extended medium raw mode, with keys above 127
-                * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
-                * the 'up' flag if needed. 0 is reserved, so this shouldn't
-                * interfere with anything else. The two bytes after 0 will
-                * always have the up flag set not to interfere with older
-                * applications. This allows for 16384 different keycodes,
-                * which should be enough.
-                */
-               if (keycode < 128) {
-                       put_queue(vc, keycode | (!down << 7));
-               } else {
-                       put_queue(vc, !down << 7);
-                       put_queue(vc, (keycode >> 7) | 0x80);
-                       put_queue(vc, keycode | 0x80);
-               }
-               raw_mode = true;
-       }
-
-       if (down)
-               set_bit(keycode, key_down);
-       else
-               clear_bit(keycode, key_down);
-
-       if (rep &&
-           (!vc_kbd_mode(kbd, VC_REPEAT) ||
-            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
-               /*
-                * Don't repeat a key if the input buffers are not empty and the
-                * characters get aren't echoed locally. This makes key repeat
-                * usable with slow applications and under heavy loads.
-                */
-               return;
-       }
-
-       param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
-       param.ledstate = kbd->ledflagstate;
-       key_map = key_maps[shift_final];
-
-       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                       KBD_KEYCODE, &param);
-       if (rc == NOTIFY_STOP || !key_map) {
-               atomic_notifier_call_chain(&keyboard_notifier_list,
-                                          KBD_UNBOUND_KEYCODE, &param);
-               compute_shiftstate();
-               kbd->slockstate = 0;
-               return;
-       }
-
-       if (keycode < NR_KEYS)
-               keysym = key_map[keycode];
-       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
-               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
-       else
-               return;
-
-       type = KTYP(keysym);
-
-       if (type < 0xf0) {
-               param.value = keysym;
-               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                               KBD_UNICODE, &param);
-               if (rc != NOTIFY_STOP)
-                       if (down && !raw_mode)
-                               to_utf8(vc, keysym);
-               return;
-       }
-
-       type -= 0xf0;
-
-       if (type == KT_LETTER) {
-               type = KT_LATIN;
-               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-                       key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
-                       if (key_map)
-                               keysym = key_map[keycode];
-               }
-       }
-
-       param.value = keysym;
-       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                       KBD_KEYSYM, &param);
-       if (rc == NOTIFY_STOP)
-               return;
-
-       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
-               return;
-
-       (*k_handler[type])(vc, keysym & 0xff, !down);
-
-       param.ledstate = kbd->ledflagstate;
-       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
-
-       if (type != KT_SLOCK)
-               kbd->slockstate = 0;
-}
-
-static void kbd_event(struct input_handle *handle, unsigned int event_type,
-                     unsigned int event_code, int value)
-{
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&kbd_event_lock);
-
-       if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
-               kbd_rawcode(value);
-       if (event_type == EV_KEY)
-               kbd_keycode(event_code, value, HW_RAW(handle->dev));
-
-       spin_unlock(&kbd_event_lock);
-
-       tasklet_schedule(&keyboard_tasklet);
-       do_poke_blanked_console = 1;
-       schedule_console_callback();
-}
-
-static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
-{
-       int i;
-
-       if (test_bit(EV_SND, dev->evbit))
-               return true;
-
-       if (test_bit(EV_KEY, dev->evbit)) {
-               for (i = KEY_RESERVED; i < BTN_MISC; i++)
-                       if (test_bit(i, dev->keybit))
-                               return true;
-               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
-                       if (test_bit(i, dev->keybit))
-                               return true;
-       }
-
-       return false;
-}
-
-/*
- * When a keyboard (or other input device) is found, the kbd_connect
- * function is called. The function then looks at the device, and if it
- * likes it, it can open it and get events from it. In this (kbd_connect)
- * function, we should decide which VT to bind that keyboard to initially.
- */
-static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
-                       const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "kbd";
-
-       error = input_register_handle(handle);
-       if (error)
-               goto err_free_handle;
-
-       error = input_open_device(handle);
-       if (error)
-               goto err_unregister_handle;
-
-       return 0;
-
- err_unregister_handle:
-       input_unregister_handle(handle);
- err_free_handle:
-       kfree(handle);
-       return error;
-}
-
-static void kbd_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-/*
- * Start keyboard handler on the new keyboard by refreshing LED state to
- * match the rest of the system.
- */
-static void kbd_start(struct input_handle *handle)
-{
-       tasklet_disable(&keyboard_tasklet);
-
-       if (ledstate != 0xff)
-               kbd_update_leds_helper(handle, &ledstate);
-
-       tasklet_enable(&keyboard_tasklet);
-}
-
-static const struct input_device_id kbd_ids[] = {
-       {
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_KEY) },
-        },
-
-       {
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_SND) },
-        },
-
-       { },    /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, kbd_ids);
-
-static struct input_handler kbd_handler = {
-       .event          = kbd_event,
-       .match          = kbd_match,
-       .connect        = kbd_connect,
-       .disconnect     = kbd_disconnect,
-       .start          = kbd_start,
-       .name           = "kbd",
-       .id_table       = kbd_ids,
-};
-
-int __init kbd_init(void)
-{
-       int i;
-       int error;
-
-        for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               kbd_table[i].ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].ledmode = LED_SHOW_FLAGS;
-               kbd_table[i].lockstate = KBD_DEFLOCK;
-               kbd_table[i].slockstate = 0;
-               kbd_table[i].modeflags = KBD_DEFMODE;
-               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-       }
-
-       error = input_register_handler(&kbd_handler);
-       if (error)
-               return error;
-
-       tasklet_enable(&keyboard_tasklet);
-       tasklet_schedule(&keyboard_tasklet);
-
-       return 0;
-}
diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c
deleted file mode 100644 (file)
index 04ef3ef..0000000
+++ /dev/null
@@ -1,2763 +0,0 @@
-/*
- * n_gsm.c GSM 0710 tty multiplexor
- * Copyright (c) 2009/10 Intel Corporation
- *
- * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *     * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
- *
- * TO DO:
- *     Mostly done:    ioctls for setting modes/timing
- *     Partly done:    hooks so you can pull off frames to non tty devs
- *     Restart DLCI 0 when it closes ?
- *     Test basic encoding
- *     Improve the tx engine
- *     Resolve tx side locking by adding a queue_head and routing
- *             all control traffic via it
- *     General tidy/document
- *     Review the locking/move to refcounts more (mux now moved to an
- *             alloc/free model ready)
- *     Use newest tty open/close port helpers and install hooks
- *     What to do about power functions ?
- *     Termios setting and negotiation
- *     Do we need a 'which mux are you' ioctl to correlate mux and tty sets
- *
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/tty_flip.h>
-#include <linux/tty_driver.h>
-#include <linux/serial.h>
-#include <linux/kfifo.h>
-#include <linux/skbuff.h>
-#include <linux/gsmmux.h>
-
-static int debug;
-module_param(debug, int, 0600);
-
-#define T1     (HZ/10)
-#define T2     (HZ/3)
-#define N2     3
-
-/* Use long timers for testing at low speed with debug on */
-#ifdef DEBUG_TIMING
-#define T1     HZ
-#define T2     (2 * HZ)
-#endif
-
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
-   limits so this is plenty */
-#define MAX_MRU 512
-#define MAX_MTU 512
-
-/*
- *     Each block of data we have queued to go out is in the form of
- *     a gsm_msg which holds everything we need in a link layer independant
- *     format
- */
-
-struct gsm_msg {
-       struct gsm_msg *next;
-       u8 addr;                /* DLCI address + flags */
-       u8 ctrl;                /* Control byte + flags */
-       unsigned int len;       /* Length of data block (can be zero) */
-       unsigned char *data;    /* Points into buffer but not at the start */
-       unsigned char buffer[0];
-};
-
-/*
- *     Each active data link has a gsm_dlci structure associated which ties
- *     the link layer to an optional tty (if the tty side is open). To avoid
- *     complexity right now these are only ever freed up when the mux is
- *     shut down.
- *
- *     At the moment we don't free DLCI objects until the mux is torn down
- *     this avoid object life time issues but might be worth review later.
- */
-
-struct gsm_dlci {
-       struct gsm_mux *gsm;
-       int addr;
-       int state;
-#define DLCI_CLOSED            0
-#define DLCI_OPENING           1       /* Sending SABM not seen UA */
-#define DLCI_OPEN              2       /* SABM/UA complete */
-#define DLCI_CLOSING           3       /* Sending DISC not seen UA/DM */
-
-       /* Link layer */
-       spinlock_t lock;        /* Protects the internal state */
-       struct timer_list t1;   /* Retransmit timer for SABM and UA */
-       int retries;
-       /* Uplink tty if active */
-       struct tty_port port;   /* The tty bound to this DLCI if there is one */
-       struct kfifo *fifo;     /* Queue fifo for the DLCI */
-       struct kfifo _fifo;     /* For new fifo API porting only */
-       int adaption;           /* Adaption layer in use */
-       u32 modem_rx;           /* Our incoming virtual modem lines */
-       u32 modem_tx;           /* Our outgoing modem lines */
-       int dead;               /* Refuse re-open */
-       /* Flow control */
-       int throttled;          /* Private copy of throttle state */
-       int constipated;        /* Throttle status for outgoing */
-       /* Packetised I/O */
-       struct sk_buff *skb;    /* Frame being sent */
-       struct sk_buff_head skb_list;   /* Queued frames */
-       /* Data handling callback */
-       void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
-};
-
-/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
-
-#define NUM_DLCI               64
-
-/*
- *     DLCI 0 is used to pass control blocks out of band of the data
- *     flow (and with a higher link priority). One command can be outstanding
- *     at a time and we use this structure to manage them. They are created
- *     and destroyed by the user context, and updated by the receive paths
- *     and timers
- */
-
-struct gsm_control {
-       u8 cmd;         /* Command we are issuing */
-       u8 *data;       /* Data for the command in case we retransmit */
-       int len;        /* Length of block for retransmission */
-       int done;       /* Done flag */
-       int error;      /* Error if any */
-};
-
-/*
- *     Each GSM mux we have is represented by this structure. If we are
- *     operating as an ldisc then we use this structure as our ldisc
- *     state. We need to sort out lifetimes and locking with respect
- *     to the gsm mux array. For now we don't free DLCI objects that
- *     have been instantiated until the mux itself is terminated.
- *
- *     To consider further: tty open versus mux shutdown.
- */
-
-struct gsm_mux {
-       struct tty_struct *tty;         /* The tty our ldisc is bound to */
-       spinlock_t lock;
-
-       /* Events on the GSM channel */
-       wait_queue_head_t event;
-
-       /* Bits for GSM mode decoding */
-
-       /* Framing Layer */
-       unsigned char *buf;
-       int state;
-#define GSM_SEARCH             0
-#define GSM_START              1
-#define GSM_ADDRESS            2
-#define GSM_CONTROL            3
-#define GSM_LEN                        4
-#define GSM_DATA               5
-#define GSM_FCS                        6
-#define GSM_OVERRUN            7
-       unsigned int len;
-       unsigned int address;
-       unsigned int count;
-       int escape;
-       int encoding;
-       u8 control;
-       u8 fcs;
-       u8 *txframe;                    /* TX framing buffer */
-
-       /* Methods for the receiver side */
-       void (*receive)(struct gsm_mux *gsm, u8 ch);
-       void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
-       /* And transmit side */
-       int (*output)(struct gsm_mux *mux, u8 *data, int len);
-
-       /* Link Layer */
-       unsigned int mru;
-       unsigned int mtu;
-       int initiator;                  /* Did we initiate connection */
-       int dead;                       /* Has the mux been shut down */
-       struct gsm_dlci *dlci[NUM_DLCI];
-       int constipated;                /* Asked by remote to shut up */
-
-       spinlock_t tx_lock;
-       unsigned int tx_bytes;          /* TX data outstanding */
-#define TX_THRESH_HI           8192
-#define TX_THRESH_LO           2048
-       struct gsm_msg *tx_head;        /* Pending data packets */
-       struct gsm_msg *tx_tail;
-
-       /* Control messages */
-       struct timer_list t2_timer;     /* Retransmit timer for commands */
-       int cretries;                   /* Command retry counter */
-       struct gsm_control *pending_cmd;/* Our current pending command */
-       spinlock_t control_lock;        /* Protects the pending command */
-
-       /* Configuration */
-       int adaption;           /* 1 or 2 supported */
-       u8 ftype;               /* UI or UIH */
-       int t1, t2;             /* Timers in 1/100th of a sec */
-       int n2;                 /* Retry count */
-
-       /* Statistics (not currently exposed) */
-       unsigned long bad_fcs;
-       unsigned long malformed;
-       unsigned long io_error;
-       unsigned long bad_size;
-       unsigned long unsupported;
-};
-
-
-/*
- *     Mux objects - needed so that we can translate a tty index into the
- *     relevant mux and DLCI.
- */
-
-#define MAX_MUX                4                       /* 256 minors */
-static struct gsm_mux *gsm_mux[MAX_MUX];       /* GSM muxes */
-static spinlock_t gsm_mux_lock;
-
-/*
- *     This section of the driver logic implements the GSM encodings
- *     both the basic and the 'advanced'. Reliable transport is not
- *     supported.
- */
-
-#define CR                     0x02
-#define EA                     0x01
-#define        PF                      0x10
-
-/* I is special: the rest are ..*/
-#define RR                     0x01
-#define UI                     0x03
-#define RNR                    0x05
-#define REJ                    0x09
-#define DM                     0x0F
-#define SABM                   0x2F
-#define DISC                   0x43
-#define UA                     0x63
-#define        UIH                     0xEF
-
-/* Channel commands */
-#define CMD_NSC                        0x09
-#define CMD_TEST               0x11
-#define CMD_PSC                        0x21
-#define CMD_RLS                        0x29
-#define CMD_FCOFF              0x31
-#define CMD_PN                 0x41
-#define CMD_RPN                        0x49
-#define CMD_FCON               0x51
-#define CMD_CLD                        0x61
-#define CMD_SNC                        0x69
-#define CMD_MSC                        0x71
-
-/* Virtual modem bits */
-#define MDM_FC                 0x01
-#define MDM_RTC                        0x02
-#define MDM_RTR                        0x04
-#define MDM_IC                 0x20
-#define MDM_DV                 0x40
-
-#define GSM0_SOF               0xF9
-#define GSM1_SOF               0x7E
-#define GSM1_ESCAPE            0x7D
-#define GSM1_ESCAPE_BITS       0x20
-#define XON                    0x11
-#define XOFF                   0x13
-
-static const struct tty_port_operations gsm_port_ops;
-
-/*
- *     CRC table for GSM 0710
- */
-
-static const u8 gsm_fcs8[256] = {
-       0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
-       0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
-       0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
-       0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
-       0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
-       0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
-       0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
-       0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
-       0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
-       0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
-       0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
-       0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
-       0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
-       0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
-       0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
-       0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
-       0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
-       0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
-       0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
-       0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
-       0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
-       0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
-       0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
-       0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
-       0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
-       0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
-       0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
-       0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
-       0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
-       0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
-       0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
-       0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
-};
-
-#define INIT_FCS       0xFF
-#define GOOD_FCS       0xCF
-
-/**
- *     gsm_fcs_add     -       update FCS
- *     @fcs: Current FCS
- *     @c: Next data
- *
- *     Update the FCS to include c. Uses the algorithm in the specification
- *     notes.
- */
-
-static inline u8 gsm_fcs_add(u8 fcs, u8 c)
-{
-       return gsm_fcs8[fcs ^ c];
-}
-
-/**
- *     gsm_fcs_add_block       -       update FCS for a block
- *     @fcs: Current FCS
- *     @c: buffer of data
- *     @len: length of buffer
- *
- *     Update the FCS to include c. Uses the algorithm in the specification
- *     notes.
- */
-
-static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
-{
-       while (len--)
-               fcs = gsm_fcs8[fcs ^ *c++];
-       return fcs;
-}
-
-/**
- *     gsm_read_ea             -       read a byte into an EA
- *     @val: variable holding value
- *     c: byte going into the EA
- *
- *     Processes one byte of an EA. Updates the passed variable
- *     and returns 1 if the EA is now completely read
- */
-
-static int gsm_read_ea(unsigned int *val, u8 c)
-{
-       /* Add the next 7 bits into the value */
-       *val <<= 7;
-       *val |= c >> 1;
-       /* Was this the last byte of the EA 1 = yes*/
-       return c & EA;
-}
-
-/**
- *     gsm_encode_modem        -       encode modem data bits
- *     @dlci: DLCI to encode from
- *
- *     Returns the correct GSM encoded modem status bits (6 bit field) for
- *     the current status of the DLCI and attached tty object
- */
-
-static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
-{
-       u8 modembits = 0;
-       /* FC is true flow control not modem bits */
-       if (dlci->throttled)
-               modembits |= MDM_FC;
-       if (dlci->modem_tx & TIOCM_DTR)
-               modembits |= MDM_RTC;
-       if (dlci->modem_tx & TIOCM_RTS)
-               modembits |= MDM_RTR;
-       if (dlci->modem_tx & TIOCM_RI)
-               modembits |= MDM_IC;
-       if (dlci->modem_tx & TIOCM_CD)
-               modembits |= MDM_DV;
-       return modembits;
-}
-
-/**
- *     gsm_print_packet        -       display a frame for debug
- *     @hdr: header to print before decode
- *     @addr: address EA from the frame
- *     @cr: C/R bit from the frame
- *     @control: control including PF bit
- *     @data: following data bytes
- *     @dlen: length of data
- *
- *     Displays a packet in human readable format for debugging purposes. The
- *     style is based on amateur radio LAP-B dump display.
- */
-
-static void gsm_print_packet(const char *hdr, int addr, int cr,
-                                       u8 control, const u8 *data, int dlen)
-{
-       if (!(debug & 1))
-               return;
-
-       printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
-
-       switch (control & ~PF) {
-       case SABM:
-               printk(KERN_CONT "SABM");
-               break;
-       case UA:
-               printk(KERN_CONT "UA");
-               break;
-       case DISC:
-               printk(KERN_CONT "DISC");
-               break;
-       case DM:
-               printk(KERN_CONT "DM");
-               break;
-       case UI:
-               printk(KERN_CONT "UI");
-               break;
-       case UIH:
-               printk(KERN_CONT "UIH");
-               break;
-       default:
-               if (!(control & 0x01)) {
-                       printk(KERN_CONT "I N(S)%d N(R)%d",
-                               (control & 0x0E) >> 1, (control & 0xE)>> 5);
-               } else switch (control & 0x0F) {
-               case RR:
-                       printk("RR(%d)", (control & 0xE0) >> 5);
-                       break;
-               case RNR:
-                       printk("RNR(%d)", (control & 0xE0) >> 5);
-                       break;
-               case REJ:
-                       printk("REJ(%d)", (control & 0xE0) >> 5);
-                       break;
-               default:
-                       printk(KERN_CONT "[%02X]", control);
-               }
-       }
-
-       if (control & PF)
-               printk(KERN_CONT "(P)");
-       else
-               printk(KERN_CONT "(F)");
-
-       if (dlen) {
-               int ct = 0;
-               while (dlen--) {
-                       if (ct % 8 == 0)
-                               printk(KERN_CONT "\n    ");
-                       printk(KERN_CONT "%02X ", *data++);
-                       ct++;
-               }
-       }
-       printk(KERN_CONT "\n");
-}
-
-
-/*
- *     Link level transmission side
- */
-
-/**
- *     gsm_stuff_packet        -       bytestuff a packet
- *     @ibuf: input
- *     @obuf: output
- *     @len: length of input
- *
- *     Expand a buffer by bytestuffing it. The worst case size change
- *     is doubling and the caller is responsible for handing out
- *     suitable sized buffers.
- */
-
-static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
-{
-       int olen = 0;
-       while (len--) {
-               if (*input == GSM1_SOF || *input == GSM1_ESCAPE
-                   || *input == XON || *input == XOFF) {
-                       *output++ = GSM1_ESCAPE;
-                       *output++ = *input++ ^ GSM1_ESCAPE_BITS;
-                       olen++;
-               } else
-                       *output++ = *input++;
-               olen++;
-       }
-       return olen;
-}
-
-static void hex_packet(const unsigned char *p, int len)
-{
-       int i;
-       for (i = 0; i < len; i++) {
-               if (i && (i % 16) == 0)
-                       printk("\n");
-               printk("%02X ", *p++);
-       }
-       printk("\n");
-}
-
-/**
- *     gsm_send        -       send a control frame
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @cr: command/response bit
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a control frame. These do not go via the
- *     queueing logic as they should be transmitted ahead of data when
- *     they are needed.
- *
- *     FIXME: Lock versus data TX path
- */
-
-static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
-{
-       int len;
-       u8 cbuf[10];
-       u8 ibuf[3];
-
-       switch (gsm->encoding) {
-       case 0:
-               cbuf[0] = GSM0_SOF;
-               cbuf[1] = (addr << 2) | (cr << 1) | EA;
-               cbuf[2] = control;
-               cbuf[3] = EA;   /* Length of data = 0 */
-               cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
-               cbuf[5] = GSM0_SOF;
-               len = 6;
-               break;
-       case 1:
-       case 2:
-               /* Control frame + packing (but not frame stuffing) in mode 1 */
-               ibuf[0] = (addr << 2) | (cr << 1) | EA;
-               ibuf[1] = control;
-               ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
-               /* Stuffing may double the size worst case */
-               len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
-               /* Now add the SOF markers */
-               cbuf[0] = GSM1_SOF;
-               cbuf[len + 1] = GSM1_SOF;
-               /* FIXME: we can omit the lead one in many cases */
-               len += 2;
-               break;
-       default:
-               WARN_ON(1);
-               return;
-       }
-       gsm->output(gsm, cbuf, len);
-       gsm_print_packet("-->", addr, cr, control, NULL, 0);
-}
-
-/**
- *     gsm_response    -       send a control response
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a link level response frame.
- */
-
-static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
-{
-       gsm_send(gsm, addr, 0, control);
-}
-
-/**
- *     gsm_command     -       send a control command
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a link level command frame.
- */
-
-static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
-{
-       gsm_send(gsm, addr, 1, control);
-}
-
-/* Data transmission */
-
-#define HDR_LEN                6       /* ADDR CTRL [LEN.2] DATA FCS */
-
-/**
- *     gsm_data_alloc          -       allocate data frame
- *     @gsm: GSM mux
- *     @addr: DLCI address
- *     @len: length excluding header and FCS
- *     @ctrl: control byte
- *
- *     Allocate a new data buffer for sending frames with data. Space is left
- *     at the front for header bytes but that is treated as an implementation
- *     detail and not for the high level code to use
- */
-
-static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
-                                                               u8 ctrl)
-{
-       struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
-                                                               GFP_ATOMIC);
-       if (m == NULL)
-               return NULL;
-       m->data = m->buffer + HDR_LEN - 1;      /* Allow for FCS */
-       m->len = len;
-       m->addr = addr;
-       m->ctrl = ctrl;
-       m->next = NULL;
-       return m;
-}
-
-/**
- *     gsm_data_kick           -       poke the queue
- *     @gsm: GSM Mux
- *
- *     The tty device has called us to indicate that room has appeared in
- *     the transmit queue. Ram more data into the pipe if we have any
- *
- *     FIXME: lock against link layer control transmissions
- */
-
-static void gsm_data_kick(struct gsm_mux *gsm)
-{
-       struct gsm_msg *msg = gsm->tx_head;
-       int len;
-       int skip_sof = 0;
-
-       /* FIXME: We need to apply this solely to data messages */
-       if (gsm->constipated)
-               return;
-
-       while (gsm->tx_head != NULL) {
-               msg = gsm->tx_head;
-               if (gsm->encoding != 0) {
-                       gsm->txframe[0] = GSM1_SOF;
-                       len = gsm_stuff_frame(msg->data,
-                                               gsm->txframe + 1, msg->len);
-                       gsm->txframe[len + 1] = GSM1_SOF;
-                       len += 2;
-               } else {
-                       gsm->txframe[0] = GSM0_SOF;
-                       memcpy(gsm->txframe + 1 , msg->data, msg->len);
-                       gsm->txframe[msg->len + 1] = GSM0_SOF;
-                       len = msg->len + 2;
-               }
-
-               if (debug & 4) {
-                       printk("gsm_data_kick: \n");
-                       hex_packet(gsm->txframe, len);
-               }
-
-               if (gsm->output(gsm, gsm->txframe + skip_sof,
-                                               len - skip_sof) < 0)
-                       break;
-               /* FIXME: Can eliminate one SOF in many more cases */
-               gsm->tx_head = msg->next;
-               if (gsm->tx_head == NULL)
-                       gsm->tx_tail = NULL;
-               gsm->tx_bytes -= msg->len;
-               kfree(msg);
-               /* For a burst of frames skip the extra SOF within the
-                  burst */
-               skip_sof = 1;
-       }
-}
-
-/**
- *     __gsm_data_queue                -       queue a UI or UIH frame
- *     @dlci: DLCI sending the data
- *     @msg: message queued
- *
- *     Add data to the transmit queue and try and get stuff moving
- *     out of the mux tty if not already doing so. The Caller must hold
- *     the gsm tx lock.
- */
-
-static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       u8 *dp = msg->data;
-       u8 *fcs = dp + msg->len;
-
-       /* Fill in the header */
-       if (gsm->encoding == 0) {
-               if (msg->len < 128)
-                       *--dp = (msg->len << 1) | EA;
-               else {
-                       *--dp = (msg->len >> 6) | EA;
-                       *--dp = (msg->len & 127) << 1;
-               }
-       }
-
-       *--dp = msg->ctrl;
-       if (gsm->initiator)
-               *--dp = (msg->addr << 2) | 2 | EA;
-       else
-               *--dp = (msg->addr << 2) | EA;
-       *fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
-       /* Ugly protocol layering violation */
-       if (msg->ctrl == UI || msg->ctrl == (UI|PF))
-               *fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
-       *fcs = 0xFF - *fcs;
-
-       gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
-                                                       msg->data, msg->len);
-
-       /* Move the header back and adjust the length, also allow for the FCS
-          now tacked on the end */
-       msg->len += (msg->data - dp) + 1;
-       msg->data = dp;
-
-       /* Add to the actual output queue */
-       if (gsm->tx_tail)
-               gsm->tx_tail->next = msg;
-       else
-               gsm->tx_head = msg;
-       gsm->tx_tail = msg;
-       gsm->tx_bytes += msg->len;
-       gsm_data_kick(gsm);
-}
-
-/**
- *     gsm_data_queue          -       queue a UI or UIH frame
- *     @dlci: DLCI sending the data
- *     @msg: message queued
- *
- *     Add data to the transmit queue and try and get stuff moving
- *     out of the mux tty if not already doing so. Take the
- *     the gsm tx lock and dlci lock.
- */
-
-static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-       __gsm_data_queue(dlci, msg);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/**
- *     gsm_dlci_data_output    -       try and push data out of a DLCI
- *     @gsm: mux
- *     @dlci: the DLCI to pull data from
- *
- *     Pull data from a DLCI and send it into the transmit queue if there
- *     is data. Keep to the MRU of the mux. This path handles the usual tty
- *     interface which is a byte stream with optional modem data.
- *
- *     Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
-{
-       struct gsm_msg *msg;
-       u8 *dp;
-       int len, size;
-       int h = dlci->adaption - 1;
-
-       len = kfifo_len(dlci->fifo);
-       if (len == 0)
-               return 0;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu)
-               len = gsm->mtu;
-
-       size = len + h;
-
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-       switch (dlci->adaption) {
-       case 1: /* Unstructured */
-               break;
-       case 2: /* Unstructed with modem bits. Always one byte as we never
-                  send inline break data */
-               *dp += gsm_encode_modem(dlci);
-               len--;
-               break;
-       }
-       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
-       __gsm_data_queue(dlci, msg);
-       /* Bytes of data we used up */
-       return size;
-}
-
-/**
- *     gsm_dlci_data_output_framed  -  try and push data out of a DLCI
- *     @gsm: mux
- *     @dlci: the DLCI to pull data from
- *
- *     Pull data from a DLCI and send it into the transmit queue if there
- *     is data. Keep to the MRU of the mux. This path handles framed data
- *     queued as skbuffs to the DLCI.
- *
- *     Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
-                                               struct gsm_dlci *dlci)
-{
-       struct gsm_msg *msg;
-       u8 *dp;
-       int len, size;
-       int last = 0, first = 0;
-       int overhead = 0;
-
-       /* One byte per frame is used for B/F flags */
-       if (dlci->adaption == 4)
-               overhead = 1;
-
-       /* dlci->skb is locked by tx_lock */
-       if (dlci->skb == NULL) {
-               dlci->skb = skb_dequeue(&dlci->skb_list);
-               if (dlci->skb == NULL)
-                       return 0;
-               first = 1;
-       }
-       len = dlci->skb->len + overhead;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu) {
-               if (dlci->adaption == 3) {
-                       /* Over long frame, bin it */
-                       kfree_skb(dlci->skb);
-                       dlci->skb = NULL;
-                       return 0;
-               }
-               len = gsm->mtu;
-       } else
-               last = 1;
-
-       size = len + overhead;
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-
-       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
-               /* Flag byte to carry the start/end info */
-               *dp++ = last << 7 | first << 6 | 1;     /* EA */
-               len--;
-       }
-       memcpy(dp, skb_pull(dlci->skb, len), len);
-       __gsm_data_queue(dlci, msg);
-       if (last)
-               dlci->skb = NULL;
-       return size;
-}
-
-/**
- *     gsm_dlci_data_sweep             -       look for data to send
- *     @gsm: the GSM mux
- *
- *     Sweep the GSM mux channels in priority order looking for ones with
- *     data to send. We could do with optimising this scan a bit. We aim
- *     to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
- *     TX_THRESH_LO we get called again
- *
- *     FIXME: We should round robin between groups and in theory you can
- *     renegotiate DLCI priorities with optional stuff. Needs optimising.
- */
-
-static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
-{
-       int len;
-       /* Priority ordering: We should do priority with RR of the groups */
-       int i = 1;
-
-       while (i < NUM_DLCI) {
-               struct gsm_dlci *dlci;
-
-               if (gsm->tx_bytes > TX_THRESH_HI)
-                       break;
-               dlci = gsm->dlci[i];
-               if (dlci == NULL || dlci->constipated) {
-                       i++;
-                       continue;
-               }
-               if (dlci->adaption < 3)
-                       len = gsm_dlci_data_output(gsm, dlci);
-               else
-                       len = gsm_dlci_data_output_framed(gsm, dlci);
-               if (len < 0)
-                       break;
-               /* DLCI empty - try the next */
-               if (len == 0)
-                       i++;
-       }
-}
-
-/**
- *     gsm_dlci_data_kick      -       transmit if possible
- *     @dlci: DLCI to kick
- *
- *     Transmit data from this DLCI if the queue is empty. We can't rely on
- *     a tty wakeup except when we filled the pipe so we need to fire off
- *     new data ourselves in other cases.
- */
-
-static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-       /* If we have nothing running then we need to fire up */
-       if (dlci->gsm->tx_bytes == 0)
-               gsm_dlci_data_output(dlci->gsm, dlci);
-       else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
-               gsm_dlci_data_sweep(dlci->gsm);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/*
- *     Control message processing
- */
-
-
-/**
- *     gsm_control_reply       -       send a response frame to a control
- *     @gsm: gsm channel
- *     @cmd: the command to use
- *     @data: data to follow encoded info
- *     @dlen: length of data
- *
- *     Encode up and queue a UI/UIH frame containing our response.
- */
-
-static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
-                                       int dlen)
-{
-       struct gsm_msg *msg;
-       msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
-       msg->data[0] = (cmd & 0xFE) << 1 | EA;  /* Clear C/R */
-       msg->data[1] = (dlen << 1) | EA;
-       memcpy(msg->data + 2, data, dlen);
-       gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *     gsm_process_modem       -       process received modem status
- *     @tty: virtual tty bound to the DLCI
- *     @dlci: DLCI to affect
- *     @modem: modem bits (full EA)
- *
- *     Used when a modem control message or line state inline in adaption
- *     layer 2 is processed. Sort out the local modem state and throttles
- */
-
-static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
-                                                       u32 modem)
-{
-       int  mlines = 0;
-       u8 brk = modem >> 6;
-
-       /* Flow control/ready to communicate */
-       if (modem & MDM_FC) {
-               /* Need to throttle our output on this device */
-               dlci->constipated = 1;
-       }
-       if (modem & MDM_RTC) {
-               mlines |= TIOCM_DSR | TIOCM_DTR;
-               dlci->constipated = 0;
-               gsm_dlci_data_kick(dlci);
-       }
-       /* Map modem bits */
-       if (modem & MDM_RTR)
-               mlines |= TIOCM_RTS | TIOCM_CTS;
-       if (modem & MDM_IC)
-               mlines |= TIOCM_RI;
-       if (modem & MDM_DV)
-               mlines |= TIOCM_CD;
-
-       /* Carrier drop -> hangup */
-       if (tty) {
-               if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
-                       if (!(tty->termios->c_cflag & CLOCAL))
-                               tty_hangup(tty);
-               if (brk & 0x01)
-                       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       }
-       dlci->modem_rx = mlines;
-}
-
-/**
- *     gsm_control_modem       -       modem status received
- *     @gsm: GSM channel
- *     @data: data following command
- *     @clen: command length
- *
- *     We have received a modem status control message. This is used by
- *     the GSM mux protocol to pass virtual modem line status and optionally
- *     to indicate break signals. Unpack it, convert to Linux representation
- *     and if need be stuff a break message down the tty.
- */
-
-static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
-{
-       unsigned int addr = 0;
-       unsigned int modem = 0;
-       struct gsm_dlci *dlci;
-       int len = clen;
-       u8 *dp = data;
-       struct tty_struct *tty;
-
-       while (gsm_read_ea(&addr, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       /* Must be at least one byte following the EA */
-       len--;
-       if (len <= 0)
-               return;
-
-       addr >>= 1;
-       /* Closed port, or invalid ? */
-       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-               return;
-       dlci = gsm->dlci[addr];
-
-       while (gsm_read_ea(&modem, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       tty = tty_port_tty_get(&dlci->port);
-       gsm_process_modem(tty, dlci, modem);
-       if (tty) {
-               tty_wakeup(tty);
-               tty_kref_put(tty);
-       }
-       gsm_control_reply(gsm, CMD_MSC, data, clen);
-}
-
-/**
- *     gsm_control_rls         -       remote line status
- *     @gsm: GSM channel
- *     @data: data bytes
- *     @clen: data length
- *
- *     The modem sends us a two byte message on the control channel whenever
- *     it wishes to send us an error state from the virtual link. Stuff
- *     this into the uplink tty if present
- */
-
-static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
-{
-       struct tty_struct *tty;
-       unsigned int addr = 0 ;
-       u8 bits;
-       int len = clen;
-       u8 *dp = data;
-
-       while (gsm_read_ea(&addr, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       /* Must be at least one byte following ea */
-       len--;
-       if (len <= 0)
-               return;
-       addr >>= 1;
-       /* Closed port, or invalid ? */
-       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-               return;
-       /* No error ? */
-       bits = *dp;
-       if ((bits & 1) == 0)
-               return;
-       /* See if we have an uplink tty */
-       tty = tty_port_tty_get(&gsm->dlci[addr]->port);
-
-       if (tty) {
-               if (bits & 2)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               if (bits & 4)
-                       tty_insert_flip_char(tty, 0, TTY_PARITY);
-               if (bits & 8)
-                       tty_insert_flip_char(tty, 0, TTY_FRAME);
-               tty_flip_buffer_push(tty);
-               tty_kref_put(tty);
-       }
-       gsm_control_reply(gsm, CMD_RLS, data, clen);
-}
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
-
-/**
- *     gsm_control_message     -       DLCI 0 control processing
- *     @gsm: our GSM mux
- *     @command:  the command EA
- *     @data: data beyond the command/length EAs
- *     @clen: length
- *
- *     Input processor for control messages from the other end of the link.
- *     Processes the incoming request and queues a response frame or an
- *     NSC response if not supported
- */
-
-static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
-                                                       u8 *data, int clen)
-{
-       u8 buf[1];
-       switch (command) {
-       case CMD_CLD: {
-               struct gsm_dlci *dlci = gsm->dlci[0];
-               /* Modem wishes to close down */
-               if (dlci) {
-                       dlci->dead = 1;
-                       gsm->dead = 1;
-                       gsm_dlci_begin_close(dlci);
-               }
-               }
-               break;
-       case CMD_TEST:
-               /* Modem wishes to test, reply with the data */
-               gsm_control_reply(gsm, CMD_TEST, data, clen);
-               break;
-       case CMD_FCON:
-               /* Modem wants us to STFU */
-               gsm->constipated = 1;
-               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
-               break;
-       case CMD_FCOFF:
-               /* Modem can accept data again */
-               gsm->constipated = 0;
-               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
-               /* Kick the link in case it is idling */
-               gsm_data_kick(gsm);
-               break;
-       case CMD_MSC:
-               /* Out of band modem line change indicator for a DLCI */
-               gsm_control_modem(gsm, data, clen);
-               break;
-       case CMD_RLS:
-               /* Out of band error reception for a DLCI */
-               gsm_control_rls(gsm, data, clen);
-               break;
-       case CMD_PSC:
-               /* Modem wishes to enter power saving state */
-               gsm_control_reply(gsm, CMD_PSC, NULL, 0);
-               break;
-               /* Optional unsupported commands */
-       case CMD_PN:    /* Parameter negotiation */
-       case CMD_RPN:   /* Remote port negotation */
-       case CMD_SNC:   /* Service negotation command */
-       default:
-               /* Reply to bad commands with an NSC */
-               buf[0] = command;
-               gsm_control_reply(gsm, CMD_NSC, buf, 1);
-               break;
-       }
-}
-
-/**
- *     gsm_control_response    -       process a response to our control
- *     @gsm: our GSM mux
- *     @command: the command (response) EA
- *     @data: data beyond the command/length EA
- *     @clen: length
- *
- *     Process a response to an outstanding command. We only allow a single
- *     control message in flight so this is fairly easy. All the clean up
- *     is done by the caller, we just update the fields, flag it as done
- *     and return
- */
-
-static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
-                                                       u8 *data, int clen)
-{
-       struct gsm_control *ctrl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gsm->control_lock, flags);
-
-       ctrl = gsm->pending_cmd;
-       /* Does the reply match our command */
-       command |= 1;
-       if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
-               /* Our command was replied to, kill the retry timer */
-               del_timer(&gsm->t2_timer);
-               gsm->pending_cmd = NULL;
-               /* Rejected by the other end */
-               if (command == CMD_NSC)
-                       ctrl->error = -EOPNOTSUPP;
-               ctrl->done = 1;
-               wake_up(&gsm->event);
-       }
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *     gsm_control_transmit    -       send control packet
- *     @gsm: gsm mux
- *     @ctrl: frame to send
- *
- *     Send out a pending control command (called under control lock)
- */
-
-static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
-{
-       struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
-                                                       gsm->ftype|PF);
-       if (msg == NULL)
-               return;
-       msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
-       memcpy(msg->data + 1, ctrl->data, ctrl->len);
-       gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *     gsm_control_retransmit  -       retransmit a control frame
- *     @data: pointer to our gsm object
- *
- *     Called off the T2 timer expiry in order to retransmit control frames
- *     that have been lost in the system somewhere. The control_lock protects
- *     us from colliding with another sender or a receive completion event.
- *     In that situation the timer may still occur in a small window but
- *     gsm->pending_cmd will be NULL and we just let the timer expire.
- */
-
-static void gsm_control_retransmit(unsigned long data)
-{
-       struct gsm_mux *gsm = (struct gsm_mux *)data;
-       struct gsm_control *ctrl;
-       unsigned long flags;
-       spin_lock_irqsave(&gsm->control_lock, flags);
-       ctrl = gsm->pending_cmd;
-       if (ctrl) {
-               gsm->cretries--;
-               if (gsm->cretries == 0) {
-                       gsm->pending_cmd = NULL;
-                       ctrl->error = -ETIMEDOUT;
-                       ctrl->done = 1;
-                       spin_unlock_irqrestore(&gsm->control_lock, flags);
-                       wake_up(&gsm->event);
-                       return;
-               }
-               gsm_control_transmit(gsm, ctrl);
-               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-       }
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *     gsm_control_send        -       send a control frame on DLCI 0
- *     @gsm: the GSM channel
- *     @command: command  to send including CR bit
- *     @data: bytes of data (must be kmalloced)
- *     @len: length of the block to send
- *
- *     Queue and dispatch a control command. Only one command can be
- *     active at a time. In theory more can be outstanding but the matching
- *     gets really complicated so for now stick to one outstanding.
- */
-
-static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
-               unsigned int command, u8 *data, int clen)
-{
-       struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
-                                               GFP_KERNEL);
-       unsigned long flags;
-       if (ctrl == NULL)
-               return NULL;
-retry:
-       wait_event(gsm->event, gsm->pending_cmd == NULL);
-       spin_lock_irqsave(&gsm->control_lock, flags);
-       if (gsm->pending_cmd != NULL) {
-               spin_unlock_irqrestore(&gsm->control_lock, flags);
-               goto retry;
-       }
-       ctrl->cmd = command;
-       ctrl->data = data;
-       ctrl->len = clen;
-       gsm->pending_cmd = ctrl;
-       gsm->cretries = gsm->n2;
-       mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-       gsm_control_transmit(gsm, ctrl);
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-       return ctrl;
-}
-
-/**
- *     gsm_control_wait        -       wait for a control to finish
- *     @gsm: GSM mux
- *     @control: control we are waiting on
- *
- *     Waits for the control to complete or time out. Frees any used
- *     resources and returns 0 for success, or an error if the remote
- *     rejected or ignored the request.
- */
-
-static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
-{
-       int err;
-       wait_event(gsm->event, control->done == 1);
-       err = control->error;
-       kfree(control);
-       return err;
-}
-
-
-/*
- *     DLCI level handling: Needs krefs
- */
-
-/*
- *     State transitions and timers
- */
-
-/**
- *     gsm_dlci_close          -       a DLCI has closed
- *     @dlci: DLCI that closed
- *
- *     Perform processing when moving a DLCI into closed state. If there
- *     is an attached tty this is hung up
- */
-
-static void gsm_dlci_close(struct gsm_dlci *dlci)
-{
-       del_timer(&dlci->t1);
-       if (debug & 8)
-               printk("DLCI %d goes closed.\n", dlci->addr);
-       dlci->state = DLCI_CLOSED;
-       if (dlci->addr != 0) {
-               struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
-               if (tty) {
-                       tty_hangup(tty);
-                       tty_kref_put(tty);
-               }
-               kfifo_reset(dlci->fifo);
-       } else
-               dlci->gsm->dead = 1;
-       wake_up(&dlci->gsm->event);
-       /* A DLCI 0 close is a MUX termination so we need to kick that
-          back to userspace somehow */
-}
-
-/**
- *     gsm_dlci_open           -       a DLCI has opened
- *     @dlci: DLCI that opened
- *
- *     Perform processing when moving a DLCI into open state.
- */
-
-static void gsm_dlci_open(struct gsm_dlci *dlci)
-{
-       /* Note that SABM UA .. SABM UA first UA lost can mean that we go
-          open -> open */
-       del_timer(&dlci->t1);
-       /* This will let a tty open continue */
-       dlci->state = DLCI_OPEN;
-       if (debug & 8)
-               printk("DLCI %d goes open.\n", dlci->addr);
-       wake_up(&dlci->gsm->event);
-}
-
-/**
- *     gsm_dlci_t1             -       T1 timer expiry
- *     @dlci: DLCI that opened
- *
- *     The T1 timer handles retransmits of control frames (essentially of
- *     SABM and DISC). We resend the command until the retry count runs out
- *     in which case an opening port goes back to closed and a closing port
- *     is simply put into closed state (any further frames from the other
- *     end will get a DM response)
- */
-
-static void gsm_dlci_t1(unsigned long data)
-{
-       struct gsm_dlci *dlci = (struct gsm_dlci *)data;
-       struct gsm_mux *gsm = dlci->gsm;
-
-       switch (dlci->state) {
-       case DLCI_OPENING:
-               dlci->retries--;
-               if (dlci->retries) {
-                       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-               } else
-                       gsm_dlci_close(dlci);
-               break;
-       case DLCI_CLOSING:
-               dlci->retries--;
-               if (dlci->retries) {
-                       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-               } else
-                       gsm_dlci_close(dlci);
-               break;
-       }
-}
-
-/**
- *     gsm_dlci_begin_open     -       start channel open procedure
- *     @dlci: DLCI to open
- *
- *     Commence opening a DLCI from the Linux side. We issue SABM messages
- *     to the modem which should then reply with a UA, at which point we
- *     will move into open state. Opening is done asynchronously with retry
- *     running off timers and the responses.
- */
-
-static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
-               return;
-       dlci->retries = gsm->n2;
-       dlci->state = DLCI_OPENING;
-       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *     gsm_dlci_begin_close    -       start channel open procedure
- *     @dlci: DLCI to open
- *
- *     Commence closing a DLCI from the Linux side. We issue DISC messages
- *     to the modem which should then reply with a UA, at which point we
- *     will move into closed state. Closing is done asynchronously with retry
- *     off timers. We may also receive a DM reply from the other end which
- *     indicates the channel was already closed.
- */
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
-               return;
-       dlci->retries = gsm->n2;
-       dlci->state = DLCI_CLOSING;
-       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *     gsm_dlci_data           -       data arrived
- *     @dlci: channel
- *     @data: block of bytes received
- *     @len: length of received block
- *
- *     A UI or UIH frame has arrived which contains data for a channel
- *     other than the control channel. If the relevant virtual tty is
- *     open we shovel the bits down it, if not we drop them.
- */
-
-static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
-{
-       /* krefs .. */
-       struct tty_port *port = &dlci->port;
-       struct tty_struct *tty = tty_port_tty_get(port);
-       unsigned int modem = 0;
-
-       if (debug & 16)
-               printk("%d bytes for tty %p\n", len, tty);
-       if (tty) {
-               switch (dlci->adaption)  {
-                       /* Unsupported types */
-                       /* Packetised interruptible data */
-                       case 4:
-                               break;
-                       /* Packetised uininterruptible voice/data */
-                       case 3:
-                               break;
-                       /* Asynchronous serial with line state in each frame */
-                       case 2:
-                               while (gsm_read_ea(&modem, *data++) == 0) {
-                                       len--;
-                                       if (len == 0)
-                                               return;
-                               }
-                               gsm_process_modem(tty, dlci, modem);
-                       /* Line state will go via DLCI 0 controls only */
-                       case 1:
-                       default:
-                               tty_insert_flip_string(tty, data, len);
-                               tty_flip_buffer_push(tty);
-               }
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     gsm_dlci_control        -       data arrived on control channel
- *     @dlci: channel
- *     @data: block of bytes received
- *     @len: length of received block
- *
- *     A UI or UIH frame has arrived which contains data for DLCI 0 the
- *     control channel. This should contain a command EA followed by
- *     control data bytes. The command EA contains a command/response bit
- *     and we divide up the work accordingly.
- */
-
-static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
-{
-       /* See what command is involved */
-       unsigned int command = 0;
-       while (len-- > 0) {
-               if (gsm_read_ea(&command, *data++) == 1) {
-                       int clen = *data++;
-                       len--;
-                       /* FIXME: this is properly an EA */
-                       clen >>= 1;
-                       /* Malformed command ? */
-                       if (clen > len)
-                               return;
-                       if (command & 1)
-                               gsm_control_message(dlci->gsm, command,
-                                                               data, clen);
-                       else
-                               gsm_control_response(dlci->gsm, command,
-                                                               data, clen);
-                       return;
-               }
-       }
-}
-
-/*
- *     Allocate/Free DLCI channels
- */
-
-/**
- *     gsm_dlci_alloc          -       allocate a DLCI
- *     @gsm: GSM mux
- *     @addr: address of the DLCI
- *
- *     Allocate and install a new DLCI object into the GSM mux.
- *
- *     FIXME: review locking races
- */
-
-static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
-{
-       struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
-       if (dlci == NULL)
-               return NULL;
-       spin_lock_init(&dlci->lock);
-       dlci->fifo = &dlci->_fifo;
-       if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
-               kfree(dlci);
-               return NULL;
-       }
-
-       skb_queue_head_init(&dlci->skb_list);
-       init_timer(&dlci->t1);
-       dlci->t1.function = gsm_dlci_t1;
-       dlci->t1.data = (unsigned long)dlci;
-       tty_port_init(&dlci->port);
-       dlci->port.ops = &gsm_port_ops;
-       dlci->gsm = gsm;
-       dlci->addr = addr;
-       dlci->adaption = gsm->adaption;
-       dlci->state = DLCI_CLOSED;
-       if (addr)
-               dlci->data = gsm_dlci_data;
-       else
-               dlci->data = gsm_dlci_command;
-       gsm->dlci[addr] = dlci;
-       return dlci;
-}
-
-/**
- *     gsm_dlci_free           -       release DLCI
- *     @dlci: DLCI to destroy
- *
- *     Free up a DLCI. Currently to keep the lifetime rules sane we only
- *     clean up DLCI objects when the MUX closes rather than as the port
- *     is closed down on both the tty and mux levels.
- *
- *     Can sleep.
- */
-static void gsm_dlci_free(struct gsm_dlci *dlci)
-{
-       struct tty_struct *tty = tty_port_tty_get(&dlci->port);
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-       del_timer_sync(&dlci->t1);
-       dlci->gsm->dlci[dlci->addr] = NULL;
-       kfifo_free(dlci->fifo);
-       kfree(dlci);
-}
-
-
-/*
- *     LAPBish link layer logic
- */
-
-/**
- *     gsm_queue               -       a GSM frame is ready to process
- *     @gsm: pointer to our gsm mux
- *
- *     At this point in time a frame has arrived and been demangled from
- *     the line encoding. All the differences between the encodings have
- *     been handled below us and the frame is unpacked into the structures.
- *     The fcs holds the header FCS but any data FCS must be added here.
- */
-
-static void gsm_queue(struct gsm_mux *gsm)
-{
-       struct gsm_dlci *dlci;
-       u8 cr;
-       int address;
-       /* We have to sneak a look at the packet body to do the FCS.
-          A somewhat layering violation in the spec */
-
-       if ((gsm->control & ~PF) == UI)
-               gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
-       if (gsm->fcs != GOOD_FCS) {
-               gsm->bad_fcs++;
-               if (debug & 4)
-                       printk("BAD FCS %02x\n", gsm->fcs);
-               return;
-       }
-       address = gsm->address >> 1;
-       if (address >= NUM_DLCI)
-               goto invalid;
-
-       cr = gsm->address & 1;          /* C/R bit */
-
-       gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
-
-       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
-       dlci = gsm->dlci[address];
-
-       switch (gsm->control) {
-       case SABM|PF:
-               if (cr == 0)
-                       goto invalid;
-               if (dlci == NULL)
-                       dlci = gsm_dlci_alloc(gsm, address);
-               if (dlci == NULL)
-                       return;
-               if (dlci->dead)
-                       gsm_response(gsm, address, DM);
-               else {
-                       gsm_response(gsm, address, UA);
-                       gsm_dlci_open(dlci);
-               }
-               break;
-       case DISC|PF:
-               if (cr == 0)
-                       goto invalid;
-               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
-                       gsm_response(gsm, address, DM);
-                       return;
-               }
-               /* Real close complete */
-               gsm_response(gsm, address, UA);
-               gsm_dlci_close(dlci);
-               break;
-       case UA:
-       case UA|PF:
-               if (cr == 0 || dlci == NULL)
-                       break;
-               switch (dlci->state) {
-               case DLCI_CLOSING:
-                       gsm_dlci_close(dlci);
-                       break;
-               case DLCI_OPENING:
-                       gsm_dlci_open(dlci);
-                       break;
-               }
-               break;
-       case DM:        /* DM can be valid unsolicited */
-       case DM|PF:
-               if (cr)
-                       goto invalid;
-               if (dlci == NULL)
-                       return;
-               gsm_dlci_close(dlci);
-               break;
-       case UI:
-       case UI|PF:
-       case UIH:
-       case UIH|PF:
-#if 0
-               if (cr)
-                       goto invalid;
-#endif
-               if (dlci == NULL || dlci->state != DLCI_OPEN) {
-                       gsm_command(gsm, address, DM|PF);
-                       return;
-               }
-               dlci->data(dlci, gsm->buf, gsm->len);
-               break;
-       default:
-               goto invalid;
-       }
-       return;
-invalid:
-       gsm->malformed++;
-       return;
-}
-
-
-/**
- *     gsm0_receive    -       perform processing for non-transparency
- *     @gsm: gsm data for this ldisc instance
- *     @c: character
- *
- *     Receive bytes in gsm mode 0
- */
-
-static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
-{
-       switch (gsm->state) {
-       case GSM_SEARCH:        /* SOF marker */
-               if (c == GSM0_SOF) {
-                       gsm->state = GSM_ADDRESS;
-                       gsm->address = 0;
-                       gsm->len = 0;
-                       gsm->fcs = INIT_FCS;
-               }
-               break;          /* Address EA */
-       case GSM_ADDRESS:
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->address, c))
-                       gsm->state = GSM_CONTROL;
-               break;
-       case GSM_CONTROL:       /* Control Byte */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               gsm->control = c;
-               gsm->state = GSM_LEN;
-               break;
-       case GSM_LEN:           /* Length EA */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->len, c)) {
-                       if (gsm->len > gsm->mru) {
-                               gsm->bad_size++;
-                               gsm->state = GSM_SEARCH;
-                               break;
-                       }
-                       gsm->count = 0;
-                       gsm->state = GSM_DATA;
-               }
-               break;
-       case GSM_DATA:          /* Data */
-               gsm->buf[gsm->count++] = c;
-               if (gsm->count == gsm->len)
-                       gsm->state = GSM_FCS;
-               break;
-       case GSM_FCS:           /* FCS follows the packet */
-               gsm->fcs = c;
-               gsm_queue(gsm);
-               /* And then back for the next frame */
-               gsm->state = GSM_SEARCH;
-               break;
-       }
-}
-
-/**
- *     gsm0_receive    -       perform processing for non-transparency
- *     @gsm: gsm data for this ldisc instance
- *     @c: character
- *
- *     Receive bytes in mode 1 (Advanced option)
- */
-
-static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
-{
-       if (c == GSM1_SOF) {
-               /* EOF is only valid in frame if we have got to the data state
-                  and received at least one byte (the FCS) */
-               if (gsm->state == GSM_DATA && gsm->count) {
-                       /* Extract the FCS */
-                       gsm->count--;
-                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
-                       gsm->len = gsm->count;
-                       gsm_queue(gsm);
-                       gsm->state  = GSM_START;
-                       return;
-               }
-               /* Any partial frame was a runt so go back to start */
-               if (gsm->state != GSM_START) {
-                       gsm->malformed++;
-                       gsm->state = GSM_START;
-               }
-               /* A SOF in GSM_START means we are still reading idling or
-                  framing bytes */
-               return;
-       }
-
-       if (c == GSM1_ESCAPE) {
-               gsm->escape = 1;
-               return;
-       }
-
-       /* Only an unescaped SOF gets us out of GSM search */
-       if (gsm->state == GSM_SEARCH)
-               return;
-
-       if (gsm->escape) {
-               c ^= GSM1_ESCAPE_BITS;
-               gsm->escape = 0;
-       }
-       switch (gsm->state) {
-       case GSM_START:         /* First byte after SOF */
-               gsm->address = 0;
-               gsm->state = GSM_ADDRESS;
-               gsm->fcs = INIT_FCS;
-               /* Drop through */
-       case GSM_ADDRESS:       /* Address continuation */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->address, c))
-                       gsm->state = GSM_CONTROL;
-               break;
-       case GSM_CONTROL:       /* Control Byte */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               gsm->control = c;
-               gsm->count = 0;
-               gsm->state = GSM_DATA;
-               break;
-       case GSM_DATA:          /* Data */
-               if (gsm->count > gsm->mru ) {   /* Allow one for the FCS */
-                       gsm->state = GSM_OVERRUN;
-                       gsm->bad_size++;
-               } else
-                       gsm->buf[gsm->count++] = c;
-               break;
-       case GSM_OVERRUN:       /* Over-long - eg a dropped SOF */
-               break;
-       }
-}
-
-/**
- *     gsm_error               -       handle tty error
- *     @gsm: ldisc data
- *     @data: byte received (may be invalid)
- *     @flag: error received
- *
- *     Handle an error in the receipt of data for a frame. Currently we just
- *     go back to hunting for a SOF.
- *
- *     FIXME: better diagnostics ?
- */
-
-static void gsm_error(struct gsm_mux *gsm,
-                               unsigned char data, unsigned char flag)
-{
-       gsm->state = GSM_SEARCH;
-       gsm->io_error++;
-}
-
-/**
- *     gsm_cleanup_mux         -       generic GSM protocol cleanup
- *     @gsm: our mux
- *
- *     Clean up the bits of the mux which are the same for all framing
- *     protocols. Remove the mux from the mux table, stop all the timers
- *     and then shut down each device hanging up the channels as we go.
- */
-
-void gsm_cleanup_mux(struct gsm_mux *gsm)
-{
-       int i;
-       struct gsm_dlci *dlci = gsm->dlci[0];
-       struct gsm_msg *txq;
-
-       gsm->dead = 1;
-
-       spin_lock(&gsm_mux_lock);
-       for (i = 0; i < MAX_MUX; i++) {
-               if (gsm_mux[i] == gsm) {
-                       gsm_mux[i] = NULL;
-                       break;
-               }
-       }
-       spin_unlock(&gsm_mux_lock);
-       WARN_ON(i == MAX_MUX);
-
-       del_timer_sync(&gsm->t2_timer);
-       /* Now we are sure T2 has stopped */
-       if (dlci) {
-               dlci->dead = 1;
-               gsm_dlci_begin_close(dlci);
-               wait_event_interruptible(gsm->event,
-                                       dlci->state == DLCI_CLOSED);
-       }
-       /* Free up any link layer users */
-       for (i = 0; i < NUM_DLCI; i++)
-               if (gsm->dlci[i])
-                       gsm_dlci_free(gsm->dlci[i]);
-       /* Now wipe the queues */
-       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
-               gsm->tx_head = txq->next;
-               kfree(txq);
-       }
-       gsm->tx_tail = NULL;
-}
-EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
-
-/**
- *     gsm_activate_mux        -       generic GSM setup
- *     @gsm: our mux
- *
- *     Set up the bits of the mux which are the same for all framing
- *     protocols. Add the mux to the mux table so it can be opened and
- *     finally kick off connecting to DLCI 0 on the modem.
- */
-
-int gsm_activate_mux(struct gsm_mux *gsm)
-{
-       struct gsm_dlci *dlci;
-       int i = 0;
-
-       init_timer(&gsm->t2_timer);
-       gsm->t2_timer.function = gsm_control_retransmit;
-       gsm->t2_timer.data = (unsigned long)gsm;
-       init_waitqueue_head(&gsm->event);
-       spin_lock_init(&gsm->control_lock);
-       spin_lock_init(&gsm->tx_lock);
-
-       if (gsm->encoding == 0)
-               gsm->receive = gsm0_receive;
-       else
-               gsm->receive = gsm1_receive;
-       gsm->error = gsm_error;
-
-       spin_lock(&gsm_mux_lock);
-       for (i = 0; i < MAX_MUX; i++) {
-               if (gsm_mux[i] == NULL) {
-                       gsm_mux[i] = gsm;
-                       break;
-               }
-       }
-       spin_unlock(&gsm_mux_lock);
-       if (i == MAX_MUX)
-               return -EBUSY;
-
-       dlci = gsm_dlci_alloc(gsm, 0);
-       if (dlci == NULL)
-               return -ENOMEM;
-       gsm->dead = 0;          /* Tty opens are now permissible */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(gsm_activate_mux);
-
-/**
- *     gsm_free_mux            -       free up a mux
- *     @mux: mux to free
- *
- *     Dispose of allocated resources for a dead mux. No refcounting
- *     at present so the mux must be truely dead.
- */
-void gsm_free_mux(struct gsm_mux *gsm)
-{
-       kfree(gsm->txframe);
-       kfree(gsm->buf);
-       kfree(gsm);
-}
-EXPORT_SYMBOL_GPL(gsm_free_mux);
-
-/**
- *     gsm_alloc_mux           -       allocate a mux
- *
- *     Creates a new mux ready for activation.
- */
-
-struct gsm_mux *gsm_alloc_mux(void)
-{
-       struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
-       if (gsm == NULL)
-               return NULL;
-       gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
-       if (gsm->buf == NULL) {
-               kfree(gsm);
-               return NULL;
-       }
-       gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
-       if (gsm->txframe == NULL) {
-               kfree(gsm->buf);
-               kfree(gsm);
-               return NULL;
-       }
-       spin_lock_init(&gsm->lock);
-
-       gsm->t1 = T1;
-       gsm->t2 = T2;
-       gsm->n2 = N2;
-       gsm->ftype = UIH;
-       gsm->initiator = 0;
-       gsm->adaption = 1;
-       gsm->encoding = 1;
-       gsm->mru = 64;  /* Default to encoding 1 so these should be 64 */
-       gsm->mtu = 64;
-       gsm->dead = 1;  /* Avoid early tty opens */
-
-       return gsm;
-}
-EXPORT_SYMBOL_GPL(gsm_alloc_mux);
-
-
-
-
-/**
- *     gsmld_output            -       write to link
- *     @gsm: our mux
- *     @data: bytes to output
- *     @len: size
- *
- *     Write a block of data from the GSM mux to the data channel. This
- *     will eventually be serialized from above but at the moment isn't.
- */
-
-static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
-{
-       if (tty_write_room(gsm->tty) < len) {
-               set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
-               return -ENOSPC;
-       }
-       if (debug & 4) {
-               printk("-->%d bytes out\n", len);
-               hex_packet(data, len);
-       }
-       gsm->tty->ops->write(gsm->tty, data, len);
-       return len;
-}
-
-/**
- *     gsmld_attach_gsm        -       mode set up
- *     @tty: our tty structure
- *     @gsm: our mux
- *
- *     Set up the MUX for basic mode and commence connecting to the
- *     modem. Currently called from the line discipline set up but
- *     will need moving to an ioctl path.
- */
-
-static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-       int ret;
-
-       gsm->tty = tty_kref_get(tty);
-       gsm->output = gsmld_output;
-       ret =  gsm_activate_mux(gsm);
-       if (ret != 0)
-               tty_kref_put(gsm->tty);
-       return ret;
-}
-
-
-/**
- *     gsmld_detach_gsm        -       stop doing 0710 mux
- *     @tty: tty atttached to the mux
- *     @gsm: mux
- *
- *     Shutdown and then clean up the resources used by the line discipline
- */
-
-static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-       WARN_ON(tty != gsm->tty);
-       gsm_cleanup_mux(gsm);
-       tty_kref_put(gsm->tty);
-       gsm->tty = NULL;
-}
-
-static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-       const unsigned char *dp;
-       char *f;
-       int i;
-       char buf[64];
-       char flags;
-
-       if (debug & 4) {
-               printk("Inbytes %dd\n", count);
-               hex_packet(cp, count);
-       }
-
-       for (i = count, dp = cp, f = fp; i; i--, dp++) {
-               flags = *f++;
-               switch (flags) {
-               case TTY_NORMAL:
-                       gsm->receive(gsm, *dp);
-                       break;
-               case TTY_OVERRUN:
-               case TTY_BREAK:
-               case TTY_PARITY:
-               case TTY_FRAME:
-                       gsm->error(gsm, *dp, flags);
-                       break;
-               default:
-                       printk(KERN_ERR "%s: unknown flag %d\n",
-                              tty_name(tty, buf), flags);
-                       break;
-               }
-       }
-       /* FASYNC if needed ? */
-       /* If clogged call tty_throttle(tty); */
-}
-
-/**
- *     gsmld_chars_in_buffer   -       report available bytes
- *     @tty: tty device
- *
- *     Report the number of characters buffered to be delivered to user
- *     at this instant in time.
- *
- *     Locking: gsm lock
- */
-
-static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;
-}
-
-/**
- *     gsmld_flush_buffer      -       clean input queue
- *     @tty:   terminal device
- *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup).
- */
-
-static void gsmld_flush_buffer(struct tty_struct *tty)
-{
-}
-
-/**
- *     gsmld_close             -       close the ldisc for this tty
- *     @tty: device
- *
- *     Called from the terminal layer when this line discipline is
- *     being shut down, either because of a close or becsuse of a
- *     discipline change. The function will not be called while other
- *     ldisc methods are in progress.
- */
-
-static void gsmld_close(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-
-       gsmld_detach_gsm(tty, gsm);
-
-       gsmld_flush_buffer(tty);
-       /* Do other clean up here */
-       gsm_free_mux(gsm);
-}
-
-/**
- *     gsmld_open              -       open an ldisc
- *     @tty: terminal to open
- *
- *     Called when this line discipline is being attached to the
- *     terminal device. Can sleep. Called serialized so that no
- *     other events will occur in parallel. No further open will occur
- *     until a close.
- */
-
-static int gsmld_open(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm;
-
-       if (tty->ops->write == NULL)
-               return -EINVAL;
-
-       /* Attach our ldisc data */
-       gsm = gsm_alloc_mux();
-       if (gsm == NULL)
-               return -ENOMEM;
-
-       tty->disc_data = gsm;
-       tty->receive_room = 65536;
-
-       /* Attach the initial passive connection */
-       gsm->encoding = 1;
-       return gsmld_attach_gsm(tty, gsm);
-}
-
-/**
- *     gsmld_write_wakeup      -       asynchronous I/O notifier
- *     @tty: tty device
- *
- *     Required for the ptys, serial driver etc. since processes
- *     that attach themselves to the master and rely on ASYNC
- *     IO must be woken up
- */
-
-static void gsmld_write_wakeup(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-       unsigned long flags;
-
-       /* Queue poll */
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       gsm_data_kick(gsm);
-       if (gsm->tx_bytes < TX_THRESH_LO) {
-               spin_lock_irqsave(&gsm->tx_lock, flags);
-               gsm_dlci_data_sweep(gsm);
-               spin_unlock_irqrestore(&gsm->tx_lock, flags);
-       }
-}
-
-/**
- *     gsmld_read              -       read function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Perform reads for the line discipline. We are guaranteed that the
- *     line discipline will not be closed under us but we may get multiple
- *     parallel readers and must handle this ourselves. We may also get
- *     a hangup. Always called in user context, may sleep.
- *
- *     This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
-                        unsigned char __user *buf, size_t nr)
-{
-       return -EOPNOTSUPP;
-}
-
-/**
- *     gsmld_write             -       write function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Called when the owner of the device wants to send a frame
- *     itself (or some other control data). The data is transferred
- *     as-is and must be properly framed and checksummed as appropriate
- *     by userspace. Frames are either sent whole or not at all as this
- *     avoids pain user side.
- */
-
-static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *buf, size_t nr)
-{
-       int space = tty_write_room(tty);
-       if (space >= nr)
-               return tty->ops->write(tty, buf, nr);
-       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       return -ENOBUFS;
-}
-
-/**
- *     gsmld_poll              -       poll method for N_GSM0710
- *     @tty: terminal device
- *     @file: file accessing it
- *     @wait: poll table
- *
- *     Called when the line discipline is asked to poll() for data or
- *     for special events. This code is not serialized with respect to
- *     other events save open/close.
- *
- *     This code must be sure never to sleep through a hangup.
- *     Called without the kernel lock held - fine
- */
-
-static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
-                                                       poll_table *wait)
-{
-       unsigned int mask = 0;
-       struct gsm_mux *gsm = tty->disc_data;
-
-       poll_wait(file, &tty->read_wait, wait);
-       poll_wait(file, &tty->write_wait, wait);
-       if (tty_hung_up_p(file))
-               mask |= POLLHUP;
-       if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
-               mask |= POLLOUT | POLLWRNORM;
-       if (gsm->dead)
-               mask |= POLLHUP;
-       return mask;
-}
-
-static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
-                                                       struct gsm_config *c)
-{
-       int need_close = 0;
-       int need_restart = 0;
-
-       /* Stuff we don't support yet - UI or I frame transport, windowing */
-       if ((c->adaption !=1 && c->adaption != 2) || c->k)
-               return -EOPNOTSUPP;
-       /* Check the MRU/MTU range looks sane */
-       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
-               return -EINVAL;
-       if (c->n2 < 3)
-               return -EINVAL;
-       if (c->encapsulation > 1)       /* Basic, advanced, no I */
-               return -EINVAL;
-       if (c->initiator > 1)
-               return -EINVAL;
-       if (c->i == 0 || c->i > 2)      /* UIH and UI only */
-               return -EINVAL;
-       /*
-        *      See what is needed for reconfiguration
-        */
-
-       /* Timing fields */
-       if (c->t1 != 0 && c->t1 != gsm->t1)
-               need_restart = 1;
-       if (c->t2 != 0 && c->t2 != gsm->t2)
-               need_restart = 1;
-       if (c->encapsulation != gsm->encoding)
-               need_restart = 1;
-       if (c->adaption != gsm->adaption)
-               need_restart = 1;
-       /* Requires care */
-       if (c->initiator != gsm->initiator)
-               need_close = 1;
-       if (c->mru != gsm->mru)
-               need_restart = 1;
-       if (c->mtu != gsm->mtu)
-               need_restart = 1;
-
-       /*
-        *      Close down what is needed, restart and initiate the new
-        *      configuration
-        */
-
-       if (need_close || need_restart) {
-               gsm_dlci_begin_close(gsm->dlci[0]);
-               /* This will timeout if the link is down due to N2 expiring */
-               wait_event_interruptible(gsm->event,
-                               gsm->dlci[0]->state == DLCI_CLOSED);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-       if (need_restart)
-               gsm_cleanup_mux(gsm);
-
-       gsm->initiator = c->initiator;
-       gsm->mru = c->mru;
-       gsm->encoding = c->encapsulation;
-       gsm->adaption = c->adaption;
-
-       if (c->i == 1)
-               gsm->ftype = UIH;
-       else if (c->i == 2)
-               gsm->ftype = UI;
-
-       if (c->t1)
-               gsm->t1 = c->t1;
-       if (c->t2)
-               gsm->t2 = c->t2;
-
-       /* FIXME: We need to separate activation/deactivation from adding
-          and removing from the mux array */
-       if (need_restart)
-               gsm_activate_mux(gsm);
-       if (gsm->initiator && need_close)
-               gsm_dlci_begin_open(gsm->dlci[0]);
-       return 0;
-}
-
-static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct gsm_config c;
-       struct gsm_mux *gsm = tty->disc_data;
-
-       switch (cmd) {
-       case GSMIOC_GETCONF:
-               memset(&c, 0, sizeof(c));
-               c.adaption = gsm->adaption;
-               c.encapsulation = gsm->encoding;
-               c.initiator = gsm->initiator;
-               c.t1 = gsm->t1;
-               c.t2 = gsm->t2;
-               c.t3 = 0;       /* Not supported */
-               c.n2 = gsm->n2;
-               if (gsm->ftype == UIH)
-                       c.i = 1;
-               else
-                       c.i = 2;
-               printk("Ftype %d i %d\n", gsm->ftype, c.i);
-               c.mru = gsm->mru;
-               c.mtu = gsm->mtu;
-               c.k = 0;
-               if (copy_to_user((void *)arg, &c, sizeof(c)))
-                       return -EFAULT;
-               return 0;
-       case GSMIOC_SETCONF:
-               if (copy_from_user(&c, (void *)arg, sizeof(c)))
-                       return -EFAULT;
-               return gsmld_config(tty, gsm, &c);
-       default:
-               return n_tty_ioctl_helper(tty, file, cmd, arg);
-       }
-}
-
-
-/* Line discipline for real tty */
-struct tty_ldisc_ops tty_ldisc_packet = {
-       .owner           = THIS_MODULE,
-       .magic           = TTY_LDISC_MAGIC,
-       .name            = "n_gsm",
-       .open            = gsmld_open,
-       .close           = gsmld_close,
-       .flush_buffer    = gsmld_flush_buffer,
-       .chars_in_buffer = gsmld_chars_in_buffer,
-       .read            = gsmld_read,
-       .write           = gsmld_write,
-       .ioctl           = gsmld_ioctl,
-       .poll            = gsmld_poll,
-       .receive_buf     = gsmld_receive_buf,
-       .write_wakeup    = gsmld_write_wakeup
-};
-
-/*
- *     Virtual tty side
- */
-
-#define TX_SIZE                512
-
-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
-{
-       u8 modembits[5];
-       struct gsm_control *ctrl;
-       int len = 2;
-
-       if (brk)
-               len++;
-
-       modembits[0] = len << 1 | EA;           /* Data bytes */
-       modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
-       modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
-       if (brk)
-               modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
-       ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
-       if (ctrl == NULL)
-               return -ENOMEM;
-       return gsm_control_wait(dlci->gsm, ctrl);
-}
-
-static int gsm_carrier_raised(struct tty_port *port)
-{
-       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-       /* Not yet open so no carrier info */
-       if (dlci->state != DLCI_OPEN)
-               return 0;
-       if (debug & 2)
-               return 1;
-       return dlci->modem_rx & TIOCM_CD;
-}
-
-static void gsm_dtr_rts(struct tty_port *port, int onoff)
-{
-       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-       unsigned int modem_tx = dlci->modem_tx;
-       if (onoff)
-               modem_tx |= TIOCM_DTR | TIOCM_RTS;
-       else
-               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
-       if (modem_tx != dlci->modem_tx) {
-               dlci->modem_tx = modem_tx;
-               gsmtty_modem_update(dlci, 0);
-       }
-}
-
-static const struct tty_port_operations gsm_port_ops = {
-       .carrier_raised = gsm_carrier_raised,
-       .dtr_rts = gsm_dtr_rts,
-};
-
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_mux *gsm;
-       struct gsm_dlci *dlci;
-       struct tty_port *port;
-       unsigned int line = tty->index;
-       unsigned int mux = line >> 6;
-
-       line = line & 0x3F;
-
-       if (mux >= MAX_MUX)
-               return -ENXIO;
-       /* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
-       if (gsm_mux[mux] == NULL)
-               return -EUNATCH;
-       if (line == 0 || line > 61)     /* 62/63 reserved */
-               return -ECHRNG;
-       gsm = gsm_mux[mux];
-       if (gsm->dead)
-               return -EL2HLT;
-       dlci = gsm->dlci[line];
-       if (dlci == NULL)
-               dlci = gsm_dlci_alloc(gsm, line);
-       if (dlci == NULL)
-               return -ENOMEM;
-       port = &dlci->port;
-       port->count++;
-       tty->driver_data = dlci;
-       tty_port_tty_set(port, tty);
-
-       dlci->modem_rx = 0;
-       /* We could in theory open and close before we wait - eg if we get
-          a DM straight back. This is ok as that will have caused a hangup */
-       set_bit(ASYNCB_INITIALIZED, &port->flags);
-       /* Start sending off SABM messages */
-       gsm_dlci_begin_open(dlci);
-       /* And wait for virtual carrier */
-       return tty_port_block_til_ready(port, tty, filp);
-}
-
-static void gsmtty_close(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (dlci == NULL)
-               return;
-       if (tty_port_close_start(&dlci->port, tty, filp) == 0)
-               return;
-       gsm_dlci_begin_close(dlci);
-       tty_port_close_end(&dlci->port, tty);
-       tty_port_tty_set(&dlci->port, NULL);
-}
-
-static void gsmtty_hangup(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       tty_port_hangup(&dlci->port);
-       gsm_dlci_begin_close(dlci);
-}
-
-static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
-                                                                   int len)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       /* Stuff the bytes into the fifo queue */
-       int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
-       /* Need to kick the channel */
-       gsm_dlci_data_kick(dlci);
-       return sent;
-}
-
-static int gsmtty_write_room(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return TX_SIZE - kfifo_len(dlci->fifo);
-}
-
-static int gsmtty_chars_in_buffer(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return kfifo_len(dlci->fifo);
-}
-
-static void gsmtty_flush_buffer(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       /* Caution needed: If we implement reliable transport classes
-          then the data being transmitted can't simply be junked once
-          it has first hit the stack. Until then we can just blow it
-          away */
-       kfifo_reset(dlci->fifo);
-       /* Need to unhook this DLCI from the transmit queue logic */
-}
-
-static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       /* The FIFO handles the queue so the kernel will do the right
-          thing waiting on chars_in_buffer before calling us. No work
-          to do here */
-}
-
-static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return dlci->modem_rx;
-}
-
-static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
-       unsigned int set, unsigned int clear)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       unsigned int modem_tx = dlci->modem_tx;
-
-       modem_tx &= clear;
-       modem_tx |= set;
-
-       if (modem_tx != dlci->modem_tx) {
-               dlci->modem_tx = modem_tx;
-               return gsmtty_modem_update(dlci, 0);
-       }
-       return 0;
-}
-
-
-static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
-                       unsigned int cmd, unsigned long arg)
-{
-       return -ENOIOCTLCMD;
-}
-
-static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       /* For the moment its fixed. In actual fact the speed information
-          for the virtual channel can be propogated in both directions by
-          the RPN control message. This however rapidly gets nasty as we
-          then have to remap modem signals each way according to whether
-          our virtual cable is null modem etc .. */
-       tty_termios_copy_hw(tty->termios, old);
-}
-
-static void gsmtty_throttle(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
-               dlci->modem_tx &= ~TIOCM_DTR;
-       dlci->throttled = 1;
-       /* Send an MSC with DTR cleared */
-       gsmtty_modem_update(dlci, 0);
-}
-
-static void gsmtty_unthrottle(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
-               dlci->modem_tx |= TIOCM_DTR;
-       dlci->throttled = 0;
-       /* Send an MSC with DTR set */
-       gsmtty_modem_update(dlci, 0);
-}
-
-static int gsmtty_break_ctl(struct tty_struct *tty, int state)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       int encode = 0; /* Off */
-
-       if (state == -1)        /* "On indefinitely" - we can't encode this
-                                   properly */
-               encode = 0x0F;
-       else if (state > 0) {
-               encode = state / 200;   /* mS to encoding */
-               if (encode > 0x0F)
-                       encode = 0x0F;  /* Best effort */
-       }
-       return gsmtty_modem_update(dlci, encode);
-}
-
-static struct tty_driver *gsm_tty_driver;
-
-/* Virtual ttys for the demux */
-static const struct tty_operations gsmtty_ops = {
-       .open                   = gsmtty_open,
-       .close                  = gsmtty_close,
-       .write                  = gsmtty_write,
-       .write_room             = gsmtty_write_room,
-       .chars_in_buffer        = gsmtty_chars_in_buffer,
-       .flush_buffer           = gsmtty_flush_buffer,
-       .ioctl                  = gsmtty_ioctl,
-       .throttle               = gsmtty_throttle,
-       .unthrottle             = gsmtty_unthrottle,
-       .set_termios            = gsmtty_set_termios,
-       .hangup                 = gsmtty_hangup,
-       .wait_until_sent        = gsmtty_wait_until_sent,
-       .tiocmget               = gsmtty_tiocmget,
-       .tiocmset               = gsmtty_tiocmset,
-       .break_ctl              = gsmtty_break_ctl,
-};
-
-
-
-static int __init gsm_init(void)
-{
-       /* Fill in our line protocol discipline, and register it */
-       int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
-       if (status != 0) {
-               printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
-               return status;
-       }
-
-       gsm_tty_driver = alloc_tty_driver(256);
-       if (!gsm_tty_driver) {
-               tty_unregister_ldisc(N_GSM0710);
-               printk(KERN_ERR "gsm_init: tty allocation failed.\n");
-               return -EINVAL;
-       }
-       gsm_tty_driver->owner   = THIS_MODULE;
-       gsm_tty_driver->driver_name     = "gsmtty";
-       gsm_tty_driver->name            = "gsmtty";
-       gsm_tty_driver->major           = 0;    /* Dynamic */
-       gsm_tty_driver->minor_start     = 0;
-       gsm_tty_driver->type            = TTY_DRIVER_TYPE_SERIAL;
-       gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       gsm_tty_driver->flags   = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
-                                                       | TTY_DRIVER_HARDWARE_BREAK;
-       gsm_tty_driver->init_termios    = tty_std_termios;
-       /* Fixme */
-       gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
-       tty_set_operations(gsm_tty_driver, &gsmtty_ops);
-
-       spin_lock_init(&gsm_mux_lock);
-
-       if (tty_register_driver(gsm_tty_driver)) {
-               put_tty_driver(gsm_tty_driver);
-               tty_unregister_ldisc(N_GSM0710);
-               printk(KERN_ERR "gsm_init: tty registration failed.\n");
-               return -EBUSY;
-       }
-       printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
-       return 0;
-}
-
-static void __exit gsm_exit(void)
-{
-       int status = tty_unregister_ldisc(N_GSM0710);
-       if (status != 0)
-               printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
-       tty_unregister_driver(gsm_tty_driver);
-       put_tty_driver(gsm_tty_driver);
-       printk(KERN_INFO "gsm_init: unloaded.\n");
-}
-
-module_init(gsm_init);
-module_exit(gsm_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
deleted file mode 100644 (file)
index 47d3228..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-/* generic HDLC line discipline for Linux
- *
- * Written by Paul Fulghum paulkf@microgate.com
- * for Microgate Corporation
- *
- * Microgate and SyncLink are registered trademarks of Microgate Corporation
- *
- * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
- *     Al Longyear <longyear@netcom.com>,
- *     Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
- *
- * Original release 01/11/99
- *
- * This code is released under the GNU General Public License (GPL)
- *
- * This module implements the tty line discipline N_HDLC for use with
- * tty device drivers that support bit-synchronous HDLC communications.
- *
- * All HDLC data is frame oriented which means:
- *
- * 1. tty write calls represent one complete transmit frame of data
- *    The device driver should accept the complete frame or none of 
- *    the frame (busy) in the write method. Each write call should have
- *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
- *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
- *    should include any crc bytes required. For example, when using
- *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
- *    the application may transmit is limited to 65531 bytes. For CCITT
- *    CRC16, the maximum application frame size would be 65533.
- *
- *
- * 2. receive callbacks from the device driver represents
- *    one received frame. The device driver should bypass
- *    the tty flip buffer and call the line discipline receive
- *    callback directly to avoid fragmenting or concatenating
- *    multiple frames into a single receive callback.
- *
- *    The HDLC line discipline queues the receive frames in separate
- *    buffers so complete receive frames can be returned by the
- *    tty read calls.
- *
- * 3. tty read calls returns an entire frame of data or nothing.
- *    
- * 4. all send and receive data is considered raw. No processing
- *    or translation is performed by the line discipline, regardless
- *    of the tty flags
- *
- * 5. When line discipline is queried for the amount of receive
- *    data available (FIOC), 0 is returned if no data available,
- *    otherwise the count of the next available frame is returned.
- *    (instead of the sum of all received frame counts).
- *
- * These conventions allow the standard tty programming interface
- * to be used for synchronous HDLC applications when used with
- * this line discipline (or another line discipline that is frame
- * oriented such as N_PPP).
- *
- * The SyncLink driver (synclink.c) implements both asynchronous
- * (using standard line discipline N_TTY) and synchronous HDLC
- * (using N_HDLC) communications, with the latter using the above
- * conventions.
- *
- * This implementation is very basic and does not maintain
- * any statistics. The main point is to enforce the raw data
- * and frame orientation of HDLC communications.
- *
- * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
- */
-
-#define HDLC_MAGIC 0x239e
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-
-#undef VERSION
-#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-
-#include <linux/poll.h>
-#include <linux/in.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>      /* used in new tty drivers */
-#include <linux/signal.h>      /* used in new tty drivers */
-#include <linux/if.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/termios.h>
-#include <asm/uaccess.h>
-
-/*
- * Buffers for individual HDLC frames
- */
-#define MAX_HDLC_FRAME_SIZE 65535 
-#define DEFAULT_RX_BUF_COUNT 10
-#define MAX_RX_BUF_COUNT 60
-#define DEFAULT_TX_BUF_COUNT 3
-
-struct n_hdlc_buf {
-       struct n_hdlc_buf *link;
-       int               count;
-       char              buf[1];
-};
-
-#define        N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
-
-struct n_hdlc_buf_list {
-       struct n_hdlc_buf *head;
-       struct n_hdlc_buf *tail;
-       int               count;
-       spinlock_t        spinlock;
-};
-
-/**
- * struct n_hdlc - per device instance data structure
- * @magic - magic value for structure
- * @flags - miscellaneous control flags
- * @tty - ptr to TTY structure
- * @backup_tty - TTY to use if tty gets closed
- * @tbusy - reentrancy flag for tx wakeup code
- * @woke_up - FIXME: describe this field
- * @tbuf - currently transmitting tx buffer
- * @tx_buf_list - list of pending transmit frame buffers
- * @rx_buf_list - list of received frame buffers
- * @tx_free_buf_list - list unused transmit frame buffers
- * @rx_free_buf_list - list unused received frame buffers
- */
-struct n_hdlc {
-       int                     magic;
-       __u32                   flags;
-       struct tty_struct       *tty;
-       struct tty_struct       *backup_tty;
-       int                     tbusy;
-       int                     woke_up;
-       struct n_hdlc_buf       *tbuf;
-       struct n_hdlc_buf_list  tx_buf_list;
-       struct n_hdlc_buf_list  rx_buf_list;
-       struct n_hdlc_buf_list  tx_free_buf_list;
-       struct n_hdlc_buf_list  rx_free_buf_list;
-};
-
-/*
- * HDLC buffer list manipulation functions
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-                          struct n_hdlc_buf *buf);
-static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
-
-/* Local functions */
-
-static struct n_hdlc *n_hdlc_alloc (void);
-
-/* debug level can be set by insmod for debugging purposes */
-#define DEBUG_LEVEL_INFO       1
-static int debuglevel;
-
-/* max frame size for memory allocations */
-static int maxframe = 4096;
-
-/* TTY callbacks */
-
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-                          __u8 __user *buf, size_t nr);
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-                           const unsigned char *buf, size_t nr);
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg);
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-                                   poll_table *wait);
-static int n_hdlc_tty_open(struct tty_struct *tty);
-static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
-                              char *fp, int count);
-static void n_hdlc_tty_wakeup(struct tty_struct *tty);
-
-#define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
-#define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
-#define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
-
-static void flush_rx_queue(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       struct n_hdlc_buf *buf;
-
-       while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
-}
-
-static void flush_tx_queue(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       struct n_hdlc_buf *buf;
-       unsigned long flags;
-
-       while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
-               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       if (n_hdlc->tbuf) {
-               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
-               n_hdlc->tbuf = NULL;
-       }
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-}
-
-static struct tty_ldisc_ops n_hdlc_ldisc = {
-       .owner          = THIS_MODULE,
-       .magic          = TTY_LDISC_MAGIC,
-       .name           = "hdlc",
-       .open           = n_hdlc_tty_open,
-       .close          = n_hdlc_tty_close,
-       .read           = n_hdlc_tty_read,
-       .write          = n_hdlc_tty_write,
-       .ioctl          = n_hdlc_tty_ioctl,
-       .poll           = n_hdlc_tty_poll,
-       .receive_buf    = n_hdlc_tty_receive,
-       .write_wakeup   = n_hdlc_tty_wakeup,
-       .flush_buffer   = flush_rx_queue,
-};
-
-/**
- * n_hdlc_release - release an n_hdlc per device line discipline info structure
- * @n_hdlc - per device line discipline info structure
- */
-static void n_hdlc_release(struct n_hdlc *n_hdlc)
-{
-       struct tty_struct *tty = n_hdlc2tty (n_hdlc);
-       struct n_hdlc_buf *buf;
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
-               
-       /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
-       wake_up_interruptible (&tty->read_wait);
-       wake_up_interruptible (&tty->write_wait);
-
-       if (tty->disc_data == n_hdlc)
-               tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
-
-       /* Release transmit and receive buffers */
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       kfree(n_hdlc->tbuf);
-       kfree(n_hdlc);
-       
-}      /* end of n_hdlc_release() */
-
-/**
- * n_hdlc_tty_close - line discipline close
- * @tty - pointer to tty info structure
- *
- * Called when the line discipline is changed to something
- * else, the tty is closed, or the tty detects a hangup.
- */
-static void n_hdlc_tty_close(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
-               
-       if (n_hdlc != NULL) {
-               if (n_hdlc->magic != HDLC_MAGIC) {
-                       printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
-                       return;
-               }
-#if defined(TTY_NO_WRITE_SPLIT)
-               clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-               tty->disc_data = NULL;
-               if (tty == n_hdlc->backup_tty)
-                       n_hdlc->backup_tty = NULL;
-               if (tty != n_hdlc->tty)
-                       return;
-               if (n_hdlc->backup_tty) {
-                       n_hdlc->tty = n_hdlc->backup_tty;
-               } else {
-                       n_hdlc_release (n_hdlc);
-               }
-       }
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
-               
-}      /* end of n_hdlc_tty_close() */
-
-/**
- * n_hdlc_tty_open - called when line discipline changed to n_hdlc
- * @tty - pointer to tty info structure
- *
- * Returns 0 if success, otherwise error code
- */
-static int n_hdlc_tty_open (struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
-               __FILE__,__LINE__,
-               tty->name);
-               
-       /* There should not be an existing table for this slot. */
-       if (n_hdlc) {
-               printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
-               return -EEXIST;
-       }
-       
-       n_hdlc = n_hdlc_alloc();
-       if (!n_hdlc) {
-               printk (KERN_ERR "n_hdlc_alloc failed\n");
-               return -ENFILE;
-       }
-               
-       tty->disc_data = n_hdlc;
-       n_hdlc->tty    = tty;
-       tty->receive_room = 65536;
-       
-#if defined(TTY_NO_WRITE_SPLIT)
-       /* change tty_io write() to not split large writes into 8K chunks */
-       set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-       
-       /* flush receive data from driver */
-       tty_driver_flush_buffer(tty);
-               
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
-               
-       return 0;
-       
-}      /* end of n_tty_hdlc_open() */
-
-/**
- * n_hdlc_send_frames - send frames on pending send buffer list
- * @n_hdlc - pointer to ldisc instance data
- * @tty - pointer to tty instance data
- *
- * Send frames on pending send buffer list until the driver does not accept a
- * frame (busy) this function is called after adding a frame to the send buffer
- * list and by the tty wakeup callback.
- */
-static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
-{
-       register int actual;
-       unsigned long flags;
-       struct n_hdlc_buf *tbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
- check_again:
-               
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       if (n_hdlc->tbusy) {
-               n_hdlc->woke_up = 1;
-               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-               return;
-       }
-       n_hdlc->tbusy = 1;
-       n_hdlc->woke_up = 0;
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-
-       /* get current transmit buffer or get new transmit */
-       /* buffer from list of pending transmit buffers */
-               
-       tbuf = n_hdlc->tbuf;
-       if (!tbuf)
-               tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               
-       while (tbuf) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d)sending frame %p, count=%d\n",
-                               __FILE__,__LINE__,tbuf,tbuf->count);
-                       
-               /* Send the next block of data to device */
-               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-               actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
-
-               /* rollback was possible and has been done */
-               if (actual == -ERESTARTSYS) {
-                       n_hdlc->tbuf = tbuf;
-                       break;
-               }
-               /* if transmit error, throw frame away by */
-               /* pretending it was accepted by driver */
-               if (actual < 0)
-                       actual = tbuf->count;
-               
-               if (actual == tbuf->count) {
-                       if (debuglevel >= DEBUG_LEVEL_INFO)     
-                               printk("%s(%d)frame %p completed\n",
-                                       __FILE__,__LINE__,tbuf);
-                                       
-                       /* free current transmit buffer */
-                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
-                       
-                       /* this tx buffer is done */
-                       n_hdlc->tbuf = NULL;
-                       
-                       /* wait up sleeping writers */
-                       wake_up_interruptible(&tty->write_wait);
-       
-                       /* get next pending transmit buffer */
-                       tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               } else {
-                       if (debuglevel >= DEBUG_LEVEL_INFO)     
-                               printk("%s(%d)frame %p pending\n",
-                                       __FILE__,__LINE__,tbuf);
-                                       
-                       /* buffer not accepted by driver */
-                       /* set this buffer as pending buffer */
-                       n_hdlc->tbuf = tbuf;
-                       break;
-               }
-       }
-       
-       if (!tbuf)
-               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
-       
-       /* Clear the re-entry flag */
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       n_hdlc->tbusy = 0;
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
-       
-        if (n_hdlc->woke_up)
-         goto check_again;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
-               
-}      /* end of n_hdlc_send_frames() */
-
-/**
- * n_hdlc_tty_wakeup - Callback for transmit wakeup
- * @tty        - pointer to associated tty instance data
- *
- * Called when low level device driver can accept more send data.
- */
-static void n_hdlc_tty_wakeup(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
-               
-       if (!n_hdlc)
-               return;
-
-       if (tty != n_hdlc->tty) {
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               return;
-       }
-
-       n_hdlc_send_frames (n_hdlc, tty);
-               
-}      /* end of n_hdlc_tty_wakeup() */
-
-/**
- * n_hdlc_tty_receive - Called by tty driver when receive data is available
- * @tty        - pointer to tty instance data
- * @data - pointer to received data
- * @flags - pointer to flags for data
- * @count - count of received data in bytes
- *
- * Called by tty low level driver when receive data is available. Data is
- * interpreted as one HDLC frame.
- */
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
-                              char *flags, int count)
-{
-       register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       register struct n_hdlc_buf *buf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
-                       __FILE__,__LINE__, count);
-               
-       /* This can happen if stuff comes in on the backup tty */
-       if (!n_hdlc || tty != n_hdlc->tty)
-               return;
-               
-       /* verify line is using HDLC discipline */
-       if (n_hdlc->magic != HDLC_MAGIC) {
-               printk("%s(%d) line not using HDLC discipline\n",
-                       __FILE__,__LINE__);
-               return;
-       }
-       
-       if ( count>maxframe ) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d) rx count>maxframesize, data discarded\n",
-                              __FILE__,__LINE__);
-               return;
-       }
-
-       /* get a free HDLC buffer */    
-       buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-       if (!buf) {
-               /* no buffers in free list, attempt to allocate another rx buffer */
-               /* unless the maximum count has been reached */
-               if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
-                       buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
-       }
-       
-       if (!buf) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d) no more rx buffers, data discarded\n",
-                              __FILE__,__LINE__);
-               return;
-       }
-               
-       /* copy received data to HDLC buffer */
-       memcpy(buf->buf,data,count);
-       buf->count=count;
-
-       /* add HDLC buffer to list of received frames */
-       n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
-       
-       /* wake up any blocked reads and perform async signalling */
-       wake_up_interruptible (&tty->read_wait);
-       if (n_hdlc->tty->fasync != NULL)
-               kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
-
-}      /* end of n_hdlc_tty_receive() */
-
-/**
- * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
- * @tty - pointer to tty instance data
- * @file - pointer to open file object
- * @buf - pointer to returned data buffer
- * @nr - size of returned data buffer
- *     
- * Returns the number of bytes returned or error code.
- */
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-                          __u8 __user *buf, size_t nr)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       int ret;
-       struct n_hdlc_buf *rbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
-               
-       /* Validate the pointers */
-       if (!n_hdlc)
-               return -EIO;
-
-       /* verify user access to buffer */
-       if (!access_ok(VERIFY_WRITE, buf, nr)) {
-               printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
-               "buffer\n", __FILE__, __LINE__);
-               return -EFAULT;
-       }
-
-       tty_lock();
-
-       for (;;) {
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                       tty_unlock();
-                       return -EIO;
-               }
-
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
-                        tty != n_hdlc->tty) {
-                       tty_unlock();
-                       return 0;
-               }
-
-               rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (rbuf)
-                       break;
-                       
-               /* no data */
-               if (file->f_flags & O_NONBLOCK) {
-                       tty_unlock();
-                       return -EAGAIN;
-               }
-                       
-               interruptible_sleep_on (&tty->read_wait);
-               if (signal_pending(current)) {
-                       tty_unlock();
-                       return -EINTR;
-               }
-       }
-               
-       if (rbuf->count > nr)
-               /* frame too large for caller's buffer (discard frame) */
-               ret = -EOVERFLOW;
-       else {
-               /* Copy the data to the caller's buffer */
-               if (copy_to_user(buf, rbuf->buf, rbuf->count))
-                       ret = -EFAULT;
-               else
-                       ret = rbuf->count;
-       }
-       
-       /* return HDLC buffer to free list unless the free list */
-       /* count has exceeded the default value, in which case the */
-       /* buffer is freed back to the OS to conserve memory */
-       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
-               kfree(rbuf);
-       else    
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-       tty_unlock();
-       return ret;
-       
-}      /* end of n_hdlc_tty_read() */
-
-/**
- * n_hdlc_tty_write - write a single frame of data to device
- * @tty        - pointer to associated tty device instance data
- * @file - pointer to file object data
- * @data - pointer to transmit data (one frame)
- * @count - size of transmit frame in bytes
- *             
- * Returns the number of bytes written (or error code).
- */
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-                           const unsigned char *data, size_t count)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       int error = 0;
-       DECLARE_WAITQUEUE(wait, current);
-       struct n_hdlc_buf *tbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
-                       __FILE__,__LINE__,count);
-               
-       /* Verify pointers */
-       if (!n_hdlc)
-               return -EIO;
-
-       if (n_hdlc->magic != HDLC_MAGIC)
-               return -EIO;
-
-       /* verify frame size */
-       if (count > maxframe ) {
-               if (debuglevel & DEBUG_LEVEL_INFO)
-                       printk (KERN_WARNING
-                               "n_hdlc_tty_write: truncating user packet "
-                               "from %lu to %d\n", (unsigned long) count,
-                               maxframe );
-               count = maxframe;
-       }
-       
-       tty_lock();
-
-       add_wait_queue(&tty->write_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       
-       /* Allocate transmit buffer */
-       /* sleep until transmit buffer available */             
-       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
-               if (file->f_flags & O_NONBLOCK) {
-                       error = -EAGAIN;
-                       break;
-               }
-               schedule();
-                       
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
-                   tty != n_hdlc->tty) {
-                       printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
-                       error = -EIO;
-                       break;
-               }
-                       
-               if (signal_pending(current)) {
-                       error = -EINTR;
-                       break;
-               }
-       }
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-
-       if (!error) {           
-               /* Retrieve the user's buffer */
-               memcpy(tbuf->buf, data, count);
-
-               /* Send the data */
-               tbuf->count = error = count;
-               n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
-               n_hdlc_send_frames(n_hdlc,tty);
-       }
-       tty_unlock();
-       return error;
-       
-}      /* end of n_hdlc_tty_write() */
-
-/**
- * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
- * @tty - pointer to tty instance data
- * @file - pointer to open file object for device
- * @cmd - IOCTL command code
- * @arg - argument for IOCTL call (cmd dependent)
- *
- * Returns command dependent result.
- */
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       int error = 0;
-       int count;
-       unsigned long flags;
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
-                       __FILE__,__LINE__,cmd);
-               
-       /* Verify the status of the device */
-       if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
-               return -EBADF;
-
-       switch (cmd) {
-       case FIONREAD:
-               /* report count of read data available */
-               /* in next available frame (if any) */
-               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
-               if (n_hdlc->rx_buf_list.head)
-                       count = n_hdlc->rx_buf_list.head->count;
-               else
-                       count = 0;
-               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
-               error = put_user(count, (int __user *)arg);
-               break;
-
-       case TIOCOUTQ:
-               /* get the pending tx byte count in the driver */
-               count = tty_chars_in_buffer(tty);
-               /* add size of next output frame in queue */
-               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
-               if (n_hdlc->tx_buf_list.head)
-                       count += n_hdlc->tx_buf_list.head->count;
-               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
-               error = put_user(count, (int __user *)arg);
-               break;
-
-       case TCFLSH:
-               switch (arg) {
-               case TCIOFLUSH:
-               case TCOFLUSH:
-                       flush_tx_queue(tty);
-               }
-               /* fall through to default */
-
-       default:
-               error = n_tty_ioctl_helper(tty, file, cmd, arg);
-               break;
-       }
-       return error;
-       
-}      /* end of n_hdlc_tty_ioctl() */
-
-/**
- * n_hdlc_tty_poll - TTY callback for poll system call
- * @tty - pointer to tty instance data
- * @filp - pointer to open file object for device
- * @poll_table - wait queue for operations
- * 
- * Determine which operations (read/write) will not block and return info
- * to caller.
- * Returns a bit mask containing info on which ops will not block.
- */
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-                                   poll_table *wait)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       unsigned int mask = 0;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
-               
-       if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
-               /* queue current process into any wait queue that */
-               /* may awaken in the future (read and write) */
-
-               poll_wait(filp, &tty->read_wait, wait);
-               poll_wait(filp, &tty->write_wait, wait);
-
-               /* set bits for operations that won't block */
-               if (n_hdlc->rx_buf_list.head)
-                       mask |= POLLIN | POLLRDNORM;    /* readable */
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-                       mask |= POLLHUP;
-               if (tty_hung_up_p(filp))
-                       mask |= POLLHUP;
-               if (!tty_is_writelocked(tty) &&
-                               n_hdlc->tx_free_buf_list.head)
-                       mask |= POLLOUT | POLLWRNORM;   /* writable */
-       }
-       return mask;
-}      /* end of n_hdlc_tty_poll() */
-
-/**
- * n_hdlc_alloc - allocate an n_hdlc instance data structure
- *
- * Returns a pointer to newly created structure if success, otherwise %NULL
- */
-static struct n_hdlc *n_hdlc_alloc(void)
-{
-       struct n_hdlc_buf *buf;
-       int i;
-       struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
-
-       if (!n_hdlc)
-               return NULL;
-
-       memset(n_hdlc, 0, sizeof(*n_hdlc));
-
-       n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
-       
-       /* allocate free rx buffer list */
-       for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
-               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-               if (buf)
-                       n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
-               else if (debuglevel >= DEBUG_LEVEL_INFO)        
-                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
-       }
-       
-       /* allocate free tx buffer list */
-       for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
-               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-               if (buf)
-                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
-               else if (debuglevel >= DEBUG_LEVEL_INFO)        
-                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
-       }
-       
-       /* Initialize the control block */
-       n_hdlc->magic  = HDLC_MAGIC;
-       n_hdlc->flags  = 0;
-       
-       return n_hdlc;
-       
-}      /* end of n_hdlc_alloc() */
-
-/**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
-{
-       memset(list, 0, sizeof(*list));
-       spin_lock_init(&list->spinlock);
-}      /* end of n_hdlc_buf_list_init() */
-
-/**
- * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
- * @list - pointer to buffer list
- * @buf        - pointer to buffer
- */
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-                          struct n_hdlc_buf *buf)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&list->spinlock,flags);
-       
-       buf->link=NULL;
-       if (list->tail)
-               list->tail->link = buf;
-       else
-               list->head = buf;
-       list->tail = buf;
-       (list->count)++;
-       
-       spin_unlock_irqrestore(&list->spinlock,flags);
-       
-}      /* end of n_hdlc_buf_put() */
-
-/**
- * n_hdlc_buf_get - remove and return an HDLC buffer from list
- * @list - pointer to HDLC buffer list
- * 
- * Remove and return an HDLC buffer from the head of the specified HDLC buffer
- * list.
- * Returns a pointer to HDLC buffer if available, otherwise %NULL.
- */
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
-{
-       unsigned long flags;
-       struct n_hdlc_buf *buf;
-       spin_lock_irqsave(&list->spinlock,flags);
-       
-       buf = list->head;
-       if (buf) {
-               list->head = buf->link;
-               (list->count)--;
-       }
-       if (!list->head)
-               list->tail = NULL;
-       
-       spin_unlock_irqrestore(&list->spinlock,flags);
-       return buf;
-       
-}      /* end of n_hdlc_buf_get() */
-
-static char hdlc_banner[] __initdata =
-       KERN_INFO "HDLC line discipline maxframe=%u\n";
-static char hdlc_register_ok[] __initdata =
-       KERN_INFO "N_HDLC line discipline registered.\n";
-static char hdlc_register_fail[] __initdata =
-       KERN_ERR "error registering line discipline: %d\n";
-static char hdlc_init_fail[] __initdata =
-       KERN_INFO "N_HDLC: init failure %d\n";
-
-static int __init n_hdlc_init(void)
-{
-       int status;
-
-       /* range check maxframe arg */
-       if (maxframe < 4096)
-               maxframe = 4096;
-       else if (maxframe > 65535)
-               maxframe = 65535;
-
-       printk(hdlc_banner, maxframe);
-
-       status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
-       if (!status)
-               printk(hdlc_register_ok);
-       else
-               printk(hdlc_register_fail, status);
-
-       if (status)
-               printk(hdlc_init_fail, status);
-       return status;
-       
-}      /* end of init_module() */
-
-static char hdlc_unregister_ok[] __exitdata =
-       KERN_INFO "N_HDLC: line discipline unregistered\n";
-static char hdlc_unregister_fail[] __exitdata =
-       KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
-
-static void __exit n_hdlc_exit(void)
-{
-       /* Release tty registration of line discipline */
-       int status = tty_unregister_ldisc(N_HDLC);
-
-       if (status)
-               printk(hdlc_unregister_fail, status);
-       else
-               printk(hdlc_unregister_ok);
-}
-
-module_init(n_hdlc_init);
-module_exit(n_hdlc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
-module_param(debuglevel, int, 0);
-module_param(maxframe, int, 0);
-MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
deleted file mode 100644 (file)
index 88dda0c..0000000
+++ /dev/null
@@ -1,1264 +0,0 @@
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by 
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Author:
- * L. Haag
- *
- * $Log: n_r3964.c,v $
- * Revision 1.10  2001/03/18 13:02:24  dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.9  2001/03/18 12:52:14  dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.8  2000/03/23 14:14:54  dwmw2
- * Fix race in sleeping in r3964_read()
- *
- * Revision 1.7  1999/28/08 11:41:50  dwmw2
- * Port to 2.3 kernel
- *
- * Revision 1.6  1998/09/30 00:40:40  dwmw2
- * Fixed compilation on 2.0.x kernels
- * Updated to newly registered tty-ldisc number 9
- *
- * Revision 1.5  1998/09/04 21:57:36  dwmw2
- * Signal handling bug fixes, port to 2.1.x.
- *
- * Revision 1.4  1998/04/02 20:26:59  lhaag
- * select, blocking, ...
- *
- * Revision 1.3  1998/02/12 18:58:43  root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2  1998/02/07 13:03:34  root
- * ioctl read_telegram
- *
- * Revision 1.1  1998/02/06 19:21:03  root
- * Initial revision
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>      /* used in new tty drivers */
-#include <linux/signal.h>      /* used in new tty drivers */
-#include <linux/ioctl.h>
-#include <linux/n_r3964.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-/*#define DEBUG_QUEUE*/
-
-/* Log successful handshake and protocol operations  */
-/*#define DEBUG_PROTO_S*/
-
-/* Log handshake and protocol errors: */
-/*#define DEBUG_PROTO_E*/
-
-/* Log Linediscipline operations (open, close, read, write...): */
-/*#define DEBUG_LDISC*/
-
-/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-/*#define DEBUG_MODUL*/
-
-/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
-
-#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_M(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PS(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PE(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_L(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_Q(fmt, arg...) do {} while (0)
-#endif
-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
-static void put_char(struct r3964_info *pInfo, unsigned char ch);
-static void trigger_transmit(struct r3964_info *pInfo);
-static void retry_transmit(struct r3964_info *pInfo);
-static void transmit_block(struct r3964_info *pInfo);
-static void receive_char(struct r3964_info *pInfo, const unsigned char c);
-static void receive_error(struct r3964_info *pInfo, const char flag);
-static void on_timeout(unsigned long priv);
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-               unsigned char __user * buf);
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-               int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-               struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
-               struct r3964_client_info *pClient);
-
-static int r3964_open(struct tty_struct *tty);
-static void r3964_close(struct tty_struct *tty);
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-               unsigned char __user * buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-               const unsigned char *buf, size_t nr);
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-               struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-               char *fp, int count);
-
-static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
-       .owner = THIS_MODULE,
-       .magic = TTY_LDISC_MAGIC,
-       .name = "R3964",
-       .open = r3964_open,
-       .close = r3964_close,
-       .read = r3964_read,
-       .write = r3964_write,
-       .ioctl = r3964_ioctl,
-       .set_termios = r3964_set_termios,
-       .poll = r3964_poll,
-       .receive_buf = r3964_receive_buf,
-};
-
-static void dump_block(const unsigned char *block, unsigned int length)
-{
-       unsigned int i, j;
-       char linebuf[16 * 3 + 1];
-
-       for (i = 0; i < length; i += 16) {
-               for (j = 0; (j < 16) && (j + i < length); j++) {
-                       sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
-               }
-               linebuf[3 * j] = '\0';
-               TRACE_PS("%s", linebuf);
-       }
-}
-
-/*************************************************************
- * Driver initialisation
- *************************************************************/
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static void __exit r3964_exit(void)
-{
-       int status;
-
-       TRACE_M("cleanup_module()");
-
-       status = tty_unregister_ldisc(N_R3964);
-
-       if (status != 0) {
-               printk(KERN_ERR "r3964: error unregistering linediscipline: "
-                               "%d\n", status);
-       } else {
-               TRACE_L("linediscipline successfully unregistered");
-       }
-}
-
-static int __init r3964_init(void)
-{
-       int status;
-
-       printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
-       /*
-        * Register the tty line discipline
-        */
-
-       status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
-       if (status == 0) {
-               TRACE_L("line discipline %d registered", N_R3964);
-               TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
-                       tty_ldisc_N_R3964.num);
-               TRACE_L("open=%p", tty_ldisc_N_R3964.open);
-               TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
-       } else {
-               printk(KERN_ERR "r3964: error registering line discipline: "
-                               "%d\n", status);
-       }
-       return status;
-}
-
-module_init(r3964_init);
-module_exit(r3964_exit);
-
-/*************************************************************
- * Protocol implementation routines
- *************************************************************/
-
-static void add_tx_queue(struct r3964_info *pInfo,
-                        struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pHeader->next = NULL;
-
-       if (pInfo->tx_last == NULL) {
-               pInfo->tx_first = pInfo->tx_last = pHeader;
-       } else {
-               pInfo->tx_last->next = pHeader;
-               pInfo->tx_last = pHeader;
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
-               pHeader, pHeader->length, pInfo->tx_first);
-}
-
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
-{
-       struct r3964_block_header *pHeader;
-       unsigned long flags;
-#ifdef DEBUG_QUEUE
-       struct r3964_block_header *pDump;
-#endif
-
-       pHeader = pInfo->tx_first;
-
-       if (pHeader == NULL)
-               return;
-
-#ifdef DEBUG_QUEUE
-       printk("r3964: remove_from_tx_queue: %p, length %u - ",
-               pHeader, pHeader->length);
-       for (pDump = pHeader; pDump; pDump = pDump->next)
-               printk("%p ", pDump);
-       printk("\n");
-#endif
-
-       if (pHeader->owner) {
-               if (error_code) {
-                       add_msg(pHeader->owner, R3964_MSG_ACK, 0,
-                               error_code, NULL);
-               } else {
-                       add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
-                               error_code, NULL);
-               }
-               wake_up_interruptible(&pInfo->read_wait);
-       }
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pInfo->tx_first = pHeader->next;
-       if (pInfo->tx_first == NULL) {
-               pInfo->tx_last = NULL;
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       kfree(pHeader);
-       TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
-
-       TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
-               pInfo->tx_first, pInfo->tx_last);
-}
-
-static void add_rx_queue(struct r3964_info *pInfo,
-                        struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pHeader->next = NULL;
-
-       if (pInfo->rx_last == NULL) {
-               pInfo->rx_first = pInfo->rx_last = pHeader;
-       } else {
-               pInfo->rx_last->next = pHeader;
-               pInfo->rx_last = pHeader;
-       }
-       pInfo->blocks_in_rx_queue++;
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
-               pHeader, pHeader->length,
-               pInfo->rx_first, pInfo->blocks_in_rx_queue);
-}
-
-static void remove_from_rx_queue(struct r3964_info *pInfo,
-                                struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-       struct r3964_block_header *pFind;
-
-       if (pHeader == NULL)
-               return;
-
-       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-       TRACE_Q("remove_from_rx_queue: %p, length %u",
-               pHeader, pHeader->length);
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       if (pInfo->rx_first == pHeader) {
-               /* Remove the first block in the linked list: */
-               pInfo->rx_first = pHeader->next;
-
-               if (pInfo->rx_first == NULL) {
-                       pInfo->rx_last = NULL;
-               }
-               pInfo->blocks_in_rx_queue--;
-       } else {
-               /* Find block to remove: */
-               for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
-                       if (pFind->next == pHeader) {
-                               /* Got it. */
-                               pFind->next = pHeader->next;
-                               pInfo->blocks_in_rx_queue--;
-                               if (pFind->next == NULL) {
-                                       /* Oh, removed the last one! */
-                                       pInfo->rx_last = pFind;
-                               }
-                               break;
-                       }
-               }
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       kfree(pHeader);
-       TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
-
-       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-}
-
-static void put_char(struct r3964_info *pInfo, unsigned char ch)
-{
-       struct tty_struct *tty = pInfo->tty;
-       /* FIXME: put_char should not be called from an IRQ */
-       tty_put_char(tty, ch);
-       pInfo->bcc ^= ch;
-}
-
-static void flush(struct r3964_info *pInfo)
-{
-       struct tty_struct *tty = pInfo->tty;
-
-       if (tty == NULL || tty->ops->flush_chars == NULL)
-               return;
-       tty->ops->flush_chars(tty);
-}
-
-static void trigger_transmit(struct r3964_info *pInfo)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
-               pInfo->state = R3964_TX_REQUEST;
-               pInfo->nRetry = 0;
-               pInfo->flags &= ~R3964_ERROR;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-
-               TRACE_PS("trigger_transmit - sent STX");
-
-               put_char(pInfo, STX);
-               flush(pInfo);
-
-               pInfo->bcc = 0;
-       } else {
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-       }
-}
-
-static void retry_transmit(struct r3964_info *pInfo)
-{
-       if (pInfo->nRetry < R3964_MAX_RETRIES) {
-               TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
-               pInfo->bcc = 0;
-               put_char(pInfo, STX);
-               flush(pInfo);
-               pInfo->state = R3964_TX_REQUEST;
-               pInfo->nRetry++;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-       } else {
-               TRACE_PE("transmission failed after %d retries",
-                        R3964_MAX_RETRIES);
-
-               remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-
-               trigger_transmit(pInfo);
-       }
-}
-
-static void transmit_block(struct r3964_info *pInfo)
-{
-       struct tty_struct *tty = pInfo->tty;
-       struct r3964_block_header *pBlock = pInfo->tx_first;
-       int room = 0;
-
-       if (tty == NULL || pBlock == NULL) {
-               return;
-       }
-
-       room = tty_write_room(tty);
-
-       TRACE_PS("transmit_block %p, room %d, length %d",
-                pBlock, room, pBlock->length);
-
-       while (pInfo->tx_position < pBlock->length) {
-               if (room < 2)
-                       break;
-
-               if (pBlock->data[pInfo->tx_position] == DLE) {
-                       /* send additional DLE char: */
-                       put_char(pInfo, DLE);
-               }
-               put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
-               room--;
-       }
-
-       if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
-               put_char(pInfo, DLE);
-               put_char(pInfo, ETX);
-               if (pInfo->flags & R3964_BCC) {
-                       put_char(pInfo, pInfo->bcc);
-               }
-               pInfo->state = R3964_WAIT_FOR_TX_ACK;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-       }
-       flush(pInfo);
-}
-
-static void on_receive_block(struct r3964_info *pInfo)
-{
-       unsigned int length;
-       struct r3964_client_info *pClient;
-       struct r3964_block_header *pBlock;
-
-       length = pInfo->rx_position;
-
-       /* compare byte checksum characters: */
-       if (pInfo->flags & R3964_BCC) {
-               if (pInfo->bcc != pInfo->last_rx) {
-                       TRACE_PE("checksum error - got %x but expected %x",
-                                pInfo->last_rx, pInfo->bcc);
-                       pInfo->flags |= R3964_CHECKSUM;
-               }
-       }
-
-       /* check for errors (parity, overrun,...): */
-       if (pInfo->flags & R3964_ERROR) {
-               TRACE_PE("on_receive_block - transmission failed error %x",
-                        pInfo->flags & R3964_ERROR);
-
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               if (pInfo->nRetry < R3964_MAX_RETRIES) {
-                       pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
-                       pInfo->nRetry++;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
-               } else {
-                       TRACE_PE("on_receive_block - failed after max retries");
-                       pInfo->state = R3964_IDLE;
-               }
-               return;
-       }
-
-       /* received block; submit DLE: */
-       put_char(pInfo, DLE);
-       flush(pInfo);
-       del_timer_sync(&pInfo->tmr);
-       TRACE_PS(" rx success: got %d chars", length);
-
-       /* prepare struct r3964_block_header: */
-       pBlock = kmalloc(length + sizeof(struct r3964_block_header),
-                       GFP_KERNEL);
-       TRACE_M("on_receive_block - kmalloc %p", pBlock);
-
-       if (pBlock == NULL)
-               return;
-
-       pBlock->length = length;
-       pBlock->data = ((unsigned char *)pBlock) +
-                       sizeof(struct r3964_block_header);
-       pBlock->locks = 0;
-       pBlock->next = NULL;
-       pBlock->owner = NULL;
-
-       memcpy(pBlock->data, pInfo->rx_buf, length);
-
-       /* queue block into rx_queue: */
-       add_rx_queue(pInfo, pBlock);
-
-       /* notify attached client processes: */
-       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-               if (pClient->sig_flags & R3964_SIG_DATA) {
-                       add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
-                               pBlock);
-               }
-       }
-       wake_up_interruptible(&pInfo->read_wait);
-
-       pInfo->state = R3964_IDLE;
-
-       trigger_transmit(pInfo);
-}
-
-static void receive_char(struct r3964_info *pInfo, const unsigned char c)
-{
-       switch (pInfo->state) {
-       case R3964_TX_REQUEST:
-               if (c == DLE) {
-                       TRACE_PS("TX_REQUEST - got DLE");
-
-                       pInfo->state = R3964_TRANSMITTING;
-                       pInfo->tx_position = 0;
-
-                       transmit_block(pInfo);
-               } else if (c == STX) {
-                       if (pInfo->nRetry == 0) {
-                               TRACE_PE("TX_REQUEST - init conflict");
-                               if (pInfo->priority == R3964_SLAVE) {
-                                       goto start_receiving;
-                               }
-                       } else {
-                               TRACE_PE("TX_REQUEST - secondary init "
-                                       "conflict!? Switching to SLAVE mode "
-                                       "for next rx.");
-                               goto start_receiving;
-                       }
-               } else {
-                       TRACE_PE("TX_REQUEST - char != DLE: %x", c);
-                       retry_transmit(pInfo);
-               }
-               break;
-       case R3964_TRANSMITTING:
-               if (c == NAK) {
-                       TRACE_PE("TRANSMITTING - got NAK");
-                       retry_transmit(pInfo);
-               } else {
-                       TRACE_PE("TRANSMITTING - got invalid char");
-
-                       pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-               }
-               break;
-       case R3964_WAIT_FOR_TX_ACK:
-               if (c == DLE) {
-                       TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
-                       remove_from_tx_queue(pInfo, R3964_OK);
-
-                       pInfo->state = R3964_IDLE;
-                       trigger_transmit(pInfo);
-               } else {
-                       retry_transmit(pInfo);
-               }
-               break;
-       case R3964_WAIT_FOR_RX_REPEAT:
-               /* FALLTHROUGH */
-       case R3964_IDLE:
-               if (c == STX) {
-                       /* Prevent rx_queue from overflow: */
-                       if (pInfo->blocks_in_rx_queue >=
-                           R3964_MAX_BLOCKS_IN_RX_QUEUE) {
-                               TRACE_PE("IDLE - got STX but no space in "
-                                               "rx_queue!");
-                               pInfo->state = R3964_WAIT_FOR_RX_BUF;
-                               mod_timer(&pInfo->tmr,
-                                         jiffies + R3964_TO_NO_BUF);
-                               break;
-                       }
-start_receiving:
-                       /* Ok, start receiving: */
-                       TRACE_PS("IDLE - got STX");
-                       pInfo->rx_position = 0;
-                       pInfo->last_rx = 0;
-                       pInfo->flags &= ~R3964_ERROR;
-                       pInfo->state = R3964_RECEIVING;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-                       pInfo->nRetry = 0;
-                       put_char(pInfo, DLE);
-                       flush(pInfo);
-                       pInfo->bcc = 0;
-               }
-               break;
-       case R3964_RECEIVING:
-               if (pInfo->rx_position < RX_BUF_SIZE) {
-                       pInfo->bcc ^= c;
-
-                       if (c == DLE) {
-                               if (pInfo->last_rx == DLE) {
-                                       pInfo->last_rx = 0;
-                                       goto char_to_buf;
-                               }
-                               pInfo->last_rx = DLE;
-                               break;
-                       } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
-                               if (pInfo->flags & R3964_BCC) {
-                                       pInfo->state = R3964_WAIT_FOR_BCC;
-                                       mod_timer(&pInfo->tmr,
-                                                 jiffies + R3964_TO_ZVZ);
-                               } else {
-                                       on_receive_block(pInfo);
-                               }
-                       } else {
-                               pInfo->last_rx = c;
-char_to_buf:
-                               pInfo->rx_buf[pInfo->rx_position++] = c;
-                               mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-                       }
-               }
-               /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
-               break;
-       case R3964_WAIT_FOR_BCC:
-               pInfo->last_rx = c;
-               on_receive_block(pInfo);
-               break;
-       }
-}
-
-static void receive_error(struct r3964_info *pInfo, const char flag)
-{
-       switch (flag) {
-       case TTY_NORMAL:
-               break;
-       case TTY_BREAK:
-               TRACE_PE("received break");
-               pInfo->flags |= R3964_BREAK;
-               break;
-       case TTY_PARITY:
-               TRACE_PE("parity error");
-               pInfo->flags |= R3964_PARITY;
-               break;
-       case TTY_FRAME:
-               TRACE_PE("frame error");
-               pInfo->flags |= R3964_FRAME;
-               break;
-       case TTY_OVERRUN:
-               TRACE_PE("frame overrun");
-               pInfo->flags |= R3964_OVERRUN;
-               break;
-       default:
-               TRACE_PE("receive_error - unknown flag %d", flag);
-               pInfo->flags |= R3964_UNKNOWN;
-               break;
-       }
-}
-
-static void on_timeout(unsigned long priv)
-{
-       struct r3964_info *pInfo = (void *)priv;
-
-       switch (pInfo->state) {
-       case R3964_TX_REQUEST:
-               TRACE_PE("TX_REQUEST - timeout");
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_FOR_TX_ACK:
-               TRACE_PE("WAIT_FOR_TX_ACK - timeout");
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_FOR_RX_BUF:
-               TRACE_PE("WAIT_FOR_RX_BUF - timeout");
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_RECEIVING:
-               TRACE_PE("RECEIVING - timeout after %d chars",
-                        pInfo->rx_position);
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_WAIT_FOR_RX_REPEAT:
-               TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_WAIT_FOR_BCC:
-               TRACE_PE("WAIT_FOR_BCC - timeout");
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       }
-}
-
-static struct r3964_client_info *findClient(struct r3964_info *pInfo,
-               struct pid *pid)
-{
-       struct r3964_client_info *pClient;
-
-       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-               if (pClient->pid == pid) {
-                       return pClient;
-               }
-       }
-       return NULL;
-}
-
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
-{
-       struct r3964_client_info *pClient;
-       struct r3964_client_info **ppClient;
-       struct r3964_message *pMsg;
-
-       if ((arg & R3964_SIG_ALL) == 0) {
-               /* Remove client from client list */
-               for (ppClient = &pInfo->firstClient; *ppClient;
-                    ppClient = &(*ppClient)->next) {
-                       pClient = *ppClient;
-
-                       if (pClient->pid == pid) {
-                               TRACE_PS("removing client %d from client list",
-                                        pid_nr(pid));
-                               *ppClient = pClient->next;
-                               while (pClient->msg_count) {
-                                       pMsg = remove_msg(pInfo, pClient);
-                                       if (pMsg) {
-                                               kfree(pMsg);
-                                               TRACE_M("enable_signals - msg "
-                                                       "kfree %p", pMsg);
-                                       }
-                               }
-                               put_pid(pClient->pid);
-                               kfree(pClient);
-                               TRACE_M("enable_signals - kfree %p", pClient);
-                               return 0;
-                       }
-               }
-               return -EINVAL;
-       } else {
-               pClient = findClient(pInfo, pid);
-               if (pClient) {
-                       /* update signal options */
-                       pClient->sig_flags = arg;
-               } else {
-                       /* add client to client list */
-                       pClient = kmalloc(sizeof(struct r3964_client_info),
-                                       GFP_KERNEL);
-                       TRACE_M("enable_signals - kmalloc %p", pClient);
-                       if (pClient == NULL)
-                               return -ENOMEM;
-
-                       TRACE_PS("add client %d to client list", pid_nr(pid));
-                       spin_lock_init(&pClient->lock);
-                       pClient->sig_flags = arg;
-                       pClient->pid = get_pid(pid);
-                       pClient->next = pInfo->firstClient;
-                       pClient->first_msg = NULL;
-                       pClient->last_msg = NULL;
-                       pClient->next_block_to_read = NULL;
-                       pClient->msg_count = 0;
-                       pInfo->firstClient = pClient;
-               }
-       }
-
-       return 0;
-}
-
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-                        unsigned char __user * buf)
-{
-       struct r3964_client_info *pClient;
-       struct r3964_block_header *block;
-
-       if (!buf) {
-               return -EINVAL;
-       }
-
-       pClient = findClient(pInfo, pid);
-       if (pClient == NULL) {
-               return -EINVAL;
-       }
-
-       block = pClient->next_block_to_read;
-       if (!block) {
-               return 0;
-       } else {
-               if (copy_to_user(buf, block->data, block->length))
-                       return -EFAULT;
-
-               remove_client_block(pInfo, pClient);
-               return block->length;
-       }
-
-       return -EINVAL;
-}
-
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-               int error_code, struct r3964_block_header *pBlock)
-{
-       struct r3964_message *pMsg;
-       unsigned long flags;
-
-       if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
-queue_the_message:
-
-               pMsg = kmalloc(sizeof(struct r3964_message),
-                               error_code ? GFP_ATOMIC : GFP_KERNEL);
-               TRACE_M("add_msg - kmalloc %p", pMsg);
-               if (pMsg == NULL) {
-                       return;
-               }
-
-               spin_lock_irqsave(&pClient->lock, flags);
-
-               pMsg->msg_id = msg_id;
-               pMsg->arg = arg;
-               pMsg->error_code = error_code;
-               pMsg->block = pBlock;
-               pMsg->next = NULL;
-
-               if (pClient->last_msg == NULL) {
-                       pClient->first_msg = pClient->last_msg = pMsg;
-               } else {
-                       pClient->last_msg->next = pMsg;
-                       pClient->last_msg = pMsg;
-               }
-
-               pClient->msg_count++;
-
-               if (pBlock != NULL) {
-                       pBlock->locks++;
-               }
-               spin_unlock_irqrestore(&pClient->lock, flags);
-       } else {
-               if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
-                   && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
-                       pClient->last_msg->arg++;
-                       TRACE_PE("add_msg - inc prev OVERFLOW-msg");
-               } else {
-                       msg_id = R3964_MSG_ACK;
-                       arg = 0;
-                       error_code = R3964_OVERFLOW;
-                       pBlock = NULL;
-                       TRACE_PE("add_msg - queue OVERFLOW-msg");
-                       goto queue_the_message;
-               }
-       }
-       /* Send SIGIO signal to client process: */
-       if (pClient->sig_flags & R3964_USE_SIGIO) {
-               kill_pid(pClient->pid, SIGIO, 1);
-       }
-}
-
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-                                       struct r3964_client_info *pClient)
-{
-       struct r3964_message *pMsg = NULL;
-       unsigned long flags;
-
-       if (pClient->first_msg) {
-               spin_lock_irqsave(&pClient->lock, flags);
-
-               pMsg = pClient->first_msg;
-               pClient->first_msg = pMsg->next;
-               if (pClient->first_msg == NULL) {
-                       pClient->last_msg = NULL;
-               }
-
-               pClient->msg_count--;
-               if (pMsg->block) {
-                       remove_client_block(pInfo, pClient);
-                       pClient->next_block_to_read = pMsg->block;
-               }
-               spin_unlock_irqrestore(&pClient->lock, flags);
-       }
-       return pMsg;
-}
-
-static void remove_client_block(struct r3964_info *pInfo,
-                               struct r3964_client_info *pClient)
-{
-       struct r3964_block_header *block;
-
-       TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
-       block = pClient->next_block_to_read;
-       if (block) {
-               block->locks--;
-               if (block->locks == 0) {
-                       remove_from_rx_queue(pInfo, block);
-               }
-       }
-       pClient->next_block_to_read = NULL;
-}
-
-/*************************************************************
- * Line discipline routines
- *************************************************************/
-
-static int r3964_open(struct tty_struct *tty)
-{
-       struct r3964_info *pInfo;
-
-       TRACE_L("open");
-       TRACE_L("tty=%p, PID=%d, disc_data=%p",
-               tty, current->pid, tty->disc_data);
-
-       pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
-       TRACE_M("r3964_open - info kmalloc %p", pInfo);
-
-       if (!pInfo) {
-               printk(KERN_ERR "r3964: failed to alloc info structure\n");
-               return -ENOMEM;
-       }
-
-       pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
-       TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
-
-       if (!pInfo->rx_buf) {
-               printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
-               kfree(pInfo);
-               TRACE_M("r3964_open - info kfree %p", pInfo);
-               return -ENOMEM;
-       }
-
-       pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
-       TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
-
-       if (!pInfo->tx_buf) {
-               printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
-               kfree(pInfo->rx_buf);
-               TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
-               kfree(pInfo);
-               TRACE_M("r3964_open - info kfree %p", pInfo);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&pInfo->lock);
-       pInfo->tty = tty;
-       init_waitqueue_head(&pInfo->read_wait);
-       pInfo->priority = R3964_MASTER;
-       pInfo->rx_first = pInfo->rx_last = NULL;
-       pInfo->tx_first = pInfo->tx_last = NULL;
-       pInfo->rx_position = 0;
-       pInfo->tx_position = 0;
-       pInfo->last_rx = 0;
-       pInfo->blocks_in_rx_queue = 0;
-       pInfo->firstClient = NULL;
-       pInfo->state = R3964_IDLE;
-       pInfo->flags = R3964_DEBUG;
-       pInfo->nRetry = 0;
-
-       tty->disc_data = pInfo;
-       tty->receive_room = 65536;
-
-       setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
-
-       return 0;
-}
-
-static void r3964_close(struct tty_struct *tty)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient, *pNext;
-       struct r3964_message *pMsg;
-       struct r3964_block_header *pHeader, *pNextHeader;
-       unsigned long flags;
-
-       TRACE_L("close");
-
-       /*
-        * Make sure that our task queue isn't activated.  If it
-        * is, take it out of the linked list.
-        */
-       del_timer_sync(&pInfo->tmr);
-
-       /* Remove client-structs and message queues: */
-       pClient = pInfo->firstClient;
-       while (pClient) {
-               pNext = pClient->next;
-               while (pClient->msg_count) {
-                       pMsg = remove_msg(pInfo, pClient);
-                       if (pMsg) {
-                               kfree(pMsg);
-                               TRACE_M("r3964_close - msg kfree %p", pMsg);
-                       }
-               }
-               put_pid(pClient->pid);
-               kfree(pClient);
-               TRACE_M("r3964_close - client kfree %p", pClient);
-               pClient = pNext;
-       }
-       /* Remove jobs from tx_queue: */
-       spin_lock_irqsave(&pInfo->lock, flags);
-       pHeader = pInfo->tx_first;
-       pInfo->tx_first = pInfo->tx_last = NULL;
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       while (pHeader) {
-               pNextHeader = pHeader->next;
-               kfree(pHeader);
-               pHeader = pNextHeader;
-       }
-
-       /* Free buffers: */
-       wake_up_interruptible(&pInfo->read_wait);
-       kfree(pInfo->rx_buf);
-       TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
-       kfree(pInfo->tx_buf);
-       TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
-       kfree(pInfo);
-       TRACE_M("r3964_close - info kfree %p", pInfo);
-}
-
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-                         unsigned char __user * buf, size_t nr)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient;
-       struct r3964_message *pMsg;
-       struct r3964_client_message theMsg;
-       int ret;
-
-       TRACE_L("read()");
-
-       tty_lock();
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               pMsg = remove_msg(pInfo, pClient);
-               if (pMsg == NULL) {
-                       /* no messages available. */
-                       if (file->f_flags & O_NONBLOCK) {
-                               ret = -EAGAIN;
-                               goto unlock;
-                       }
-                       /* block until there is a message: */
-                       wait_event_interruptible_tty(pInfo->read_wait,
-                                       (pMsg = remove_msg(pInfo, pClient)));
-               }
-
-               /* If we still haven't got a message, we must have been signalled */
-
-               if (!pMsg) {
-                       ret = -EINTR;
-                       goto unlock;
-               }
-
-               /* deliver msg to client process: */
-               theMsg.msg_id = pMsg->msg_id;
-               theMsg.arg = pMsg->arg;
-               theMsg.error_code = pMsg->error_code;
-               ret = sizeof(struct r3964_client_message);
-
-               kfree(pMsg);
-               TRACE_M("r3964_read - msg kfree %p", pMsg);
-
-               if (copy_to_user(buf, &theMsg, ret)) {
-                       ret = -EFAULT;
-                       goto unlock;
-               }
-
-               TRACE_PS("read - return %d", ret);
-               goto unlock;
-       }
-       ret = -EPERM;
-unlock:
-       tty_unlock();
-       return ret;
-}
-
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *data, size_t count)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_block_header *pHeader;
-       struct r3964_client_info *pClient;
-       unsigned char *new_data;
-
-       TRACE_L("write request, %d characters", count);
-/* 
- * Verify the pointers 
- */
-
-       if (!pInfo)
-               return -EIO;
-
-/*
- * Ensure that the caller does not wish to send too much.
- */
-       if (count > R3964_MTU) {
-               if (pInfo->flags & R3964_DEBUG) {
-                       TRACE_L(KERN_WARNING "r3964_write: truncating user "
-                               "packet from %u to mtu %d", count, R3964_MTU);
-               }
-               count = R3964_MTU;
-       }
-/*
- * Allocate a buffer for the data and copy it from the buffer with header prepended
- */
-       new_data = kmalloc(count + sizeof(struct r3964_block_header),
-                       GFP_KERNEL);
-       TRACE_M("r3964_write - kmalloc %p", new_data);
-       if (new_data == NULL) {
-               if (pInfo->flags & R3964_DEBUG) {
-                       printk(KERN_ERR "r3964_write: no memory\n");
-               }
-               return -ENOSPC;
-       }
-
-       pHeader = (struct r3964_block_header *)new_data;
-       pHeader->data = new_data + sizeof(struct r3964_block_header);
-       pHeader->length = count;
-       pHeader->locks = 0;
-       pHeader->owner = NULL;
-
-       tty_lock();
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               pHeader->owner = pClient;
-       }
-
-       memcpy(pHeader->data, data, count);     /* We already verified this */
-
-       if (pInfo->flags & R3964_DEBUG) {
-               dump_block(pHeader->data, count);
-       }
-
-/*
- * Add buffer to transmit-queue:
- */
-       add_tx_queue(pInfo, pHeader);
-       trigger_transmit(pInfo);
-
-       tty_unlock();
-
-       return 0;
-}
-
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       if (pInfo == NULL)
-               return -EINVAL;
-       switch (cmd) {
-       case R3964_ENABLE_SIGNALS:
-               return enable_signals(pInfo, task_pid(current), arg);
-       case R3964_SETPRIORITY:
-               if (arg < R3964_MASTER || arg > R3964_SLAVE)
-                       return -EINVAL;
-               pInfo->priority = arg & 0xff;
-               return 0;
-       case R3964_USE_BCC:
-               if (arg)
-                       pInfo->flags |= R3964_BCC;
-               else
-                       pInfo->flags &= ~R3964_BCC;
-               return 0;
-       case R3964_READ_TELEGRAM:
-               return read_telegram(pInfo, task_pid(current),
-                               (unsigned char __user *)arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       TRACE_L("set_termios");
-}
-
-/* Called without the kernel lock held - fine */
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-                       struct poll_table_struct *wait)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient;
-       struct r3964_message *pMsg = NULL;
-       unsigned long flags;
-       int result = POLLOUT;
-
-       TRACE_L("POLL");
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               poll_wait(file, &pInfo->read_wait, wait);
-               spin_lock_irqsave(&pInfo->lock, flags);
-               pMsg = pClient->first_msg;
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-               if (pMsg)
-                       result |= POLLIN | POLLRDNORM;
-       } else {
-               result = -EINVAL;
-       }
-       return result;
-}
-
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                       char *fp, int count)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       const unsigned char *p;
-       char *f, flags = 0;
-       int i;
-
-       for (i = count, p = cp, f = fp; i; i--, p++) {
-               if (f)
-                       flags = *f++;
-               if (flags == TTY_NORMAL) {
-                       receive_char(pInfo, *p);
-               } else {
-                       receive_error(pInfo, flags);
-               }
-
-       }
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
deleted file mode 100644 (file)
index 428f4fe..0000000
+++ /dev/null
@@ -1,2121 +0,0 @@
-/*
- * n_tty.c --- implements the N_TTY line discipline.
- *
- * This code used to be in tty_io.c, but things are getting hairy
- * enough that it made sense to split things off.  (The N_TTY
- * processing has changed so much that it's hardly recognizable,
- * anyway...)
- *
- * Note that the open routine for N_TTY is guaranteed never to return
- * an error.  This is because Linux will fall back to setting a line
- * to N_TTY if it can not switch to any other line discipline.
- *
- * Written by Theodore Ts'o, Copyright 1994.
- *
- * This file also contains code originally written by Linus Torvalds,
- * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
- *
- * This file may be redistributed under the terms of the GNU General Public
- * License.
- *
- * Reduced memory usage for older ARM systems  - Russell King.
- *
- * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
- *             the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
- *             who actually finally proved there really was a race.
- *
- * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
- *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *             Also fixed a bug in BLOCKING mode where n_tty_write returns
- *             EAGAIN
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/audit.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#include <asm/system.h>
-
-/* number of characters left in xmit buffer before select has we have room */
-#define WAKEUP_CHARS 256
-
-/*
- * This defines the low- and high-watermarks for throttling and
- * unthrottling the TTY driver.  These watermarks are used for
- * controlling the space in the read buffer.
- */
-#define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
-#define TTY_THRESHOLD_UNTHROTTLE       128
-
-/*
- * Special byte codes used in the echo buffer to represent operations
- * or special handling of characters.  Bytes in the echo buffer that
- * are not part of such special blocks are treated as normal character
- * codes.
- */
-#define ECHO_OP_START 0xff
-#define ECHO_OP_MOVE_BACK_COL 0x80
-#define ECHO_OP_SET_CANON_COL 0x81
-#define ECHO_OP_ERASE_TAB 0x82
-
-static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
-                              unsigned char __user *ptr)
-{
-       tty_audit_add_data(tty, &x, 1);
-       return put_user(x, ptr);
-}
-
-/**
- *     n_tty_set__room -       receive space
- *     @tty: terminal
- *
- *     Called by the driver to find out how much data it is
- *     permitted to feed to the line discipline without any being lost
- *     and thus to manage flow control. Not serialized. Answers for the
- *     "instant".
- */
-
-static void n_tty_set_room(struct tty_struct *tty)
-{
-       /* tty->read_cnt is not read locked ? */
-       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
-       /*
-        * If we are doing input canonicalization, and there are no
-        * pending newlines, let characters through without limit, so
-        * that erase characters will be handled.  Other excess
-        * characters will be beeped.
-        */
-       if (left <= 0)
-               left = tty->icanon && !tty->canon_data;
-       tty->receive_room = left;
-}
-
-static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
-{
-       if (tty->read_cnt < N_TTY_BUF_SIZE) {
-               tty->read_buf[tty->read_head] = c;
-               tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt++;
-       }
-}
-
-/**
- *     put_tty_queue           -       add character to tty
- *     @c: character
- *     @tty: tty device
- *
- *     Add a character to the tty read_buf queue. This is done under the
- *     read_lock to serialize character addition and also to protect us
- *     against parallel reads or flushes
- */
-
-static void put_tty_queue(unsigned char c, struct tty_struct *tty)
-{
-       unsigned long flags;
-       /*
-        *      The problem of stomping on the buffers ends here.
-        *      Why didn't anyone see this one coming? --AJK
-       */
-       spin_lock_irqsave(&tty->read_lock, flags);
-       put_tty_queue_nolock(c, tty);
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-}
-
-/**
- *     check_unthrottle        -       allow new receive data
- *     @tty; tty device
- *
- *     Check whether to call the driver unthrottle functions
- *
- *     Can sleep, may be called under the atomic_read_lock mutex but
- *     this is not guaranteed.
- */
-static void check_unthrottle(struct tty_struct *tty)
-{
-       if (tty->count)
-               tty_unthrottle(tty);
-}
-
-/**
- *     reset_buffer_flags      -       reset buffer state
- *     @tty: terminal to reset
- *
- *     Reset the read buffer counters, clear the flags,
- *     and make sure the driver is unthrottled. Called
- *     from n_tty_open() and n_tty_flush_buffer().
- *
- *     Locking: tty_read_lock for read fields.
- */
-
-static void reset_buffer_flags(struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->read_lock, flags);
-       tty->read_head = tty->read_tail = tty->read_cnt = 0;
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-
-       mutex_lock(&tty->echo_lock);
-       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
-       mutex_unlock(&tty->echo_lock);
-
-       tty->canon_head = tty->canon_data = tty->erasing = 0;
-       memset(&tty->read_flags, 0, sizeof tty->read_flags);
-       n_tty_set_room(tty);
-       check_unthrottle(tty);
-}
-
-/**
- *     n_tty_flush_buffer      -       clean input queue
- *     @tty:   terminal device
- *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup) or when the N_TTY line discipline internally has to
- *     clean the pending queue (for example some signals).
- *
- *     Locking: ctrl_lock, read_lock.
- */
-
-static void n_tty_flush_buffer(struct tty_struct *tty)
-{
-       unsigned long flags;
-       /* clear everything and unthrottle the driver */
-       reset_buffer_flags(tty);
-
-       if (!tty->link)
-               return;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->link->packet) {
-               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
-               wake_up_interruptible(&tty->link->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-}
-
-/**
- *     n_tty_chars_in_buffer   -       report available bytes
- *     @tty: tty device
- *
- *     Report the number of characters buffered to be delivered to user
- *     at this instant in time.
- *
- *     Locking: read_lock
- */
-
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
-{
-       unsigned long flags;
-       ssize_t n = 0;
-
-       spin_lock_irqsave(&tty->read_lock, flags);
-       if (!tty->icanon) {
-               n = tty->read_cnt;
-       } else if (tty->canon_data) {
-               n = (tty->canon_head > tty->read_tail) ?
-                       tty->canon_head - tty->read_tail :
-                       tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
-       }
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-       return n;
-}
-
-/**
- *     is_utf8_continuation    -       utf8 multibyte check
- *     @c: byte to check
- *
- *     Returns true if the utf8 character 'c' is a multibyte continuation
- *     character. We use this to correctly compute the on screen size
- *     of the character when printing
- */
-
-static inline int is_utf8_continuation(unsigned char c)
-{
-       return (c & 0xc0) == 0x80;
-}
-
-/**
- *     is_continuation         -       multibyte check
- *     @c: byte to check
- *
- *     Returns true if the utf8 character 'c' is a multibyte continuation
- *     character and the terminal is in unicode mode.
- */
-
-static inline int is_continuation(unsigned char c, struct tty_struct *tty)
-{
-       return I_IUTF8(tty) && is_utf8_continuation(c);
-}
-
-/**
- *     do_output_char                  -       output one character
- *     @c: character (or partial unicode symbol)
- *     @tty: terminal device
- *     @space: space available in tty driver write buffer
- *
- *     This is a helper function that handles one output character
- *     (including special characters like TAB, CR, LF, etc.),
- *     doing OPOST processing and putting the results in the
- *     tty driver's write buffer.
- *
- *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
- *     and NLDLY.  They simply aren't relevant in the world today.
- *     If you ever need them, add them here.
- *
- *     Returns the number of bytes of buffer space used or -1 if
- *     no space left.
- *
- *     Locking: should be called under the output_lock to protect
- *              the column state and space left in the buffer
- */
-
-static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
-{
-       int     spaces;
-
-       if (!space)
-               return -1;
-
-       switch (c) {
-       case '\n':
-               if (O_ONLRET(tty))
-                       tty->column = 0;
-               if (O_ONLCR(tty)) {
-                       if (space < 2)
-                               return -1;
-                       tty->canon_column = tty->column = 0;
-                       tty->ops->write(tty, "\r\n", 2);
-                       return 2;
-               }
-               tty->canon_column = tty->column;
-               break;
-       case '\r':
-               if (O_ONOCR(tty) && tty->column == 0)
-                       return 0;
-               if (O_OCRNL(tty)) {
-                       c = '\n';
-                       if (O_ONLRET(tty))
-                               tty->canon_column = tty->column = 0;
-                       break;
-               }
-               tty->canon_column = tty->column = 0;
-               break;
-       case '\t':
-               spaces = 8 - (tty->column & 7);
-               if (O_TABDLY(tty) == XTABS) {
-                       if (space < spaces)
-                               return -1;
-                       tty->column += spaces;
-                       tty->ops->write(tty, "        ", spaces);
-                       return spaces;
-               }
-               tty->column += spaces;
-               break;
-       case '\b':
-               if (tty->column > 0)
-                       tty->column--;
-               break;
-       default:
-               if (!iscntrl(c)) {
-                       if (O_OLCUC(tty))
-                               c = toupper(c);
-                       if (!is_continuation(c, tty))
-                               tty->column++;
-               }
-               break;
-       }
-
-       tty_put_char(tty, c);
-       return 1;
-}
-
-/**
- *     process_output                  -       output post processor
- *     @c: character (or partial unicode symbol)
- *     @tty: terminal device
- *
- *     Output one character with OPOST processing.
- *     Returns -1 when the output device is full and the character
- *     must be retried.
- *
- *     Locking: output_lock to protect column state and space left
- *              (also, this is called from n_tty_write under the
- *               tty layer write lock)
- */
-
-static int process_output(unsigned char c, struct tty_struct *tty)
-{
-       int     space, retval;
-
-       mutex_lock(&tty->output_lock);
-
-       space = tty_write_room(tty);
-       retval = do_output_char(c, tty, space);
-
-       mutex_unlock(&tty->output_lock);
-       if (retval < 0)
-               return -1;
-       else
-               return 0;
-}
-
-/**
- *     process_output_block            -       block post processor
- *     @tty: terminal device
- *     @buf: character buffer
- *     @nr: number of bytes to output
- *
- *     Output a block of characters with OPOST processing.
- *     Returns the number of characters output.
- *
- *     This path is used to speed up block console writes, among other
- *     things when processing blocks of output data. It handles only
- *     the simple cases normally found and helps to generate blocks of
- *     symbols for the console driver and thus improve performance.
- *
- *     Locking: output_lock to protect column state and space left
- *              (also, this is called from n_tty_write under the
- *               tty layer write lock)
- */
-
-static ssize_t process_output_block(struct tty_struct *tty,
-                                   const unsigned char *buf, unsigned int nr)
-{
-       int     space;
-       int     i;
-       const unsigned char *cp;
-
-       mutex_lock(&tty->output_lock);
-
-       space = tty_write_room(tty);
-       if (!space) {
-               mutex_unlock(&tty->output_lock);
-               return 0;
-       }
-       if (nr > space)
-               nr = space;
-
-       for (i = 0, cp = buf; i < nr; i++, cp++) {
-               unsigned char c = *cp;
-
-               switch (c) {
-               case '\n':
-                       if (O_ONLRET(tty))
-                               tty->column = 0;
-                       if (O_ONLCR(tty))
-                               goto break_out;
-                       tty->canon_column = tty->column;
-                       break;
-               case '\r':
-                       if (O_ONOCR(tty) && tty->column == 0)
-                               goto break_out;
-                       if (O_OCRNL(tty))
-                               goto break_out;
-                       tty->canon_column = tty->column = 0;
-                       break;
-               case '\t':
-                       goto break_out;
-               case '\b':
-                       if (tty->column > 0)
-                               tty->column--;
-                       break;
-               default:
-                       if (!iscntrl(c)) {
-                               if (O_OLCUC(tty))
-                                       goto break_out;
-                               if (!is_continuation(c, tty))
-                                       tty->column++;
-                       }
-                       break;
-               }
-       }
-break_out:
-       i = tty->ops->write(tty, buf, i);
-
-       mutex_unlock(&tty->output_lock);
-       return i;
-}
-
-/**
- *     process_echoes  -       write pending echo characters
- *     @tty: terminal device
- *
- *     Write previously buffered echo (and other ldisc-generated)
- *     characters to the tty.
- *
- *     Characters generated by the ldisc (including echoes) need to
- *     be buffered because the driver's write buffer can fill during
- *     heavy program output.  Echoing straight to the driver will
- *     often fail under these conditions, causing lost characters and
- *     resulting mismatches of ldisc state information.
- *
- *     Since the ldisc state must represent the characters actually sent
- *     to the driver at the time of the write, operations like certain
- *     changes in column state are also saved in the buffer and executed
- *     here.
- *
- *     A circular fifo buffer is used so that the most recent characters
- *     are prioritized.  Also, when control characters are echoed with a
- *     prefixed "^", the pair is treated atomically and thus not separated.
- *
- *     Locking: output_lock to protect column state and space left,
- *              echo_lock to protect the echo buffer
- */
-
-static void process_echoes(struct tty_struct *tty)
-{
-       int     space, nr;
-       unsigned char c;
-       unsigned char *cp, *buf_end;
-
-       if (!tty->echo_cnt)
-               return;
-
-       mutex_lock(&tty->output_lock);
-       mutex_lock(&tty->echo_lock);
-
-       space = tty_write_room(tty);
-
-       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
-       cp = tty->echo_buf + tty->echo_pos;
-       nr = tty->echo_cnt;
-       while (nr > 0) {
-               c = *cp;
-               if (c == ECHO_OP_START) {
-                       unsigned char op;
-                       unsigned char *opp;
-                       int no_space_left = 0;
-
-                       /*
-                        * If the buffer byte is the start of a multi-byte
-                        * operation, get the next byte, which is either the
-                        * op code or a control character value.
-                        */
-                       opp = cp + 1;
-                       if (opp == buf_end)
-                               opp -= N_TTY_BUF_SIZE;
-                       op = *opp;
-
-                       switch (op) {
-                               unsigned int num_chars, num_bs;
-
-                       case ECHO_OP_ERASE_TAB:
-                               if (++opp == buf_end)
-                                       opp -= N_TTY_BUF_SIZE;
-                               num_chars = *opp;
-
-                               /*
-                                * Determine how many columns to go back
-                                * in order to erase the tab.
-                                * This depends on the number of columns
-                                * used by other characters within the tab
-                                * area.  If this (modulo 8) count is from
-                                * the start of input rather than from a
-                                * previous tab, we offset by canon column.
-                                * Otherwise, tab spacing is normal.
-                                */
-                               if (!(num_chars & 0x80))
-                                       num_chars += tty->canon_column;
-                               num_bs = 8 - (num_chars & 7);
-
-                               if (num_bs > space) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               space -= num_bs;
-                               while (num_bs--) {
-                                       tty_put_char(tty, '\b');
-                                       if (tty->column > 0)
-                                               tty->column--;
-                               }
-                               cp += 3;
-                               nr -= 3;
-                               break;
-
-                       case ECHO_OP_SET_CANON_COL:
-                               tty->canon_column = tty->column;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       case ECHO_OP_MOVE_BACK_COL:
-                               if (tty->column > 0)
-                                       tty->column--;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       case ECHO_OP_START:
-                               /* This is an escaped echo op start code */
-                               if (!space) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               tty_put_char(tty, ECHO_OP_START);
-                               tty->column++;
-                               space--;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       default:
-                               /*
-                                * If the op is not a special byte code,
-                                * it is a ctrl char tagged to be echoed
-                                * as "^X" (where X is the letter
-                                * representing the control char).
-                                * Note that we must ensure there is
-                                * enough space for the whole ctrl pair.
-                                *
-                                */
-                               if (space < 2) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               tty_put_char(tty, '^');
-                               tty_put_char(tty, op ^ 0100);
-                               tty->column += 2;
-                               space -= 2;
-                               cp += 2;
-                               nr -= 2;
-                       }
-
-                       if (no_space_left)
-                               break;
-               } else {
-                       if (O_OPOST(tty) &&
-                           !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-                               int retval = do_output_char(c, tty, space);
-                               if (retval < 0)
-                                       break;
-                               space -= retval;
-                       } else {
-                               if (!space)
-                                       break;
-                               tty_put_char(tty, c);
-                               space -= 1;
-                       }
-                       cp += 1;
-                       nr -= 1;
-               }
-
-               /* When end of circular buffer reached, wrap around */
-               if (cp >= buf_end)
-                       cp -= N_TTY_BUF_SIZE;
-       }
-
-       if (nr == 0) {
-               tty->echo_pos = 0;
-               tty->echo_cnt = 0;
-               tty->echo_overrun = 0;
-       } else {
-               int num_processed = tty->echo_cnt - nr;
-               tty->echo_pos += num_processed;
-               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-               tty->echo_cnt = nr;
-               if (num_processed > 0)
-                       tty->echo_overrun = 0;
-       }
-
-       mutex_unlock(&tty->echo_lock);
-       mutex_unlock(&tty->output_lock);
-
-       if (tty->ops->flush_chars)
-               tty->ops->flush_chars(tty);
-}
-
-/**
- *     add_echo_byte   -       add a byte to the echo buffer
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Add a character or operation byte to the echo buffer.
- *
- *     Should be called under the echo lock to protect the echo buffer.
- */
-
-static void add_echo_byte(unsigned char c, struct tty_struct *tty)
-{
-       int     new_byte_pos;
-
-       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
-               /* Circular buffer is already at capacity */
-               new_byte_pos = tty->echo_pos;
-
-               /*
-                * Since the buffer start position needs to be advanced,
-                * be sure to step by a whole operation byte group.
-                */
-               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
-                       if (tty->echo_buf[(tty->echo_pos + 1) &
-                                         (N_TTY_BUF_SIZE - 1)] ==
-                                               ECHO_OP_ERASE_TAB) {
-                               tty->echo_pos += 3;
-                               tty->echo_cnt -= 2;
-                       } else {
-                               tty->echo_pos += 2;
-                               tty->echo_cnt -= 1;
-                       }
-               } else {
-                       tty->echo_pos++;
-               }
-               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-
-               tty->echo_overrun = 1;
-       } else {
-               new_byte_pos = tty->echo_pos + tty->echo_cnt;
-               new_byte_pos &= N_TTY_BUF_SIZE - 1;
-               tty->echo_cnt++;
-       }
-
-       tty->echo_buf[new_byte_pos] = c;
-}
-
-/**
- *     echo_move_back_col      -       add operation to move back a column
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to move back one column.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_move_back_col(struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_set_canon_col      -       add operation to set the canon column
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to set the canon column
- *     to the current column.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_set_canon_col(struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_erase_tab  -       add operation to erase a tab
- *     @num_chars: number of character columns already used
- *     @after_tab: true if num_chars starts after a previous tab
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to erase a tab.
- *
- *     Called by the eraser function, which knows how many character
- *     columns have been used since either a previous tab or the start
- *     of input.  This information will be used later, along with
- *     canon column (if applicable), to go back the correct number
- *     of columns.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_erase_tab(unsigned int num_chars, int after_tab,
-                          struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
-
-       /* We only need to know this modulo 8 (tab spacing) */
-       num_chars &= 7;
-
-       /* Set the high bit as a flag if num_chars is after a previous tab */
-       if (after_tab)
-               num_chars |= 0x80;
-
-       add_echo_byte(num_chars, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_char_raw   -       echo a character raw
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Echo user input back onto the screen. This must be called only when
- *     L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *     This variant does not treat control characters specially.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char_raw(unsigned char c, struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       if (c == ECHO_OP_START) {
-               add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(ECHO_OP_START, tty);
-       } else {
-               add_echo_byte(c, tty);
-       }
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_char       -       echo a character
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Echo user input back onto the screen. This must be called only when
- *     L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *     This variant tags control characters to be echoed as "^X"
- *     (where X is the letter representing the control char).
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char(unsigned char c, struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       if (c == ECHO_OP_START) {
-               add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(ECHO_OP_START, tty);
-       } else {
-               if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
-                       add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(c, tty);
-       }
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     finish_erasing          -       complete erase
- *     @tty: tty doing the erase
- */
-
-static inline void finish_erasing(struct tty_struct *tty)
-{
-       if (tty->erasing) {
-               echo_char_raw('/', tty);
-               tty->erasing = 0;
-       }
-}
-
-/**
- *     eraser          -       handle erase function
- *     @c: character input
- *     @tty: terminal device
- *
- *     Perform erase and necessary output when an erase character is
- *     present in the stream from the driver layer. Handles the complexities
- *     of UTF-8 multibyte symbols.
- *
- *     Locking: read_lock for tty buffers
- */
-
-static void eraser(unsigned char c, struct tty_struct *tty)
-{
-       enum { ERASE, WERASE, KILL } kill_type;
-       int head, seen_alnums, cnt;
-       unsigned long flags;
-
-       /* FIXME: locking needed ? */
-       if (tty->read_head == tty->canon_head) {
-               /* process_output('\a', tty); */ /* what do you think? */
-               return;
-       }
-       if (c == ERASE_CHAR(tty))
-               kill_type = ERASE;
-       else if (c == WERASE_CHAR(tty))
-               kill_type = WERASE;
-       else {
-               if (!L_ECHO(tty)) {
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-                                         (N_TTY_BUF_SIZE - 1));
-                       tty->read_head = tty->canon_head;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       return;
-               }
-               if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-                                         (N_TTY_BUF_SIZE - 1));
-                       tty->read_head = tty->canon_head;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       finish_erasing(tty);
-                       echo_char(KILL_CHAR(tty), tty);
-                       /* Add a newline if ECHOK is on and ECHOKE is off. */
-                       if (L_ECHOK(tty))
-                               echo_char_raw('\n', tty);
-                       return;
-               }
-               kill_type = KILL;
-       }
-
-       seen_alnums = 0;
-       /* FIXME: Locking ?? */
-       while (tty->read_head != tty->canon_head) {
-               head = tty->read_head;
-
-               /* erase a single possibly multibyte character */
-               do {
-                       head = (head - 1) & (N_TTY_BUF_SIZE-1);
-                       c = tty->read_buf[head];
-               } while (is_continuation(c, tty) && head != tty->canon_head);
-
-               /* do not partially erase */
-               if (is_continuation(c, tty))
-                       break;
-
-               if (kill_type == WERASE) {
-                       /* Equivalent to BSD's ALTWERASE. */
-                       if (isalnum(c) || c == '_')
-                               seen_alnums++;
-                       else if (seen_alnums)
-                               break;
-               }
-               cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
-               spin_lock_irqsave(&tty->read_lock, flags);
-               tty->read_head = head;
-               tty->read_cnt -= cnt;
-               spin_unlock_irqrestore(&tty->read_lock, flags);
-               if (L_ECHO(tty)) {
-                       if (L_ECHOPRT(tty)) {
-                               if (!tty->erasing) {
-                                       echo_char_raw('\\', tty);
-                                       tty->erasing = 1;
-                               }
-                               /* if cnt > 1, output a multi-byte character */
-                               echo_char(c, tty);
-                               while (--cnt > 0) {
-                                       head = (head+1) & (N_TTY_BUF_SIZE-1);
-                                       echo_char_raw(tty->read_buf[head], tty);
-                                       echo_move_back_col(tty);
-                               }
-                       } else if (kill_type == ERASE && !L_ECHOE(tty)) {
-                               echo_char(ERASE_CHAR(tty), tty);
-                       } else if (c == '\t') {
-                               unsigned int num_chars = 0;
-                               int after_tab = 0;
-                               unsigned long tail = tty->read_head;
-
-                               /*
-                                * Count the columns used for characters
-                                * since the start of input or after a
-                                * previous tab.
-                                * This info is used to go back the correct
-                                * number of columns.
-                                */
-                               while (tail != tty->canon_head) {
-                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
-                                       c = tty->read_buf[tail];
-                                       if (c == '\t') {
-                                               after_tab = 1;
-                                               break;
-                                       } else if (iscntrl(c)) {
-                                               if (L_ECHOCTL(tty))
-                                                       num_chars += 2;
-                                       } else if (!is_continuation(c, tty)) {
-                                               num_chars++;
-                                       }
-                               }
-                               echo_erase_tab(num_chars, after_tab, tty);
-                       } else {
-                               if (iscntrl(c) && L_ECHOCTL(tty)) {
-                                       echo_char_raw('\b', tty);
-                                       echo_char_raw(' ', tty);
-                                       echo_char_raw('\b', tty);
-                               }
-                               if (!iscntrl(c) || L_ECHOCTL(tty)) {
-                                       echo_char_raw('\b', tty);
-                                       echo_char_raw(' ', tty);
-                                       echo_char_raw('\b', tty);
-                               }
-                       }
-               }
-               if (kill_type == ERASE)
-                       break;
-       }
-       if (tty->read_head == tty->canon_head && L_ECHO(tty))
-               finish_erasing(tty);
-}
-
-/**
- *     isig            -       handle the ISIG optio
- *     @sig: signal
- *     @tty: terminal
- *     @flush: force flush
- *
- *     Called when a signal is being sent due to terminal input. This
- *     may caus terminal flushing to take place according to the termios
- *     settings and character used. Called from the driver receive_buf
- *     path so serialized.
- *
- *     Locking: ctrl_lock, read_lock (both via flush buffer)
- */
-
-static inline void isig(int sig, struct tty_struct *tty, int flush)
-{
-       if (tty->pgrp)
-               kill_pgrp(tty->pgrp, sig, 1);
-       if (flush || !L_NOFLSH(tty)) {
-               n_tty_flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-       }
-}
-
-/**
- *     n_tty_receive_break     -       handle break
- *     @tty: terminal
- *
- *     An RS232 break event has been hit in the incoming bitstream. This
- *     can cause a variety of events depending upon the termios settings.
- *
- *     Called from the receive_buf path so single threaded.
- */
-
-static inline void n_tty_receive_break(struct tty_struct *tty)
-{
-       if (I_IGNBRK(tty))
-               return;
-       if (I_BRKINT(tty)) {
-               isig(SIGINT, tty, 1);
-               return;
-       }
-       if (I_PARMRK(tty)) {
-               put_tty_queue('\377', tty);
-               put_tty_queue('\0', tty);
-       }
-       put_tty_queue('\0', tty);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_receive_overrun   -       handle overrun reporting
- *     @tty: terminal
- *
- *     Data arrived faster than we could process it. While the tty
- *     driver has flagged this the bits that were missed are gone
- *     forever.
- *
- *     Called from the receive_buf path so single threaded. Does not
- *     need locking as num_overrun and overrun_time are function
- *     private.
- */
-
-static inline void n_tty_receive_overrun(struct tty_struct *tty)
-{
-       char buf[64];
-
-       tty->num_overrun++;
-       if (time_before(tty->overrun_time, jiffies - HZ) ||
-                       time_after(tty->overrun_time, jiffies)) {
-               printk(KERN_WARNING "%s: %d input overrun(s)\n",
-                       tty_name(tty, buf),
-                       tty->num_overrun);
-               tty->overrun_time = jiffies;
-               tty->num_overrun = 0;
-       }
-}
-
-/**
- *     n_tty_receive_parity_error      -       error notifier
- *     @tty: terminal device
- *     @c: character
- *
- *     Process a parity error and queue the right data to indicate
- *     the error case if necessary. Locking as per n_tty_receive_buf.
- */
-static inline void n_tty_receive_parity_error(struct tty_struct *tty,
-                                             unsigned char c)
-{
-       if (I_IGNPAR(tty))
-               return;
-       if (I_PARMRK(tty)) {
-               put_tty_queue('\377', tty);
-               put_tty_queue('\0', tty);
-               put_tty_queue(c, tty);
-       } else  if (I_INPCK(tty))
-               put_tty_queue('\0', tty);
-       else
-               put_tty_queue(c, tty);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_receive_char      -       perform processing
- *     @tty: terminal device
- *     @c: character
- *
- *     Process an individual character of input received from the driver.
- *     This is serialized with respect to itself by the rules for the
- *     driver above.
- */
-
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
-{
-       unsigned long flags;
-       int parmrk;
-
-       if (tty->raw) {
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (I_ISTRIP(tty))
-               c &= 0x7f;
-       if (I_IUCLC(tty) && L_IEXTEN(tty))
-               c = tolower(c);
-
-       if (L_EXTPROC(tty)) {
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
-           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
-           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
-               start_tty(tty);
-               process_echoes(tty);
-       }
-
-       if (tty->closing) {
-               if (I_IXON(tty)) {
-                       if (c == START_CHAR(tty)) {
-                               start_tty(tty);
-                               process_echoes(tty);
-                       } else if (c == STOP_CHAR(tty))
-                               stop_tty(tty);
-               }
-               return;
-       }
-
-       /*
-        * If the previous character was LNEXT, or we know that this
-        * character is not one of the characters that we'll have to
-        * handle specially, do shortcut processing to speed things
-        * up.
-        */
-       if (!test_bit(c, tty->process_char_map) || tty->lnext) {
-               tty->lnext = 0;
-               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-                       /* beep if no space */
-                       if (L_ECHO(tty))
-                               process_output('\a', tty);
-                       return;
-               }
-               if (L_ECHO(tty)) {
-                       finish_erasing(tty);
-                       /* Record the column of first canon char. */
-                       if (tty->canon_head == tty->read_head)
-                               echo_set_canon_col(tty);
-                       echo_char(c, tty);
-                       process_echoes(tty);
-               }
-               if (parmrk)
-                       put_tty_queue(c, tty);
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (I_IXON(tty)) {
-               if (c == START_CHAR(tty)) {
-                       start_tty(tty);
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == STOP_CHAR(tty)) {
-                       stop_tty(tty);
-                       return;
-               }
-       }
-
-       if (L_ISIG(tty)) {
-               int signal;
-               signal = SIGINT;
-               if (c == INTR_CHAR(tty))
-                       goto send_signal;
-               signal = SIGQUIT;
-               if (c == QUIT_CHAR(tty))
-                       goto send_signal;
-               signal = SIGTSTP;
-               if (c == SUSP_CHAR(tty)) {
-send_signal:
-                       /*
-                        * Note that we do not use isig() here because we want
-                        * the order to be:
-                        * 1) flush, 2) echo, 3) signal
-                        */
-                       if (!L_NOFLSH(tty)) {
-                               n_tty_flush_buffer(tty);
-                               tty_driver_flush_buffer(tty);
-                       }
-                       if (I_IXON(tty))
-                               start_tty(tty);
-                       if (L_ECHO(tty)) {
-                               echo_char(c, tty);
-                               process_echoes(tty);
-                       }
-                       if (tty->pgrp)
-                               kill_pgrp(tty->pgrp, signal, 1);
-                       return;
-               }
-       }
-
-       if (c == '\r') {
-               if (I_IGNCR(tty))
-                       return;
-               if (I_ICRNL(tty))
-                       c = '\n';
-       } else if (c == '\n' && I_INLCR(tty))
-               c = '\r';
-
-       if (tty->icanon) {
-               if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
-                   (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
-                       eraser(c, tty);
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
-                       tty->lnext = 1;
-                       if (L_ECHO(tty)) {
-                               finish_erasing(tty);
-                               if (L_ECHOCTL(tty)) {
-                                       echo_char_raw('^', tty);
-                                       echo_char_raw('\b', tty);
-                                       process_echoes(tty);
-                               }
-                       }
-                       return;
-               }
-               if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
-                   L_IEXTEN(tty)) {
-                       unsigned long tail = tty->canon_head;
-
-                       finish_erasing(tty);
-                       echo_char(c, tty);
-                       echo_char_raw('\n', tty);
-                       while (tail != tty->read_head) {
-                               echo_char(tty->read_buf[tail], tty);
-                               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-                       }
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == '\n') {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
-                               if (L_ECHO(tty))
-                                       process_output('\a', tty);
-                               return;
-                       }
-                       if (L_ECHO(tty) || L_ECHONL(tty)) {
-                               echo_char_raw('\n', tty);
-                               process_echoes(tty);
-                       }
-                       goto handle_newline;
-               }
-               if (c == EOF_CHAR(tty)) {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
-                               return;
-                       if (tty->canon_head != tty->read_head)
-                               set_bit(TTY_PUSH, &tty->flags);
-                       c = __DISABLED_CHAR;
-                       goto handle_newline;
-               }
-               if ((c == EOL_CHAR(tty)) ||
-                   (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
-                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
-                                ? 1 : 0;
-                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
-                               if (L_ECHO(tty))
-                                       process_output('\a', tty);
-                               return;
-                       }
-                       /*
-                        * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
-                        */
-                       if (L_ECHO(tty)) {
-                               /* Record the column of first canon char. */
-                               if (tty->canon_head == tty->read_head)
-                                       echo_set_canon_col(tty);
-                               echo_char(c, tty);
-                               process_echoes(tty);
-                       }
-                       /*
-                        * XXX does PARMRK doubling happen for
-                        * EOL_CHAR and EOL2_CHAR?
-                        */
-                       if (parmrk)
-                               put_tty_queue(c, tty);
-
-handle_newline:
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       set_bit(tty->read_head, tty->read_flags);
-                       put_tty_queue_nolock(c, tty);
-                       tty->canon_head = tty->read_head;
-                       tty->canon_data++;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-                       if (waitqueue_active(&tty->read_wait))
-                               wake_up_interruptible(&tty->read_wait);
-                       return;
-               }
-       }
-
-       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-               /* beep if no space */
-               if (L_ECHO(tty))
-                       process_output('\a', tty);
-               return;
-       }
-       if (L_ECHO(tty)) {
-               finish_erasing(tty);
-               if (c == '\n')
-                       echo_char_raw('\n', tty);
-               else {
-                       /* Record the column of first canon char. */
-                       if (tty->canon_head == tty->read_head)
-                               echo_set_canon_col(tty);
-                       echo_char(c, tty);
-               }
-               process_echoes(tty);
-       }
-
-       if (parmrk)
-               put_tty_queue(c, tty);
-
-       put_tty_queue(c, tty);
-}
-
-
-/**
- *     n_tty_write_wakeup      -       asynchronous I/O notifier
- *     @tty: tty device
- *
- *     Required for the ptys, serial driver etc. since processes
- *     that attach themselves to the master and rely on ASYNC
- *     IO must be woken up
- */
-
-static void n_tty_write_wakeup(struct tty_struct *tty)
-{
-       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
-               kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
-}
-
-/**
- *     n_tty_receive_buf       -       data receive
- *     @tty: terminal device
- *     @cp: buffer
- *     @fp: flag buffer
- *     @count: characters
- *
- *     Called by the terminal driver when a block of characters has
- *     been received. This function must be called from soft contexts
- *     not from interrupt context. The driver is responsible for making
- *     calls one at a time and in order (or using flush_to_ldisc)
- */
-
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       const unsigned char *p;
-       char *f, flags = TTY_NORMAL;
-       int     i;
-       char    buf[64];
-       unsigned long cpuflags;
-
-       if (!tty->read_buf)
-               return;
-
-       if (tty->real_raw) {
-               spin_lock_irqsave(&tty->read_lock, cpuflags);
-               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-                       N_TTY_BUF_SIZE - tty->read_head);
-               i = min(count, i);
-               memcpy(tty->read_buf + tty->read_head, cp, i);
-               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt += i;
-               cp += i;
-               count -= i;
-
-               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-                       N_TTY_BUF_SIZE - tty->read_head);
-               i = min(count, i);
-               memcpy(tty->read_buf + tty->read_head, cp, i);
-               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt += i;
-               spin_unlock_irqrestore(&tty->read_lock, cpuflags);
-       } else {
-               for (i = count, p = cp, f = fp; i; i--, p++) {
-                       if (f)
-                               flags = *f++;
-                       switch (flags) {
-                       case TTY_NORMAL:
-                               n_tty_receive_char(tty, *p);
-                               break;
-                       case TTY_BREAK:
-                               n_tty_receive_break(tty);
-                               break;
-                       case TTY_PARITY:
-                       case TTY_FRAME:
-                               n_tty_receive_parity_error(tty, *p);
-                               break;
-                       case TTY_OVERRUN:
-                               n_tty_receive_overrun(tty);
-                               break;
-                       default:
-                               printk(KERN_ERR "%s: unknown flag %d\n",
-                                      tty_name(tty, buf), flags);
-                               break;
-                       }
-               }
-               if (tty->ops->flush_chars)
-                       tty->ops->flush_chars(tty);
-       }
-
-       n_tty_set_room(tty);
-
-       if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
-               L_EXTPROC(tty)) {
-               kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-               if (waitqueue_active(&tty->read_wait))
-                       wake_up_interruptible(&tty->read_wait);
-       }
-
-       /*
-        * Check the remaining room for the input canonicalization
-        * mode.  We don't want to throttle the driver if we're in
-        * canonical mode and don't have a newline yet!
-        */
-       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
-               tty_throttle(tty);
-}
-
-int is_ignored(int sig)
-{
-       return (sigismember(&current->blocked, sig) ||
-               current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
-}
-
-/**
- *     n_tty_set_termios       -       termios data changed
- *     @tty: terminal
- *     @old: previous data
- *
- *     Called by the tty layer when the user changes termios flags so
- *     that the line discipline can plan ahead. This function cannot sleep
- *     and is protected from re-entry by the tty layer. The user is
- *     guaranteed that this function will not be re-entered or in progress
- *     when the ldisc is closed.
- *
- *     Locking: Caller holds tty->termios_mutex
- */
-
-static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       int canon_change = 1;
-       BUG_ON(!tty);
-
-       if (old)
-               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
-       if (canon_change) {
-               memset(&tty->read_flags, 0, sizeof tty->read_flags);
-               tty->canon_head = tty->read_tail;
-               tty->canon_data = 0;
-               tty->erasing = 0;
-       }
-
-       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-               wake_up_interruptible(&tty->read_wait);
-
-       tty->icanon = (L_ICANON(tty) != 0);
-       if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
-               tty->raw = 1;
-               tty->real_raw = 1;
-               n_tty_set_room(tty);
-               return;
-       }
-       if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
-           I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
-           I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
-           I_PARMRK(tty)) {
-               memset(tty->process_char_map, 0, 256/8);
-
-               if (I_IGNCR(tty) || I_ICRNL(tty))
-                       set_bit('\r', tty->process_char_map);
-               if (I_INLCR(tty))
-                       set_bit('\n', tty->process_char_map);
-
-               if (L_ICANON(tty)) {
-                       set_bit(ERASE_CHAR(tty), tty->process_char_map);
-                       set_bit(KILL_CHAR(tty), tty->process_char_map);
-                       set_bit(EOF_CHAR(tty), tty->process_char_map);
-                       set_bit('\n', tty->process_char_map);
-                       set_bit(EOL_CHAR(tty), tty->process_char_map);
-                       if (L_IEXTEN(tty)) {
-                               set_bit(WERASE_CHAR(tty),
-                                       tty->process_char_map);
-                               set_bit(LNEXT_CHAR(tty),
-                                       tty->process_char_map);
-                               set_bit(EOL2_CHAR(tty),
-                                       tty->process_char_map);
-                               if (L_ECHO(tty))
-                                       set_bit(REPRINT_CHAR(tty),
-                                               tty->process_char_map);
-                       }
-               }
-               if (I_IXON(tty)) {
-                       set_bit(START_CHAR(tty), tty->process_char_map);
-                       set_bit(STOP_CHAR(tty), tty->process_char_map);
-               }
-               if (L_ISIG(tty)) {
-                       set_bit(INTR_CHAR(tty), tty->process_char_map);
-                       set_bit(QUIT_CHAR(tty), tty->process_char_map);
-                       set_bit(SUSP_CHAR(tty), tty->process_char_map);
-               }
-               clear_bit(__DISABLED_CHAR, tty->process_char_map);
-               tty->raw = 0;
-               tty->real_raw = 0;
-       } else {
-               tty->raw = 1;
-               if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
-                   (I_IGNPAR(tty) || !I_INPCK(tty)) &&
-                   (tty->driver->flags & TTY_DRIVER_REAL_RAW))
-                       tty->real_raw = 1;
-               else
-                       tty->real_raw = 0;
-       }
-       n_tty_set_room(tty);
-       /* The termios change make the tty ready for I/O */
-       wake_up_interruptible(&tty->write_wait);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_close             -       close the ldisc for this tty
- *     @tty: device
- *
- *     Called from the terminal layer when this line discipline is
- *     being shut down, either because of a close or becsuse of a
- *     discipline change. The function will not be called while other
- *     ldisc methods are in progress.
- */
-
-static void n_tty_close(struct tty_struct *tty)
-{
-       n_tty_flush_buffer(tty);
-       if (tty->read_buf) {
-               kfree(tty->read_buf);
-               tty->read_buf = NULL;
-       }
-       if (tty->echo_buf) {
-               kfree(tty->echo_buf);
-               tty->echo_buf = NULL;
-       }
-}
-
-/**
- *     n_tty_open              -       open an ldisc
- *     @tty: terminal to open
- *
- *     Called when this line discipline is being attached to the
- *     terminal device. Can sleep. Called serialized so that no
- *     other events will occur in parallel. No further open will occur
- *     until a close.
- */
-
-static int n_tty_open(struct tty_struct *tty)
-{
-       if (!tty)
-               return -EINVAL;
-
-       /* These are ugly. Currently a malloc failure here can panic */
-       if (!tty->read_buf) {
-               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-               if (!tty->read_buf)
-                       return -ENOMEM;
-       }
-       if (!tty->echo_buf) {
-               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-
-               if (!tty->echo_buf)
-                       return -ENOMEM;
-       }
-       reset_buffer_flags(tty);
-       tty->column = 0;
-       n_tty_set_termios(tty, NULL);
-       tty->minimum_to_wake = 1;
-       tty->closing = 0;
-       return 0;
-}
-
-static inline int input_available_p(struct tty_struct *tty, int amt)
-{
-       tty_flush_to_ldisc(tty);
-       if (tty->icanon && !L_EXTPROC(tty)) {
-               if (tty->canon_data)
-                       return 1;
-       } else if (tty->read_cnt >= (amt ? amt : 1))
-               return 1;
-
-       return 0;
-}
-
-/**
- *     copy_from_read_buf      -       copy read data directly
- *     @tty: terminal device
- *     @b: user data
- *     @nr: size of data
- *
- *     Helper function to speed up n_tty_read.  It is only called when
- *     ICANON is off; it copies characters straight from the tty queue to
- *     user space directly.  It can be profitably called twice; once to
- *     drain the space from the tail pointer to the (physical) end of the
- *     buffer, and once to drain the space from the (physical) beginning of
- *     the buffer to head pointer.
- *
- *     Called under the tty->atomic_read_lock sem
- *
- */
-
-static int copy_from_read_buf(struct tty_struct *tty,
-                                     unsigned char __user **b,
-                                     size_t *nr)
-
-{
-       int retval;
-       size_t n;
-       unsigned long flags;
-
-       retval = 0;
-       spin_lock_irqsave(&tty->read_lock, flags);
-       n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
-       n = min(*nr, n);
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-       if (n) {
-               retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
-               n -= retval;
-               tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
-               spin_lock_irqsave(&tty->read_lock, flags);
-               tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt -= n;
-               /* Turn single EOF into zero-length read */
-               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-                               n--;
-               }
-               spin_unlock_irqrestore(&tty->read_lock, flags);
-               *b += n;
-               *nr -= n;
-       }
-       return retval;
-}
-
-extern ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-
-/**
- *     job_control             -       check job control
- *     @tty: tty
- *     @file: file handle
- *
- *     Perform job control management checks on this file/tty descriptor
- *     and if appropriate send any needed signals and return a negative
- *     error code if action should be taken.
- *
- *     FIXME:
- *     Locking: None - redirected write test is safe, testing
- *     current->signal should possibly lock current->sighand
- *     pgrp locking ?
- */
-
-static int job_control(struct tty_struct *tty, struct file *file)
-{
-       /* Job control check -- must be done at start and after
-          every sleep (POSIX.1 7.1.1.4). */
-       /* NOTE: not yet done after every sleep pending a thorough
-          check of the logic of this change. -- jlc */
-       /* don't stop on /dev/console */
-       if (file->f_op->write != redirected_tty_write &&
-           current->signal->tty == tty) {
-               if (!tty->pgrp)
-                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
-               else if (task_pgrp(current) != tty->pgrp) {
-                       if (is_ignored(SIGTTIN) ||
-                           is_current_pgrp_orphaned())
-                               return -EIO;
-                       kill_pgrp(task_pgrp(current), SIGTTIN, 1);
-                       set_thread_flag(TIF_SIGPENDING);
-                       return -ERESTARTSYS;
-               }
-       }
-       return 0;
-}
-
-
-/**
- *     n_tty_read              -       read function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Perform reads for the line discipline. We are guaranteed that the
- *     line discipline will not be closed under us but we may get multiple
- *     parallel readers and must handle this ourselves. We may also get
- *     a hangup. Always called in user context, may sleep.
- *
- *     This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
-                        unsigned char __user *buf, size_t nr)
-{
-       unsigned char __user *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       int minimum, time;
-       ssize_t retval = 0;
-       ssize_t size;
-       long timeout;
-       unsigned long flags;
-       int packet;
-
-do_it_again:
-
-       BUG_ON(!tty->read_buf);
-
-       c = job_control(tty, file);
-       if (c < 0)
-               return c;
-
-       minimum = time = 0;
-       timeout = MAX_SCHEDULE_TIMEOUT;
-       if (!tty->icanon) {
-               time = (HZ / 10) * TIME_CHAR(tty);
-               minimum = MIN_CHAR(tty);
-               if (minimum) {
-                       if (time)
-                               tty->minimum_to_wake = 1;
-                       else if (!waitqueue_active(&tty->read_wait) ||
-                                (tty->minimum_to_wake > minimum))
-                               tty->minimum_to_wake = minimum;
-               } else {
-                       timeout = 0;
-                       if (time) {
-                               timeout = time;
-                               time = 0;
-                       }
-                       tty->minimum_to_wake = minimum = 1;
-               }
-       }
-
-       /*
-        *      Internal serialization of reads.
-        */
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&tty->atomic_read_lock))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&tty->atomic_read_lock))
-                       return -ERESTARTSYS;
-       }
-       packet = tty->packet;
-
-       add_wait_queue(&tty->read_wait, &wait);
-       while (nr) {
-               /* First test for status change. */
-               if (packet && tty->link->ctrl_status) {
-                       unsigned char cs;
-                       if (b != buf)
-                               break;
-                       spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-                       cs = tty->link->ctrl_status;
-                       tty->link->ctrl_status = 0;
-                       spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-                       if (tty_put_user(tty, cs, b++)) {
-                               retval = -EFAULT;
-                               b--;
-                               break;
-                       }
-                       nr--;
-                       break;
-               }
-               /* This statement must be first before checking for input
-                  so that any interrupt will set the state back to
-                  TASK_RUNNING. */
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
-                   ((minimum - (b - buf)) >= 1))
-                       tty->minimum_to_wake = (minimum - (b - buf));
-
-               if (!input_available_p(tty, 0)) {
-                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       /* FIXME: does n_tty_set_room need locking ? */
-                       n_tty_set_room(tty);
-                       timeout = schedule_timeout(timeout);
-                       continue;
-               }
-               __set_current_state(TASK_RUNNING);
-
-               /* Deal with packet mode. */
-               if (packet && b == buf) {
-                       if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
-                               retval = -EFAULT;
-                               b--;
-                               break;
-                       }
-                       nr--;
-               }
-
-               if (tty->icanon && !L_EXTPROC(tty)) {
-                       /* N.B. avoid overrun if nr == 0 */
-                       while (nr && tty->read_cnt) {
-                               int eol;
-
-                               eol = test_and_clear_bit(tty->read_tail,
-                                               tty->read_flags);
-                               c = tty->read_buf[tty->read_tail];
-                               spin_lock_irqsave(&tty->read_lock, flags);
-                               tty->read_tail = ((tty->read_tail+1) &
-                                                 (N_TTY_BUF_SIZE-1));
-                               tty->read_cnt--;
-                               if (eol) {
-                                       /* this test should be redundant:
-                                        * we shouldn't be reading data if
-                                        * canon_data is 0
-                                        */
-                                       if (--tty->canon_data < 0)
-                                               tty->canon_data = 0;
-                               }
-                               spin_unlock_irqrestore(&tty->read_lock, flags);
-
-                               if (!eol || (c != __DISABLED_CHAR)) {
-                                       if (tty_put_user(tty, c, b++)) {
-                                               retval = -EFAULT;
-                                               b--;
-                                               break;
-                                       }
-                                       nr--;
-                               }
-                               if (eol) {
-                                       tty_audit_push(tty);
-                                       break;
-                               }
-                       }
-                       if (retval)
-                               break;
-               } else {
-                       int uncopied;
-                       /* The copy function takes the read lock and handles
-                          locking internally for this case */
-                       uncopied = copy_from_read_buf(tty, &b, &nr);
-                       uncopied += copy_from_read_buf(tty, &b, &nr);
-                       if (uncopied) {
-                               retval = -EFAULT;
-                               break;
-                       }
-               }
-
-               /* If there is enough space in the read buffer now, let the
-                * low-level driver know. We use n_tty_chars_in_buffer() to
-                * check the buffer, as it now knows about canonical mode.
-                * Otherwise, if the driver is throttled and the line is
-                * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
-                * we won't get any more characters.
-                */
-               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
-                       n_tty_set_room(tty);
-                       check_unthrottle(tty);
-               }
-
-               if (b - buf >= minimum)
-                       break;
-               if (time)
-                       timeout = time;
-       }
-       mutex_unlock(&tty->atomic_read_lock);
-       remove_wait_queue(&tty->read_wait, &wait);
-
-       if (!waitqueue_active(&tty->read_wait))
-               tty->minimum_to_wake = minimum;
-
-       __set_current_state(TASK_RUNNING);
-       size = b - buf;
-       if (size) {
-               retval = size;
-               if (nr)
-                       clear_bit(TTY_PUSH, &tty->flags);
-       } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-                goto do_it_again;
-
-       n_tty_set_room(tty);
-       return retval;
-}
-
-/**
- *     n_tty_write             -       write function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Write function of the terminal device.  This is serialized with
- *     respect to other write callers but not to termios changes, reads
- *     and other such events.  Since the receive code will echo characters,
- *     thus calling driver write methods, the output_lock is used in
- *     the output processing functions called here as well as in the
- *     echo processing function to protect the column state and space
- *     left in the buffer.
- *
- *     This code must be sure never to sleep through a hangup.
- *
- *     Locking: output_lock to protect column state and space left
- *              (note that the process_output*() functions take this
- *               lock themselves)
- */
-
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *buf, size_t nr)
-{
-       const unsigned char *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       ssize_t retval = 0;
-
-       /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-       }
-
-       /* Write out any echoed characters that are still pending */
-       process_echoes(tty);
-
-       add_wait_queue(&tty->write_wait, &wait);
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
-                       retval = -EIO;
-                       break;
-               }
-               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-                       while (nr > 0) {
-                               ssize_t num = process_output_block(tty, b, nr);
-                               if (num < 0) {
-                                       if (num == -EAGAIN)
-                                               break;
-                                       retval = num;
-                                       goto break_out;
-                               }
-                               b += num;
-                               nr -= num;
-                               if (nr == 0)
-                                       break;
-                               c = *b;
-                               if (process_output(c, tty) < 0)
-                                       break;
-                               b++; nr--;
-                       }
-                       if (tty->ops->flush_chars)
-                               tty->ops->flush_chars(tty);
-               } else {
-                       while (nr > 0) {
-                               c = tty->ops->write(tty, b, nr);
-                               if (c < 0) {
-                                       retval = c;
-                                       goto break_out;
-                               }
-                               if (!c)
-                                       break;
-                               b += c;
-                               nr -= c;
-                       }
-               }
-               if (!nr)
-                       break;
-               if (file->f_flags & O_NONBLOCK) {
-                       retval = -EAGAIN;
-                       break;
-               }
-               schedule();
-       }
-break_out:
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-       if (b - buf != nr && tty->fasync)
-               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       return (b - buf) ? b - buf : retval;
-}
-
-/**
- *     n_tty_poll              -       poll method for N_TTY
- *     @tty: terminal device
- *     @file: file accessing it
- *     @wait: poll table
- *
- *     Called when the line discipline is asked to poll() for data or
- *     for special events. This code is not serialized with respect to
- *     other events save open/close.
- *
- *     This code must be sure never to sleep through a hangup.
- *     Called without the kernel lock held - fine
- */
-
-static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
-                                                       poll_table *wait)
-{
-       unsigned int mask = 0;
-
-       poll_wait(file, &tty->read_wait, wait);
-       poll_wait(file, &tty->write_wait, wait);
-       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
-               mask |= POLLIN | POLLRDNORM;
-       if (tty->packet && tty->link->ctrl_status)
-               mask |= POLLPRI | POLLIN | POLLRDNORM;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               mask |= POLLHUP;
-       if (tty_hung_up_p(file))
-               mask |= POLLHUP;
-       if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
-               if (MIN_CHAR(tty) && !TIME_CHAR(tty))
-                       tty->minimum_to_wake = MIN_CHAR(tty);
-               else
-                       tty->minimum_to_wake = 1;
-       }
-       if (tty->ops->write && !tty_is_writelocked(tty) &&
-                       tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
-                       tty_write_room(tty) > 0)
-               mask |= POLLOUT | POLLWRNORM;
-       return mask;
-}
-
-static unsigned long inq_canon(struct tty_struct *tty)
-{
-       int nr, head, tail;
-
-       if (!tty->canon_data)
-               return 0;
-       head = tty->canon_head;
-       tail = tty->read_tail;
-       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-       /* Skip EOF-chars.. */
-       while (head != tail) {
-               if (test_bit(tail, tty->read_flags) &&
-                   tty->read_buf[tail] == __DISABLED_CHAR)
-                       nr--;
-               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-       }
-       return nr;
-}
-
-static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       int retval;
-
-       switch (cmd) {
-       case TIOCOUTQ:
-               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-       case TIOCINQ:
-               /* FIXME: Locking */
-               retval = tty->read_cnt;
-               if (L_ICANON(tty))
-                       retval = inq_canon(tty);
-               return put_user(retval, (unsigned int __user *) arg);
-       default:
-               return n_tty_ioctl_helper(tty, file, cmd, arg);
-       }
-}
-
-struct tty_ldisc_ops tty_ldisc_N_TTY = {
-       .magic           = TTY_LDISC_MAGIC,
-       .name            = "n_tty",
-       .open            = n_tty_open,
-       .close           = n_tty_close,
-       .flush_buffer    = n_tty_flush_buffer,
-       .chars_in_buffer = n_tty_chars_in_buffer,
-       .read            = n_tty_read,
-       .write           = n_tty_write,
-       .ioctl           = n_tty_ioctl,
-       .set_termios     = n_tty_set_termios,
-       .poll            = n_tty_poll,
-       .receive_buf     = n_tty_receive_buf,
-       .write_wakeup    = n_tty_write_wakeup
-};
-
-/**
- *     n_tty_inherit_ops       -       inherit N_TTY methods
- *     @ops: struct tty_ldisc_ops where to save N_TTY methods
- *
- *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
- *     methods.
- */
-
-void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
-{
-       *ops = tty_ldisc_N_TTY;
-       ops->owner = NULL;
-       ops->refcount = ops->flags = 0;
-}
-EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
index dd3f9b1f11b4f59685853873977b3913daf3b0a2..294d03e8c61a6a249b6008878efd08386c86d0a9 100644 (file)
@@ -1828,7 +1828,6 @@ static int ntty_ioctl(struct tty_struct *tty, struct file *file,
                      unsigned int cmd, unsigned long arg)
 {
        struct port *port = tty->driver_data;
-       void __user *argp = (void __user *)arg;
        int rval = -ENOIOCTLCMD;
 
        DBG1("******** IOCTL, cmd: %d", cmd);
index d962f25dcc2a730b912c139f7b7ae5f7c408ce8d..777181a2e603592361b32bfea492429b506b64e6 100644 (file)
@@ -979,8 +979,9 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
                if (dev->flags0 & 1) {
                        set_bit(IS_CMM_ABSENT, &dev->flags);
                        rc = -ENODEV;
+               } else {
+                       rc = -EIO;
                }
-               rc = -EIO;
                goto release_io;
        }
 
index bfc10f89d9511d8f26367329c5b7658e8a6b526c..eaa41992fbe234a17bd1d102e05fd39229e0ac5d 100644 (file)
@@ -2796,6 +2796,7 @@ static const struct tty_operations mgslpc_ops = {
        .hangup = mgslpc_hangup,
        .tiocmget = tiocmget,
        .tiocmset = tiocmset,
+       .get_icount = mgslpc_get_icount,
        .proc_fops = &mgslpc_proc_fops,
 };
 
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
deleted file mode 100644 (file)
index 923a485..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
- *  linux/drivers/char/pty.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  Added support for a Unix98-style ptmx device.
- *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- *  When reading this code see also fs/devpts. In particular note that the
- *  driver_data field is used by the devpts side as a binding to the devpts
- *  inode.
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/sysctl.h>
-#include <linux/device.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/devpts_fs.h>
-#include <linux/slab.h>
-
-#include <asm/system.h>
-
-#ifdef CONFIG_UNIX98_PTYS
-static struct tty_driver *ptm_driver;
-static struct tty_driver *pts_driver;
-#endif
-
-static void pty_close(struct tty_struct *tty, struct file *filp)
-{
-       BUG_ON(!tty);
-       if (tty->driver->subtype == PTY_TYPE_MASTER)
-               WARN_ON(tty->count > 1);
-       else {
-               if (tty->count > 2)
-                       return;
-       }
-       wake_up_interruptible(&tty->read_wait);
-       wake_up_interruptible(&tty->write_wait);
-       tty->packet = 0;
-       if (!tty->link)
-               return;
-       tty->link->packet = 0;
-       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       wake_up_interruptible(&tty->link->read_wait);
-       wake_up_interruptible(&tty->link->write_wait);
-       if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               set_bit(TTY_OTHER_CLOSED, &tty->flags);
-#ifdef CONFIG_UNIX98_PTYS
-               if (tty->driver == ptm_driver)
-                       devpts_pty_kill(tty->link);
-#endif
-               tty_unlock();
-               tty_vhangup(tty->link);
-               tty_lock();
-       }
-}
-
-/*
- * The unthrottle routine is called by the line discipline to signal
- * that it can receive more characters.  For PTY's, the TTY_THROTTLED
- * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
- * characters in the queue.  This is necessary since each time this
- * happens, we need to wake up any sleeping processes that could be
- * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
- * for the pty buffer to be drained.
- */
-static void pty_unthrottle(struct tty_struct *tty)
-{
-       tty_wakeup(tty->link);
-       set_bit(TTY_THROTTLED, &tty->flags);
-}
-
-/**
- *     pty_space       -       report space left for writing
- *     @to: tty we are writing into
- *
- *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
- *     allows a lot of overspill room for echo and other fun messes to
- *     be handled properly
- */
-
-static int pty_space(struct tty_struct *to)
-{
-       int n = 8192 - to->buf.memory_used;
-       if (n < 0)
-               return 0;
-       return n;
-}
-
-/**
- *     pty_write               -       write to a pty
- *     @tty: the tty we write from
- *     @buf: kernel buffer of data
- *     @count: bytes to write
- *
- *     Our "hardware" write method. Data is coming from the ldisc which
- *     may be in a non sleeping state. We simply throw this at the other
- *     end of the link as if we were an IRQ handler receiving stuff for
- *     the other side of the pty/tty pair.
- */
-
-static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
-{
-       struct tty_struct *to = tty->link;
-
-       if (tty->stopped)
-               return 0;
-
-       if (c > 0) {
-               /* Stuff the data into the input queue of the other end */
-               c = tty_insert_flip_string(to, buf, c);
-               /* And shovel */
-               if (c) {
-                       tty_flip_buffer_push(to);
-                       tty_wakeup(tty);
-               }
-       }
-       return c;
-}
-
-/**
- *     pty_write_room  -       write space
- *     @tty: tty we are writing from
- *
- *     Report how many bytes the ldisc can send into the queue for
- *     the other device.
- */
-
-static int pty_write_room(struct tty_struct *tty)
-{
-       if (tty->stopped)
-               return 0;
-       return pty_space(tty->link);
-}
-
-/**
- *     pty_chars_in_buffer     -       characters currently in our tx queue
- *     @tty: our tty
- *
- *     Report how much we have in the transmit queue. As everything is
- *     instantly at the other end this is easy to implement.
- */
-
-static int pty_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;
-}
-
-/* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user *arg)
-{
-       int val;
-       if (get_user(val, arg))
-               return -EFAULT;
-       if (val)
-               set_bit(TTY_PTY_LOCK, &tty->flags);
-       else
-               clear_bit(TTY_PTY_LOCK, &tty->flags);
-       return 0;
-}
-
-/* Send a signal to the slave */
-static int pty_signal(struct tty_struct *tty, int sig)
-{
-       unsigned long flags;
-       struct pid *pgrp;
-
-       if (tty->link) {
-               spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-               pgrp = get_pid(tty->link->pgrp);
-               spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-
-               kill_pgrp(pgrp, sig, 1);
-               put_pid(pgrp);
-       }
-       return 0;
-}
-
-static void pty_flush_buffer(struct tty_struct *tty)
-{
-       struct tty_struct *to = tty->link;
-       unsigned long flags;
-
-       if (!to)
-               return;
-       /* tty_buffer_flush(to); FIXME */
-       if (to->packet) {
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
-               wake_up_interruptible(&to->read_wait);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       }
-}
-
-static int pty_open(struct tty_struct *tty, struct file *filp)
-{
-       int     retval = -ENODEV;
-
-       if (!tty || !tty->link)
-               goto out;
-
-       retval = -EIO;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               goto out;
-       if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
-               goto out;
-       if (tty->link->count != 1)
-               goto out;
-
-       clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       set_bit(TTY_THROTTLED, &tty->flags);
-       retval = 0;
-out:
-       return retval;
-}
-
-static void pty_set_termios(struct tty_struct *tty,
-                                       struct ktermios *old_termios)
-{
-       tty->termios->c_cflag &= ~(CSIZE | PARENB);
-       tty->termios->c_cflag |= (CS8 | CREAD);
-}
-
-/**
- *     pty_do_resize           -       resize event
- *     @tty: tty being resized
- *     @ws: window size being set.
- *
- *     Update the termios variables and send the necessary signals to
- *     peform a terminal resize correctly
- */
-
-int pty_resize(struct tty_struct *tty,  struct winsize *ws)
-{
-       struct pid *pgrp, *rpgrp;
-       unsigned long flags;
-       struct tty_struct *pty = tty->link;
-
-       /* For a PTY we need to lock the tty side */
-       mutex_lock(&tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-               goto done;
-
-       /* Get the PID values and reference them so we can
-          avoid holding the tty ctrl lock while sending signals.
-          We need to lock these individually however. */
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       spin_lock_irqsave(&pty->ctrl_lock, flags);
-       rpgrp = get_pid(pty->pgrp);
-       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
-
-       if (pgrp)
-               kill_pgrp(pgrp, SIGWINCH, 1);
-       if (rpgrp != pgrp && rpgrp)
-               kill_pgrp(rpgrp, SIGWINCH, 1);
-
-       put_pid(pgrp);
-       put_pid(rpgrp);
-
-       tty->winsize = *ws;
-       pty->winsize = *ws;     /* Never used so will go away soon */
-done:
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-       int retval;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               free_tty_struct(o_tty);
-               return -ENOMEM;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       /* We always use new tty termios data so we can do this
-          the easy way .. */
-       retval = tty_init_termios(tty);
-       if (retval)
-               goto free_mem_out;
-
-       retval = tty_init_termios(o_tty);
-       if (retval) {
-               tty_free_termios(tty);
-               goto free_mem_out;
-       }
-
-       /*
-        * Everything allocated ... set up the o_tty structure.
-        */
-       driver->other->ttys[idx] = o_tty;
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-
-       tty_driver_kref_get(driver);
-       tty->count++;
-       driver->ttys[idx] = tty;
-       return 0;
-free_mem_out:
-       module_put(o_tty->driver->owner);
-       free_tty_struct(o_tty);
-       return -ENOMEM;
-}
-
-static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-               return pty_set_lock(tty, (int __user *) arg);
-       case TIOCSIG:    /* Send signal to other side of pty */
-               return pty_signal(tty, (int) arg);
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
-module_param(legacy_count, int, 0);
-
-/*
- * The master side of a pty can do TIOCSPTLCK and thus
- * has pty_bsd_ioctl.
- */
-static const struct tty_operations master_pty_ops_bsd = {
-       .install = pty_install,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .ioctl = pty_bsd_ioctl,
-       .resize = pty_resize
-};
-
-static const struct tty_operations slave_pty_ops_bsd = {
-       .install = pty_install,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .resize = pty_resize
-};
-
-static void __init legacy_pty_init(void)
-{
-       struct tty_driver *pty_driver, *pty_slave_driver;
-
-       if (legacy_count <= 0)
-               return;
-
-       pty_driver = alloc_tty_driver(legacy_count);
-       if (!pty_driver)
-               panic("Couldn't allocate pty driver");
-
-       pty_slave_driver = alloc_tty_driver(legacy_count);
-       if (!pty_slave_driver)
-               panic("Couldn't allocate pty slave driver");
-
-       pty_driver->owner = THIS_MODULE;
-       pty_driver->driver_name = "pty_master";
-       pty_driver->name = "pty";
-       pty_driver->major = PTY_MASTER_MAJOR;
-       pty_driver->minor_start = 0;
-       pty_driver->type = TTY_DRIVER_TYPE_PTY;
-       pty_driver->subtype = PTY_TYPE_MASTER;
-       pty_driver->init_termios = tty_std_termios;
-       pty_driver->init_termios.c_iflag = 0;
-       pty_driver->init_termios.c_oflag = 0;
-       pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pty_driver->init_termios.c_lflag = 0;
-       pty_driver->init_termios.c_ispeed = 38400;
-       pty_driver->init_termios.c_ospeed = 38400;
-       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
-       pty_driver->other = pty_slave_driver;
-       tty_set_operations(pty_driver, &master_pty_ops_bsd);
-
-       pty_slave_driver->owner = THIS_MODULE;
-       pty_slave_driver->driver_name = "pty_slave";
-       pty_slave_driver->name = "ttyp";
-       pty_slave_driver->major = PTY_SLAVE_MAJOR;
-       pty_slave_driver->minor_start = 0;
-       pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
-       pty_slave_driver->subtype = PTY_TYPE_SLAVE;
-       pty_slave_driver->init_termios = tty_std_termios;
-       pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pty_slave_driver->init_termios.c_ispeed = 38400;
-       pty_slave_driver->init_termios.c_ospeed = 38400;
-       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-                                       TTY_DRIVER_REAL_RAW;
-       pty_slave_driver->other = pty_driver;
-       tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
-
-       if (tty_register_driver(pty_driver))
-               panic("Couldn't register pty driver");
-       if (tty_register_driver(pty_slave_driver))
-               panic("Couldn't register pty slave driver");
-}
-#else
-static inline void legacy_pty_init(void) { }
-#endif
-
-/* Unix98 devices */
-#ifdef CONFIG_UNIX98_PTYS
-/*
- * sysctl support for setting limits on the number of Unix98 ptys allocated.
- * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
- */
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count;
-
-static struct cdev ptmx_cdev;
-
-static struct ctl_table pty_table[] = {
-       {
-               .procname       = "max",
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .data           = &pty_limit,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &pty_limit_min,
-               .extra2         = &pty_limit_max,
-       }, {
-               .procname       = "nr",
-               .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .data           = &pty_count,
-               .proc_handler   = proc_dointvec,
-       }, 
-       {}
-};
-
-static struct ctl_table pty_kern_table[] = {
-       {
-               .procname       = "pty",
-               .mode           = 0555,
-               .child          = pty_table,
-       },
-       {}
-};
-
-static struct ctl_table pty_root_table[] = {
-       {
-               .procname       = "kernel",
-               .mode           = 0555,
-               .child          = pty_kern_table,
-       },
-       {}
-};
-
-
-static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-               return pty_set_lock(tty, (int __user *)arg);
-       case TIOCGPTN: /* Get PT Number */
-               return put_user(tty->index, (unsigned int __user *)arg);
-       case TIOCSIG:    /* Send signal to other side of pty */
-               return pty_signal(tty, (int) arg);
-       }
-
-       return -ENOIOCTLCMD;
-}
-
-/**
- *     ptm_unix98_lookup       -       find a pty master
- *     @driver: ptm driver
- *     @idx: tty index
- *
- *     Look up a pty master device. Called under the tty_mutex for now.
- *     This provides our locking.
- */
-
-static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
-               struct inode *ptm_inode, int idx)
-{
-       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
-       if (tty)
-               tty = tty->link;
-       return tty;
-}
-
-/**
- *     pts_unix98_lookup       -       find a pty slave
- *     @driver: pts driver
- *     @idx: tty index
- *
- *     Look up a pty master device. Called under the tty_mutex for now.
- *     This provides our locking.
- */
-
-static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
-               struct inode *pts_inode, int idx)
-{
-       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
-       /* Master must be open before slave */
-       if (!tty)
-               return ERR_PTR(-EIO);
-       return tty;
-}
-
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
-       /* We have our own method as we don't use the tty index */
-       kfree(tty->termios);
-}
-
-/* We have no need to install and remove our tty objects as devpts does all
-   the work for us */
-
-static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               free_tty_struct(o_tty);
-               return -ENOMEM;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (tty->termios == NULL)
-               goto free_mem_out;
-       *tty->termios = driver->init_termios;
-       tty->termios_locked = tty->termios + 1;
-
-       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (o_tty->termios == NULL)
-               goto free_mem_out;
-       *o_tty->termios = driver->other->init_termios;
-       o_tty->termios_locked = o_tty->termios + 1;
-
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-       /*
-        * All structures have been allocated, so now we install them.
-        * Failures after this point use release_tty to clean up, so
-        * there's no need to null out the local pointers.
-        */
-       tty_driver_kref_get(driver);
-       tty->count++;
-       pty_count++;
-       return 0;
-free_mem_out:
-       kfree(o_tty->termios);
-       module_put(o_tty->driver->owner);
-       free_tty_struct(o_tty);
-       kfree(tty->termios);
-       return -ENOMEM;
-}
-
-static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
-       pty_count--;
-}
-
-static const struct tty_operations ptm_unix98_ops = {
-       .lookup = ptm_unix98_lookup,
-       .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .ioctl = pty_unix98_ioctl,
-       .shutdown = pty_unix98_shutdown,
-       .resize = pty_resize
-};
-
-static const struct tty_operations pty_unix98_ops = {
-       .lookup = pts_unix98_lookup,
-       .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .shutdown = pty_unix98_shutdown
-};
-
-/**
- *     ptmx_open               -       open a unix 98 pty master
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     Allocate a unix98 pty master device from the ptmx driver.
- *
- *     Locking: tty_mutex protects the init_dev work. tty->count should
- *             protect the rest.
- *             allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty;
-       int retval;
-       int index;
-
-       nonseekable_open(inode, filp);
-
-       /* find a device that is not in use. */
-       tty_lock();
-       index = devpts_new_index(inode);
-       tty_unlock();
-       if (index < 0)
-               return index;
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-       tty = tty_init_dev(ptm_driver, index, 1);
-       mutex_unlock(&tty_mutex);
-
-       if (IS_ERR(tty)) {
-               retval = PTR_ERR(tty);
-               goto out;
-       }
-
-       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-
-       retval = tty_add_file(tty, filp);
-       if (retval)
-               goto out;
-
-       retval = devpts_pty_new(inode, tty->link);
-       if (retval)
-               goto out1;
-
-       retval = ptm_driver->ops->open(tty, filp);
-       if (retval)
-               goto out2;
-out1:
-       tty_unlock();
-       return retval;
-out2:
-       tty_unlock();
-       tty_release(inode, filp);
-       return retval;
-out:
-       devpts_kill_index(inode, index);
-       tty_unlock();
-       return retval;
-}
-
-static struct file_operations ptmx_fops;
-
-static void __init unix98_pty_init(void)
-{
-       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!ptm_driver)
-               panic("Couldn't allocate Unix98 ptm driver");
-       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!pts_driver)
-               panic("Couldn't allocate Unix98 pts driver");
-
-       ptm_driver->owner = THIS_MODULE;
-       ptm_driver->driver_name = "pty_master";
-       ptm_driver->name = "ptm";
-       ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
-       ptm_driver->minor_start = 0;
-       ptm_driver->type = TTY_DRIVER_TYPE_PTY;
-       ptm_driver->subtype = PTY_TYPE_MASTER;
-       ptm_driver->init_termios = tty_std_termios;
-       ptm_driver->init_termios.c_iflag = 0;
-       ptm_driver->init_termios.c_oflag = 0;
-       ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       ptm_driver->init_termios.c_lflag = 0;
-       ptm_driver->init_termios.c_ispeed = 38400;
-       ptm_driver->init_termios.c_ospeed = 38400;
-       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-       ptm_driver->other = pts_driver;
-       tty_set_operations(ptm_driver, &ptm_unix98_ops);
-
-       pts_driver->owner = THIS_MODULE;
-       pts_driver->driver_name = "pty_slave";
-       pts_driver->name = "pts";
-       pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
-       pts_driver->minor_start = 0;
-       pts_driver->type = TTY_DRIVER_TYPE_PTY;
-       pts_driver->subtype = PTY_TYPE_SLAVE;
-       pts_driver->init_termios = tty_std_termios;
-       pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pts_driver->init_termios.c_ispeed = 38400;
-       pts_driver->init_termios.c_ospeed = 38400;
-       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-       pts_driver->other = ptm_driver;
-       tty_set_operations(pts_driver, &pty_unix98_ops);
-
-       if (tty_register_driver(ptm_driver))
-               panic("Couldn't register Unix98 ptm driver");
-       if (tty_register_driver(pts_driver))
-               panic("Couldn't register Unix98 pts driver");
-
-       register_sysctl_table(pty_root_table);
-
-       /* Now create the /dev/ptmx special device */
-       tty_default_fops(&ptmx_fops);
-       ptmx_fops.open = ptmx_open;
-
-       cdev_init(&ptmx_cdev, &ptmx_fops);
-       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
-               panic("Couldn't register /dev/ptmx driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-}
-
-#else
-static inline void unix98_pty_init(void) { }
-#endif
-
-static int __init pty_init(void)
-{
-       legacy_pty_init();
-       unix98_pty_init();
-       return 0;
-}
-module_init(pty_init);
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
deleted file mode 100644 (file)
index ebae344..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * linux/drivers/char/selection.c
- *
- * This module exports the functions:
- *
- *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
- *     'void clear_selection(void)'
- *     'int paste_selection(struct tty_struct *)'
- *     'int sel_loadlut(char __user *)'
- *
- * Now that /dev/vcs exists, most of this can disappear again.
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/tiocl.h>
-#include <linux/console.h>
-#include <linux/smp_lock.h>
-
-/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
-#define isspace(c)     ((c) == ' ')
-
-extern void poke_blanked_console(void);
-
-/* Variables for selection control. */
-/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons;              /* must not be deallocated */
-static int use_unicode;
-static volatile int sel_start = -1;    /* cleared by clear_selection */
-static int sel_end;
-static int sel_buffer_lth;
-static char *sel_buffer;
-
-/* clear_selection, highlight and highlight_pointer can be called
-   from interrupt (via scrollback/front) */
-
-/* set reverse video on characters s-e of console with selection. */
-static inline void highlight(const int s, const int e)
-{
-       invert_screen(sel_cons, s, e-s+2, 1);
-}
-
-/* use complementary color to show the pointer */
-static inline void highlight_pointer(const int where)
-{
-       complement_pos(sel_cons, where);
-}
-
-static u16
-sel_pos(int n)
-{
-       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
-                               use_unicode);
-}
-
-/* remove the current selection highlight, if any,
-   from the console holding the selection. */
-void
-clear_selection(void) {
-       highlight_pointer(-1); /* hide the pointer */
-       if (sel_start != -1) {
-               highlight(sel_start, sel_end);
-               sel_start = -1;
-       }
-}
-
-/*
- * User settable table: what characters are to be considered alphabetic?
- * 256 bits
- */
-static u32 inwordLut[8]={
-  0x00000000, /* control chars     */
-  0x03FF0000, /* digits            */
-  0x87FFFFFE, /* uppercase and '_' */
-  0x07FFFFFE, /* lowercase         */
-  0x00000000,
-  0x00000000,
-  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
-  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
-};
-
-static inline int inword(const u16 c) {
-       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
-}
-
-/* set inwordLut contents. Invoked by ioctl(). */
-int sel_loadlut(char __user *p)
-{
-       return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
-}
-
-/* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p, int size_row)
-{
-       return (!(p % size_row) || !((p + 2) % size_row));
-}
-
-/* constrain v such that v <= u */
-static inline unsigned short limit(const unsigned short v, const unsigned short u)
-{
-       return (v > u) ? u : v;
-}
-
-/* stores the char in UTF8 and returns the number of bytes used (1-3) */
-static int store_utf8(u16 c, char *p)
-{
-       if (c < 0x80) {
-               /*  0******* */
-               p[0] = c;
-               return 1;
-       } else if (c < 0x800) {
-               /* 110***** 10****** */
-               p[0] = 0xc0 | (c >> 6);
-               p[1] = 0x80 | (c & 0x3f);
-               return 2;
-       } else {
-               /* 1110**** 10****** 10****** */
-               p[0] = 0xe0 | (c >> 12);
-               p[1] = 0x80 | ((c >> 6) & 0x3f);
-               p[2] = 0x80 | (c & 0x3f);
-               return 3;
-       }
-}
-
-/* set the current selection. Invoked by ioctl() or by kernel code. */
-int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       int sel_mode, new_sel_start, new_sel_end, spc;
-       char *bp, *obp;
-       int i, ps, pe, multiplier;
-       u16 c;
-       struct kbd_struct *kbd = kbd_table + fg_console;
-
-       poke_blanked_console();
-
-       { unsigned short xs, ys, xe, ye;
-
-         if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
-               return -EFAULT;
-         __get_user(xs, &sel->xs);
-         __get_user(ys, &sel->ys);
-         __get_user(xe, &sel->xe);
-         __get_user(ye, &sel->ye);
-         __get_user(sel_mode, &sel->sel_mode);
-         xs--; ys--; xe--; ye--;
-         xs = limit(xs, vc->vc_cols - 1);
-         ys = limit(ys, vc->vc_rows - 1);
-         xe = limit(xe, vc->vc_cols - 1);
-         ye = limit(ye, vc->vc_rows - 1);
-         ps = ys * vc->vc_size_row + (xs << 1);
-         pe = ye * vc->vc_size_row + (xe << 1);
-
-         if (sel_mode == TIOCL_SELCLEAR) {
-             /* useful for screendump without selection highlights */
-             clear_selection();
-             return 0;
-         }
-
-         if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
-             mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
-             return 0;
-         }
-        }
-
-       if (ps > pe)    /* make sel_start <= sel_end */
-       {
-               int tmp = ps;
-               ps = pe;
-               pe = tmp;
-       }
-
-       if (sel_cons != vc_cons[fg_console].d) {
-               clear_selection();
-               sel_cons = vc_cons[fg_console].d;
-       }
-       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
-
-       switch (sel_mode)
-       {
-               case TIOCL_SELCHAR:     /* character-by-character selection */
-                       new_sel_start = ps;
-                       new_sel_end = pe;
-                       break;
-               case TIOCL_SELWORD:     /* word-by-word selection */
-                       spc = isspace(sel_pos(ps));
-                       for (new_sel_start = ps; ; ps -= 2)
-                       {
-                               if ((spc && !isspace(sel_pos(ps))) ||
-                                   (!spc && !inword(sel_pos(ps))))
-                                       break;
-                               new_sel_start = ps;
-                               if (!(ps % vc->vc_size_row))
-                                       break;
-                       }
-                       spc = isspace(sel_pos(pe));
-                       for (new_sel_end = pe; ; pe += 2)
-                       {
-                               if ((spc && !isspace(sel_pos(pe))) ||
-                                   (!spc && !inword(sel_pos(pe))))
-                                       break;
-                               new_sel_end = pe;
-                               if (!((pe + 2) % vc->vc_size_row))
-                                       break;
-                       }
-                       break;
-               case TIOCL_SELLINE:     /* line-by-line selection */
-                       new_sel_start = ps - ps % vc->vc_size_row;
-                       new_sel_end = pe + vc->vc_size_row
-                                   - pe % vc->vc_size_row - 2;
-                       break;
-               case TIOCL_SELPOINTER:
-                       highlight_pointer(pe);
-                       return 0;
-               default:
-                       return -EINVAL;
-       }
-
-       /* remove the pointer */
-       highlight_pointer(-1);
-
-       /* select to end of line if on trailing space */
-       if (new_sel_end > new_sel_start &&
-               !atedge(new_sel_end, vc->vc_size_row) &&
-               isspace(sel_pos(new_sel_end))) {
-               for (pe = new_sel_end + 2; ; pe += 2)
-                       if (!isspace(sel_pos(pe)) ||
-                           atedge(pe, vc->vc_size_row))
-                               break;
-               if (isspace(sel_pos(pe)))
-                       new_sel_end = pe;
-       }
-       if (sel_start == -1)    /* no current selection */
-               highlight(new_sel_start, new_sel_end);
-       else if (new_sel_start == sel_start)
-       {
-               if (new_sel_end == sel_end)     /* no action required */
-                       return 0;
-               else if (new_sel_end > sel_end) /* extend to right */
-                       highlight(sel_end + 2, new_sel_end);
-               else                            /* contract from right */
-                       highlight(new_sel_end + 2, sel_end);
-       }
-       else if (new_sel_end == sel_end)
-       {
-               if (new_sel_start < sel_start)  /* extend to left */
-                       highlight(new_sel_start, sel_start - 2);
-               else                            /* contract from left */
-                       highlight(sel_start, new_sel_start - 2);
-       }
-       else    /* some other case; start selection from scratch */
-       {
-               clear_selection();
-               highlight(new_sel_start, new_sel_end);
-       }
-       sel_start = new_sel_start;
-       sel_end = new_sel_end;
-
-       /* Allocate a new buffer before freeing the old one ... */
-       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
-       bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
-       if (!bp) {
-               printk(KERN_WARNING "selection: kmalloc() failed\n");
-               clear_selection();
-               return -ENOMEM;
-       }
-       kfree(sel_buffer);
-       sel_buffer = bp;
-
-       obp = bp;
-       for (i = sel_start; i <= sel_end; i += 2) {
-               c = sel_pos(i);
-               if (use_unicode)
-                       bp += store_utf8(c, bp);
-               else
-                       *bp++ = c;
-               if (!isspace(c))
-                       obp = bp;
-               if (! ((i + 2) % vc->vc_size_row)) {
-                       /* strip trailing blanks from line and add newline,
-                          unless non-space at end of line. */
-                       if (obp != bp) {
-                               bp = obp;
-                               *bp++ = '\r';
-                       }
-                       obp = bp;
-               }
-       }
-       sel_buffer_lth = bp - sel_buffer;
-       return 0;
-}
-
-/* Insert the contents of the selection buffer into the
- * queue of the tty associated with the current console.
- * Invoked by ioctl().
- */
-int paste_selection(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-       int     pasted = 0;
-       unsigned int count;
-       struct  tty_ldisc *ld;
-       DECLARE_WAITQUEUE(wait, current);
-
-       /* always called with BTM from vt_ioctl */
-       WARN_ON(!tty_locked());
-
-       acquire_console_sem();
-       poke_blanked_console();
-       release_console_sem();
-
-       ld = tty_ldisc_ref(tty);
-       if (!ld) {
-               tty_unlock();
-               ld = tty_ldisc_ref_wait(tty);
-               tty_lock();
-       }
-
-       add_wait_queue(&vc->paste_wait, &wait);
-       while (sel_buffer && sel_buffer_lth > pasted) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (test_bit(TTY_THROTTLED, &tty->flags)) {
-                       schedule();
-                       continue;
-               }
-               count = sel_buffer_lth - pasted;
-               count = min(count, tty->receive_room);
-               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
-                                                               NULL, count);
-               pasted += count;
-       }
-       remove_wait_queue(&vc->paste_wait, &wait);
-       __set_current_state(TASK_RUNNING);
-
-       tty_ldisc_deref(ld);
-       return 0;
-}
index f646725bd567ec279541dd968e9a1653746035fe..748c3b0ecd89413f4bbe918e783bb042fcb02d1a 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/interrupt.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
index 9f8495b4fc8f5d648529d9c57950718bf11e8fd0..a7616d226a491bb0c295441f5db66c8e2cd98cc8 100644 (file)
@@ -87,7 +87,6 @@
 #include <linux/tty_flip.h>
 #include <linux/mm.h>
 #include <linux/serial.h>
-#include <linux/smp_lock.h>
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/delay.h>
index 4bef6ab83622f5e0e71ed6532a7f4cca12397a1c..461a5a0455170b63807b1945451d69c9f1abd1fd 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/stallion.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
index e53f16865397c491fa4afac65988c49b0f391ff9..a786326cea2f38163c343ff77997d2c2322c5e5b 100644 (file)
 #include <linux/eisa.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/bitops.h>
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
deleted file mode 100644 (file)
index eaa5d3e..0000000
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- *     Linux Magic System Request Key Hacks
- *
- *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
- *
- *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
- *     overhauled to use key registration
- *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
- *
- *     Copyright (c) 2010 Dmitry Torokhov
- *     Input handler conversion
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/reboot.h>
-#include <linux/sysrq.h>
-#include <linux/kbd_kern.h>
-#include <linux/proc_fs.h>
-#include <linux/nmi.h>
-#include <linux/quotaops.h>
-#include <linux/perf_event.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/suspend.h>
-#include <linux/writeback.h>
-#include <linux/buffer_head.h>         /* for fsync_bdev() */
-#include <linux/swap.h>
-#include <linux/spinlock.h>
-#include <linux/vt_kern.h>
-#include <linux/workqueue.h>
-#include <linux/hrtimer.h>
-#include <linux/oom.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-
-#include <asm/ptrace.h>
-#include <asm/irq_regs.h>
-
-/* Whether we react on sysrq keys or just ignore them */
-static int __read_mostly sysrq_enabled = 1;
-static bool __read_mostly sysrq_always_enabled;
-
-static bool sysrq_on(void)
-{
-       return sysrq_enabled || sysrq_always_enabled;
-}
-
-/*
- * A value of 1 means 'all', other nonzero values are an op mask:
- */
-static bool sysrq_on_mask(int mask)
-{
-       return sysrq_always_enabled ||
-              sysrq_enabled == 1 ||
-              (sysrq_enabled & mask);
-}
-
-static int __init sysrq_always_enabled_setup(char *str)
-{
-       sysrq_always_enabled = true;
-       pr_info("sysrq always enabled.\n");
-
-       return 1;
-}
-
-__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
-
-
-static void sysrq_handle_loglevel(int key)
-{
-       int i;
-
-       i = key - '0';
-       console_loglevel = 7;
-       printk("Loglevel set to %d\n", i);
-       console_loglevel = i;
-}
-static struct sysrq_key_op sysrq_loglevel_op = {
-       .handler        = sysrq_handle_loglevel,
-       .help_msg       = "loglevel(0-9)",
-       .action_msg     = "Changing Loglevel",
-       .enable_mask    = SYSRQ_ENABLE_LOG,
-};
-
-#ifdef CONFIG_VT
-static void sysrq_handle_SAK(int key)
-{
-       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-       schedule_work(SAK_work);
-}
-static struct sysrq_key_op sysrq_SAK_op = {
-       .handler        = sysrq_handle_SAK,
-       .help_msg       = "saK",
-       .action_msg     = "SAK",
-       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_VT
-static void sysrq_handle_unraw(int key)
-{
-       struct kbd_struct *kbd = &kbd_table[fg_console];
-
-       if (kbd)
-               kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-}
-static struct sysrq_key_op sysrq_unraw_op = {
-       .handler        = sysrq_handle_unraw,
-       .help_msg       = "unRaw",
-       .action_msg     = "Keyboard mode set to system default",
-       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
-#endif /* CONFIG_VT */
-
-static void sysrq_handle_crash(int key)
-{
-       char *killer = NULL;
-
-       panic_on_oops = 1;      /* force panic */
-       wmb();
-       *killer = 1;
-}
-static struct sysrq_key_op sysrq_crash_op = {
-       .handler        = sysrq_handle_crash,
-       .help_msg       = "Crash",
-       .action_msg     = "Trigger a crash",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_reboot(int key)
-{
-       lockdep_off();
-       local_irq_enable();
-       emergency_restart();
-}
-static struct sysrq_key_op sysrq_reboot_op = {
-       .handler        = sysrq_handle_reboot,
-       .help_msg       = "reBoot",
-       .action_msg     = "Resetting",
-       .enable_mask    = SYSRQ_ENABLE_BOOT,
-};
-
-static void sysrq_handle_sync(int key)
-{
-       emergency_sync();
-}
-static struct sysrq_key_op sysrq_sync_op = {
-       .handler        = sysrq_handle_sync,
-       .help_msg       = "Sync",
-       .action_msg     = "Emergency Sync",
-       .enable_mask    = SYSRQ_ENABLE_SYNC,
-};
-
-static void sysrq_handle_show_timers(int key)
-{
-       sysrq_timer_list_show();
-}
-
-static struct sysrq_key_op sysrq_show_timers_op = {
-       .handler        = sysrq_handle_show_timers,
-       .help_msg       = "show-all-timers(Q)",
-       .action_msg     = "Show clockevent devices & pending hrtimers (no others)",
-};
-
-static void sysrq_handle_mountro(int key)
-{
-       emergency_remount();
-}
-static struct sysrq_key_op sysrq_mountro_op = {
-       .handler        = sysrq_handle_mountro,
-       .help_msg       = "Unmount",
-       .action_msg     = "Emergency Remount R/O",
-       .enable_mask    = SYSRQ_ENABLE_REMOUNT,
-};
-
-#ifdef CONFIG_LOCKDEP
-static void sysrq_handle_showlocks(int key)
-{
-       debug_show_all_locks();
-}
-
-static struct sysrq_key_op sysrq_showlocks_op = {
-       .handler        = sysrq_handle_showlocks,
-       .help_msg       = "show-all-locks(D)",
-       .action_msg     = "Show Locks Held",
-};
-#else
-#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(show_lock);
-
-static void showacpu(void *dummy)
-{
-       unsigned long flags;
-
-       /* Idle CPUs have no interesting backtrace. */
-       if (idle_cpu(smp_processor_id()))
-               return;
-
-       spin_lock_irqsave(&show_lock, flags);
-       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-       show_stack(NULL, NULL);
-       spin_unlock_irqrestore(&show_lock, flags);
-}
-
-static void sysrq_showregs_othercpus(struct work_struct *dummy)
-{
-       smp_call_function(showacpu, NULL, 0);
-}
-
-static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
-
-static void sysrq_handle_showallcpus(int key)
-{
-       /*
-        * Fall back to the workqueue based printing if the
-        * backtrace printing did not succeed or the
-        * architecture has no support for it:
-        */
-       if (!trigger_all_cpu_backtrace()) {
-               struct pt_regs *regs = get_irq_regs();
-
-               if (regs) {
-                       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-                       show_regs(regs);
-               }
-               schedule_work(&sysrq_showallcpus);
-       }
-}
-
-static struct sysrq_key_op sysrq_showallcpus_op = {
-       .handler        = sysrq_handle_showallcpus,
-       .help_msg       = "show-backtrace-all-active-cpus(L)",
-       .action_msg     = "Show backtrace of all active CPUs",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-#endif
-
-static void sysrq_handle_showregs(int key)
-{
-       struct pt_regs *regs = get_irq_regs();
-       if (regs)
-               show_regs(regs);
-       perf_event_print_debug();
-}
-static struct sysrq_key_op sysrq_showregs_op = {
-       .handler        = sysrq_handle_showregs,
-       .help_msg       = "show-registers(P)",
-       .action_msg     = "Show Regs",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate(int key)
-{
-       show_state();
-}
-static struct sysrq_key_op sysrq_showstate_op = {
-       .handler        = sysrq_handle_showstate,
-       .help_msg       = "show-task-states(T)",
-       .action_msg     = "Show State",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate_blocked(int key)
-{
-       show_state_filter(TASK_UNINTERRUPTIBLE);
-}
-static struct sysrq_key_op sysrq_showstate_blocked_op = {
-       .handler        = sysrq_handle_showstate_blocked,
-       .help_msg       = "show-blocked-tasks(W)",
-       .action_msg     = "Show Blocked State",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-#ifdef CONFIG_TRACING
-#include <linux/ftrace.h>
-
-static void sysrq_ftrace_dump(int key)
-{
-       ftrace_dump(DUMP_ALL);
-}
-static struct sysrq_key_op sysrq_ftrace_dump_op = {
-       .handler        = sysrq_ftrace_dump,
-       .help_msg       = "dump-ftrace-buffer(Z)",
-       .action_msg     = "Dump ftrace buffer",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-#else
-#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-static void sysrq_handle_showmem(int key)
-{
-       show_mem();
-}
-static struct sysrq_key_op sysrq_showmem_op = {
-       .handler        = sysrq_handle_showmem,
-       .help_msg       = "show-memory-usage(M)",
-       .action_msg     = "Show Memory",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-/*
- * Signal sysrq helper function.  Sends a signal to all user processes.
- */
-static void send_sig_all(int sig)
-{
-       struct task_struct *p;
-
-       for_each_process(p) {
-               if (p->mm && !is_global_init(p))
-                       /* Not swapper, init nor kernel thread */
-                       force_sig(sig, p);
-       }
-}
-
-static void sysrq_handle_term(int key)
-{
-       send_sig_all(SIGTERM);
-       console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_term_op = {
-       .handler        = sysrq_handle_term,
-       .help_msg       = "terminate-all-tasks(E)",
-       .action_msg     = "Terminate All Tasks",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-static void moom_callback(struct work_struct *ignored)
-{
-       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
-}
-
-static DECLARE_WORK(moom_work, moom_callback);
-
-static void sysrq_handle_moom(int key)
-{
-       schedule_work(&moom_work);
-}
-static struct sysrq_key_op sysrq_moom_op = {
-       .handler        = sysrq_handle_moom,
-       .help_msg       = "memory-full-oom-kill(F)",
-       .action_msg     = "Manual OOM execution",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-#ifdef CONFIG_BLOCK
-static void sysrq_handle_thaw(int key)
-{
-       emergency_thaw_all();
-}
-static struct sysrq_key_op sysrq_thaw_op = {
-       .handler        = sysrq_handle_thaw,
-       .help_msg       = "thaw-filesystems(J)",
-       .action_msg     = "Emergency Thaw of all frozen filesystems",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-#endif
-
-static void sysrq_handle_kill(int key)
-{
-       send_sig_all(SIGKILL);
-       console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_kill_op = {
-       .handler        = sysrq_handle_kill,
-       .help_msg       = "kill-all-tasks(I)",
-       .action_msg     = "Kill All Tasks",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-static void sysrq_handle_unrt(int key)
-{
-       normalize_rt_tasks();
-}
-static struct sysrq_key_op sysrq_unrt_op = {
-       .handler        = sysrq_handle_unrt,
-       .help_msg       = "nice-all-RT-tasks(N)",
-       .action_msg     = "Nice All RT Tasks",
-       .enable_mask    = SYSRQ_ENABLE_RTNICE,
-};
-
-/* Key Operations table and lock */
-static DEFINE_SPINLOCK(sysrq_key_table_lock);
-
-static struct sysrq_key_op *sysrq_key_table[36] = {
-       &sysrq_loglevel_op,             /* 0 */
-       &sysrq_loglevel_op,             /* 1 */
-       &sysrq_loglevel_op,             /* 2 */
-       &sysrq_loglevel_op,             /* 3 */
-       &sysrq_loglevel_op,             /* 4 */
-       &sysrq_loglevel_op,             /* 5 */
-       &sysrq_loglevel_op,             /* 6 */
-       &sysrq_loglevel_op,             /* 7 */
-       &sysrq_loglevel_op,             /* 8 */
-       &sysrq_loglevel_op,             /* 9 */
-
-       /*
-        * a: Don't use for system provided sysrqs, it is handled specially on
-        * sparc and will never arrive.
-        */
-       NULL,                           /* a */
-       &sysrq_reboot_op,               /* b */
-       &sysrq_crash_op,                /* c & ibm_emac driver debug */
-       &sysrq_showlocks_op,            /* d */
-       &sysrq_term_op,                 /* e */
-       &sysrq_moom_op,                 /* f */
-       /* g: May be registered for the kernel debugger */
-       NULL,                           /* g */
-       NULL,                           /* h - reserved for help */
-       &sysrq_kill_op,                 /* i */
-#ifdef CONFIG_BLOCK
-       &sysrq_thaw_op,                 /* j */
-#else
-       NULL,                           /* j */
-#endif
-       &sysrq_SAK_op,                  /* k */
-#ifdef CONFIG_SMP
-       &sysrq_showallcpus_op,          /* l */
-#else
-       NULL,                           /* l */
-#endif
-       &sysrq_showmem_op,              /* m */
-       &sysrq_unrt_op,                 /* n */
-       /* o: This will often be registered as 'Off' at init time */
-       NULL,                           /* o */
-       &sysrq_showregs_op,             /* p */
-       &sysrq_show_timers_op,          /* q */
-       &sysrq_unraw_op,                /* r */
-       &sysrq_sync_op,                 /* s */
-       &sysrq_showstate_op,            /* t */
-       &sysrq_mountro_op,              /* u */
-       /* v: May be registered for frame buffer console restore */
-       NULL,                           /* v */
-       &sysrq_showstate_blocked_op,    /* w */
-       /* x: May be registered on ppc/powerpc for xmon */
-       NULL,                           /* x */
-       /* y: May be registered on sparc64 for global register dump */
-       NULL,                           /* y */
-       &sysrq_ftrace_dump_op,          /* z */
-};
-
-/* key2index calculation, -1 on invalid index */
-static int sysrq_key_table_key2index(int key)
-{
-       int retval;
-
-       if ((key >= '0') && (key <= '9'))
-               retval = key - '0';
-       else if ((key >= 'a') && (key <= 'z'))
-               retval = key + 10 - 'a';
-       else
-               retval = -1;
-       return retval;
-}
-
-/*
- * get and put functions for the table, exposed to modules.
- */
-struct sysrq_key_op *__sysrq_get_key_op(int key)
-{
-        struct sysrq_key_op *op_p = NULL;
-        int i;
-
-       i = sysrq_key_table_key2index(key);
-       if (i != -1)
-               op_p = sysrq_key_table[i];
-
-        return op_p;
-}
-
-static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
-{
-        int i = sysrq_key_table_key2index(key);
-
-        if (i != -1)
-                sysrq_key_table[i] = op_p;
-}
-
-void __handle_sysrq(int key, bool check_mask)
-{
-       struct sysrq_key_op *op_p;
-       int orig_log_level;
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sysrq_key_table_lock, flags);
-       /*
-        * Raise the apparent loglevel to maximum so that the sysrq header
-        * is shown to provide the user with positive feedback.  We do not
-        * simply emit this at KERN_EMERG as that would change message
-        * routing in the consumers of /proc/kmsg.
-        */
-       orig_log_level = console_loglevel;
-       console_loglevel = 7;
-       printk(KERN_INFO "SysRq : ");
-
-        op_p = __sysrq_get_key_op(key);
-        if (op_p) {
-               /*
-                * Should we check for enabled operations (/proc/sysrq-trigger
-                * should not) and is the invoked operation enabled?
-                */
-               if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
-                       printk("%s\n", op_p->action_msg);
-                       console_loglevel = orig_log_level;
-                       op_p->handler(key);
-               } else {
-                       printk("This sysrq operation is disabled.\n");
-               }
-       } else {
-               printk("HELP : ");
-               /* Only print the help msg once per handler */
-               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
-                       if (sysrq_key_table[i]) {
-                               int j;
-
-                               for (j = 0; sysrq_key_table[i] !=
-                                               sysrq_key_table[j]; j++)
-                                       ;
-                               if (j != i)
-                                       continue;
-                               printk("%s ", sysrq_key_table[i]->help_msg);
-                       }
-               }
-               printk("\n");
-               console_loglevel = orig_log_level;
-       }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-}
-
-void handle_sysrq(int key)
-{
-       if (sysrq_on())
-               __handle_sysrq(key, true);
-}
-EXPORT_SYMBOL(handle_sysrq);
-
-#ifdef CONFIG_INPUT
-
-/* Simple translation table for the SysRq keys */
-static const unsigned char sysrq_xlate[KEY_MAX + 1] =
-        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
-        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
-        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
-        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
-        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
-        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-        "\r\000/";                                      /* 0x60 - 0x6f */
-
-static bool sysrq_down;
-static int sysrq_alt_use;
-static int sysrq_alt;
-static DEFINE_SPINLOCK(sysrq_event_lock);
-
-static bool sysrq_filter(struct input_handle *handle, unsigned int type,
-                        unsigned int code, int value)
-{
-       bool suppress;
-
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&sysrq_event_lock);
-
-       if (type != EV_KEY)
-               goto out;
-
-       switch (code) {
-
-       case KEY_LEFTALT:
-       case KEY_RIGHTALT:
-               if (value)
-                       sysrq_alt = code;
-               else {
-                       if (sysrq_down && code == sysrq_alt_use)
-                               sysrq_down = false;
-
-                       sysrq_alt = 0;
-               }
-               break;
-
-       case KEY_SYSRQ:
-               if (value == 1 && sysrq_alt) {
-                       sysrq_down = true;
-                       sysrq_alt_use = sysrq_alt;
-               }
-               break;
-
-       default:
-               if (sysrq_down && value && value != 2)
-                       __handle_sysrq(sysrq_xlate[code], true);
-               break;
-       }
-
-out:
-       suppress = sysrq_down;
-       spin_unlock(&sysrq_event_lock);
-
-       return suppress;
-}
-
-static int sysrq_connect(struct input_handler *handler,
-                        struct input_dev *dev,
-                        const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       sysrq_down = false;
-       sysrq_alt = 0;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "sysrq";
-
-       error = input_register_handle(handle);
-       if (error) {
-               pr_err("Failed to register input sysrq handler, error %d\n",
-                       error);
-               goto err_free;
-       }
-
-       error = input_open_device(handle);
-       if (error) {
-               pr_err("Failed to open input device, error %d\n", error);
-               goto err_unregister;
-       }
-
-       return 0;
-
- err_unregister:
-       input_unregister_handle(handle);
- err_free:
-       kfree(handle);
-       return error;
-}
-
-static void sysrq_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-/*
- * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
- * keyboards have SysRq key predefined and so user may add it to keymap
- * later, but we expect all such keyboards to have left alt.
- */
-static const struct input_device_id sysrq_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { BIT_MASK(KEY_LEFTALT) },
-       },
-       { },
-};
-
-static struct input_handler sysrq_handler = {
-       .filter         = sysrq_filter,
-       .connect        = sysrq_connect,
-       .disconnect     = sysrq_disconnect,
-       .name           = "sysrq",
-       .id_table       = sysrq_ids,
-};
-
-static bool sysrq_handler_registered;
-
-static inline void sysrq_register_handler(void)
-{
-       int error;
-
-       error = input_register_handler(&sysrq_handler);
-       if (error)
-               pr_err("Failed to register input handler, error %d", error);
-       else
-               sysrq_handler_registered = true;
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-       if (sysrq_handler_registered) {
-               input_unregister_handler(&sysrq_handler);
-               sysrq_handler_registered = false;
-       }
-}
-
-#else
-
-static inline void sysrq_register_handler(void)
-{
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-}
-
-#endif /* CONFIG_INPUT */
-
-int sysrq_toggle_support(int enable_mask)
-{
-       bool was_enabled = sysrq_on();
-
-       sysrq_enabled = enable_mask;
-
-       if (was_enabled != sysrq_on()) {
-               if (sysrq_on())
-                       sysrq_register_handler();
-               else
-                       sysrq_unregister_handler();
-       }
-
-       return 0;
-}
-
-static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
-                                struct sysrq_key_op *remove_op_p)
-{
-       int retval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sysrq_key_table_lock, flags);
-       if (__sysrq_get_key_op(key) == remove_op_p) {
-               __sysrq_put_key_op(key, insert_op_p);
-               retval = 0;
-       } else {
-               retval = -1;
-       }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-       return retval;
-}
-
-int register_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-       return __sysrq_swap_key_ops(key, op_p, NULL);
-}
-EXPORT_SYMBOL(register_sysrq_key);
-
-int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-       return __sysrq_swap_key_ops(key, NULL, op_p);
-}
-EXPORT_SYMBOL(unregister_sysrq_key);
-
-#ifdef CONFIG_PROC_FS
-/*
- * writing 'C' to /proc/sysrq-trigger is like sysrq-C
- */
-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       if (count) {
-               char c;
-
-               if (get_user(c, buf))
-                       return -EFAULT;
-               __handle_sysrq(c, false);
-       }
-
-       return count;
-}
-
-static const struct file_operations proc_sysrq_trigger_operations = {
-       .write          = write_sysrq_trigger,
-       .llseek         = noop_llseek,
-};
-
-static void sysrq_init_procfs(void)
-{
-       if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
-                        &proc_sysrq_trigger_operations))
-               pr_err("Failed to register proc interface\n");
-}
-
-#else
-
-static inline void sysrq_init_procfs(void)
-{
-}
-
-#endif /* CONFIG_PROC_FS */
-
-static int __init sysrq_init(void)
-{
-       sysrq_init_procfs();
-
-       if (sysrq_on())
-               sysrq_register_handler();
-
-       return 0;
-}
-module_init(sysrq_init);
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
deleted file mode 100644 (file)
index f64582b..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Creating audit events from TTY input.
- *
- * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
- * material is made available to anyone wishing to use, modify, copy, or
- * redistribute it subject to the terms and conditions of the GNU General
- * Public License v.2.
- *
- * Authors: Miloslav Trmac <mitr@redhat.com>
- */
-
-#include <linux/audit.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-
-struct tty_audit_buf {
-       atomic_t count;
-       struct mutex mutex;     /* Protects all data below */
-       int major, minor;       /* The TTY which the data is from */
-       unsigned icanon:1;
-       size_t valid;
-       unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
-};
-
-static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
-                                                int icanon)
-{
-       struct tty_audit_buf *buf;
-
-       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
-       if (!buf)
-               goto err;
-       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-       if (!buf->data)
-               goto err_buf;
-       atomic_set(&buf->count, 1);
-       mutex_init(&buf->mutex);
-       buf->major = major;
-       buf->minor = minor;
-       buf->icanon = icanon;
-       buf->valid = 0;
-       return buf;
-
-err_buf:
-       kfree(buf);
-err:
-       return NULL;
-}
-
-static void tty_audit_buf_free(struct tty_audit_buf *buf)
-{
-       WARN_ON(buf->valid != 0);
-       kfree(buf->data);
-       kfree(buf);
-}
-
-static void tty_audit_buf_put(struct tty_audit_buf *buf)
-{
-       if (atomic_dec_and_test(&buf->count))
-               tty_audit_buf_free(buf);
-}
-
-static void tty_audit_log(const char *description, struct task_struct *tsk,
-                         uid_t loginuid, unsigned sessionid, int major,
-                         int minor, unsigned char *data, size_t size)
-{
-       struct audit_buffer *ab;
-
-       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
-       if (ab) {
-               char name[sizeof(tsk->comm)];
-               uid_t uid = task_uid(tsk);
-
-               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
-                                "major=%d minor=%d comm=", description,
-                                tsk->pid, uid, loginuid, sessionid,
-                                major, minor);
-               get_task_comm(name, tsk);
-               audit_log_untrustedstring(ab, name);
-               audit_log_format(ab, " data=");
-               audit_log_n_hex(ab, data, size);
-               audit_log_end(ab);
-       }
-}
-
-/**
- *     tty_audit_buf_push      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     @tsk with @loginuid.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
-                              unsigned int sessionid,
-                              struct tty_audit_buf *buf)
-{
-       if (buf->valid == 0)
-               return;
-       if (audit_enabled == 0)
-               return;
-       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
-                     buf->data, buf->valid);
-       buf->valid = 0;
-}
-
-/**
- *     tty_audit_buf_push_current      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     the current task.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
-{
-       uid_t auid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       tty_audit_buf_push(current, auid, sessionid, buf);
-}
-
-/**
- *     tty_audit_exit  -       Handle a task exit
- *
- *     Make sure all buffered data is written out and deallocate the buffer.
- *     Only needs to be called if current->signal->tty_audit_buf != %NULL.
- */
-void tty_audit_exit(void)
-{
-       struct tty_audit_buf *buf;
-
-       spin_lock_irq(&current->sighand->siglock);
-       buf = current->signal->tty_audit_buf;
-       current->signal->tty_audit_buf = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
-       if (!buf)
-               return;
-
-       mutex_lock(&buf->mutex);
-       tty_audit_buf_push_current(buf);
-       mutex_unlock(&buf->mutex);
-
-       tty_audit_buf_put(buf);
-}
-
-/**
- *     tty_audit_fork  -       Copy TTY audit state for a new task
- *
- *     Set up TTY audit state in @sig from current.  @sig needs no locking.
- */
-void tty_audit_fork(struct signal_struct *sig)
-{
-       spin_lock_irq(&current->sighand->siglock);
-       sig->audit_tty = current->signal->audit_tty;
-       spin_unlock_irq(&current->sighand->siglock);
-}
-
-/**
- *     tty_audit_tiocsti       -       Log TIOCSTI
- */
-void tty_audit_tiocsti(struct tty_struct *tty, char ch)
-{
-       struct tty_audit_buf *buf;
-       int major, minor, should_audit;
-
-       spin_lock_irq(&current->sighand->siglock);
-       should_audit = current->signal->audit_tty;
-       buf = current->signal->tty_audit_buf;
-       if (buf)
-               atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
-
-       major = tty->driver->major;
-       minor = tty->driver->minor_start + tty->index;
-       if (buf) {
-               mutex_lock(&buf->mutex);
-               if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
-               mutex_unlock(&buf->mutex);
-               tty_audit_buf_put(buf);
-       }
-
-       if (should_audit && audit_enabled) {
-               uid_t auid;
-               unsigned int sessionid;
-
-               auid = audit_get_loginuid(current);
-               sessionid = audit_get_sessionid(current);
-               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
-                             minor, &ch, 1);
-       }
-}
-
-/**
- * tty_audit_push_task -       Flush task's pending audit data
- * @tsk:               task pointer
- * @loginuid:          sender login uid
- * @sessionid:         sender session id
- *
- * Called with a ref on @tsk held. Try to lock sighand and get a
- * reference to the tty audit buffer if available.
- * Flush the buffer or return an appropriate error code.
- */
-int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
-{
-       struct tty_audit_buf *buf = ERR_PTR(-EPERM);
-       unsigned long flags;
-
-       if (!lock_task_sighand(tsk, &flags))
-               return -ESRCH;
-
-       if (tsk->signal->audit_tty) {
-               buf = tsk->signal->tty_audit_buf;
-               if (buf)
-                       atomic_inc(&buf->count);
-       }
-       unlock_task_sighand(tsk, &flags);
-
-       /*
-        * Return 0 when signal->audit_tty set
-        * but tsk->signal->tty_audit_buf == NULL.
-        */
-       if (!buf || IS_ERR(buf))
-               return PTR_ERR(buf);
-
-       mutex_lock(&buf->mutex);
-       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
-       mutex_unlock(&buf->mutex);
-
-       tty_audit_buf_put(buf);
-       return 0;
-}
-
-/**
- *     tty_audit_buf_get       -       Get an audit buffer.
- *
- *     Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
- *     if TTY auditing is disabled or out of memory.  Otherwise, return a new
- *     reference to the buffer.
- */
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
-{
-       struct tty_audit_buf *buf, *buf2;
-
-       buf = NULL;
-       buf2 = NULL;
-       spin_lock_irq(&current->sighand->siglock);
-       if (likely(!current->signal->audit_tty))
-               goto out;
-       buf = current->signal->tty_audit_buf;
-       if (buf) {
-               atomic_inc(&buf->count);
-               goto out;
-       }
-       spin_unlock_irq(&current->sighand->siglock);
-
-       buf2 = tty_audit_buf_alloc(tty->driver->major,
-                                  tty->driver->minor_start + tty->index,
-                                  tty->icanon);
-       if (buf2 == NULL) {
-               audit_log_lost("out of memory in TTY auditing");
-               return NULL;
-       }
-
-       spin_lock_irq(&current->sighand->siglock);
-       if (!current->signal->audit_tty)
-               goto out;
-       buf = current->signal->tty_audit_buf;
-       if (!buf) {
-               current->signal->tty_audit_buf = buf2;
-               buf = buf2;
-               buf2 = NULL;
-       }
-       atomic_inc(&buf->count);
-       /* Fall through */
- out:
-       spin_unlock_irq(&current->sighand->siglock);
-       if (buf2)
-               tty_audit_buf_free(buf2);
-       return buf;
-}
-
-/**
- *     tty_audit_add_data      -       Add data for TTY auditing.
- *
- *     Audit @data of @size from @tty, if necessary.
- */
-void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
-                       size_t size)
-{
-       struct tty_audit_buf *buf;
-       int major, minor;
-
-       if (unlikely(size == 0))
-               return;
-
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY
-           && tty->driver->subtype == PTY_TYPE_MASTER)
-               return;
-
-       buf = tty_audit_buf_get(tty);
-       if (!buf)
-               return;
-
-       mutex_lock(&buf->mutex);
-       major = tty->driver->major;
-       minor = tty->driver->minor_start + tty->index;
-       if (buf->major != major || buf->minor != minor
-           || buf->icanon != tty->icanon) {
-               tty_audit_buf_push_current(buf);
-               buf->major = major;
-               buf->minor = minor;
-               buf->icanon = tty->icanon;
-       }
-       do {
-               size_t run;
-
-               run = N_TTY_BUF_SIZE - buf->valid;
-               if (run > size)
-                       run = size;
-               memcpy(buf->data + buf->valid, data, run);
-               buf->valid += run;
-               data += run;
-               size -= run;
-               if (buf->valid == N_TTY_BUF_SIZE)
-                       tty_audit_buf_push_current(buf);
-       } while (size != 0);
-       mutex_unlock(&buf->mutex);
-       tty_audit_buf_put(buf);
-}
-
-/**
- *     tty_audit_push  -       Push buffered data out
- *
- *     Make sure no audit data is pending for @tty on the current process.
- */
-void tty_audit_push(struct tty_struct *tty)
-{
-       struct tty_audit_buf *buf;
-
-       spin_lock_irq(&current->sighand->siglock);
-       if (likely(!current->signal->audit_tty)) {
-               spin_unlock_irq(&current->sighand->siglock);
-               return;
-       }
-       buf = current->signal->tty_audit_buf;
-       if (buf)
-               atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (buf) {
-               int major, minor;
-
-               major = tty->driver->major;
-               minor = tty->driver->minor_start + tty->index;
-               mutex_lock(&buf->mutex);
-               if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
-               mutex_unlock(&buf->mutex);
-               tty_audit_buf_put(buf);
-       }
-}
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
deleted file mode 100644 (file)
index cc1e985..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Tty buffer allocation management
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-/**
- *     tty_buffer_free_all             -       free buffers used by a tty
- *     @tty: tty to free from
- *
- *     Remove all the buffers pending on a tty whether queued with data
- *     or in the free ring. Must be called when the tty is no longer in use
- *
- *     Locking: none
- */
-
-void tty_buffer_free_all(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               kfree(thead);
-       }
-       while ((thead = tty->buf.free) != NULL) {
-               tty->buf.free = thead->next;
-               kfree(thead);
-       }
-       tty->buf.tail = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_alloc        -       allocate a tty buffer
- *     @tty: tty device
- *     @size: desired size (characters)
- *
- *     Allocate a new tty buffer to hold the desired number of characters.
- *     Return NULL if out of memory or the allocation would exceed the
- *     per device queue
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *p;
-
-       if (tty->buf.memory_used + size > 65536)
-               return NULL;
-       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-       if (p == NULL)
-               return NULL;
-       p->used = 0;
-       p->size = size;
-       p->next = NULL;
-       p->commit = 0;
-       p->read = 0;
-       p->char_buf_ptr = (char *)(p->data);
-       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-       tty->buf.memory_used += size;
-       return p;
-}
-
-/**
- *     tty_buffer_free         -       free a tty buffer
- *     @tty: tty owning the buffer
- *     @b: the buffer to free
- *
- *     Free a tty buffer, or add it to the free list according to our
- *     internal strategy
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-       /* Dumb strategy for now - should keep some stats */
-       tty->buf.memory_used -= b->size;
-       WARN_ON(tty->buf.memory_used < 0);
-
-       if (b->size >= 512)
-               kfree(b);
-       else {
-               b->next = tty->buf.free;
-               tty->buf.free = b;
-       }
-}
-
-/**
- *     __tty_buffer_flush              -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. Caller must
- *     hold the buffer lock and must have ensured no parallel flush to
- *     ldisc is running.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               tty_buffer_free(tty, thead);
-       }
-       tty->buf.tail = NULL;
-}
-
-/**
- *     tty_buffer_flush                -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. If the buffer is
- *     being processed by flush_to_ldisc then we defer the processing
- *     to that function
- *
- *     Locking: none
- */
-
-void tty_buffer_flush(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* If the data is being pushed to the tty layer then we can't
-          process it here. Instead set a flag and the flush_to_ldisc
-          path will process the flush request before it exits */
-       if (test_bit(TTY_FLUSHING, &tty->flags)) {
-               set_bit(TTY_FLUSHPENDING, &tty->flags);
-               spin_unlock_irqrestore(&tty->buf.lock, flags);
-               wait_event(tty->read_wait,
-                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-               return;
-       } else
-               __tty_buffer_flush(tty);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *     tty_buffer_find         -       find a free tty buffer
- *     @tty: tty owning the buffer
- *     @size: characters wanted
- *
- *     Locate an existing suitable tty buffer or if we are lacking one then
- *     allocate a new one. We round our buffers off in 256 character chunks
- *     to get better allocation behaviour.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer **tbh = &tty->buf.free;
-       while ((*tbh) != NULL) {
-               struct tty_buffer *t = *tbh;
-               if (t->size >= size) {
-                       *tbh = t->next;
-                       t->next = NULL;
-                       t->used = 0;
-                       t->commit = 0;
-                       t->read = 0;
-                       tty->buf.memory_used += t->size;
-                       return t;
-               }
-               tbh = &((*tbh)->next);
-       }
-       /* Round the buffer size out */
-       size = (size + 0xFF) & ~0xFF;
-       return tty_buffer_alloc(tty, size);
-       /* Should possibly check if this fails for the largest buffer we
-          have queued and recycle that ? */
-}
-
-/**
- *     tty_buffer_request_room         -       grow tty buffer if needed
- *     @tty: tty structure
- *     @size: size desired
- *
- *     Make at least size bytes of linear space available for the tty
- *     buffer. If we fail return the size we managed to find.
- *
- *     Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *b, *n;
-       int left;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-          remove this conditional if its worth it. This would be invisible
-          to the callers */
-       if ((b = tty->buf.tail) != NULL)
-               left = b->size - b->used;
-       else
-               left = 0;
-
-       if (left < size) {
-               /* This is the slow path - looking for new buffers to use */
-               if ((n = tty_buffer_find(tty, size)) != NULL) {
-                       if (b != NULL) {
-                               b->next = n;
-                               b->commit = b->used;
-                       } else
-                               tty->buf.head = n;
-                       tty->buf.tail = n;
-               } else
-                       size = left;
-       }
-
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *     tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flag: flag value for each character
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. All the characters
- *     passed are marked with the supplied flag. Returns the number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
-               const unsigned char *chars, char flag, size_t size)
-{
-       int copied = 0;
-       do {
-               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(tty, goal);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memset(tb->flag_buf_ptr + tb->used, flag, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
-
-/**
- *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flags: flag bytes
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. For each character
- *     the flags array indicates the status of the character. Returns the
- *     number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-               const unsigned char *chars, const char *flags, size_t size)
-{
-       int copied = 0;
-       do {
-               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(tty, goal);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               flags += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *     tty_schedule_flip       -       push characters to ldisc
- *     @tty: tty to push from
- *
- *     Takes any pending buffers and transfers their ownership to the
- *     ldisc side of the queue. It then schedules those characters for
- *     processing by the line discipline.
- *
- *     Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *     tty_prepare_flip_string         -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for normal characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-                                                               size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-                       unsigned char **chars, char **flags, size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               *flags = tb->flag_buf_ptr + tb->used;
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
-/**
- *     flush_to_ldisc
- *     @work: tty structure passed from work queue.
- *
- *     This routine is called out of the software interrupt to flush data
- *     from the buffer chain to the line discipline.
- *
- *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *     while invoking the line discipline receive_buf method. The
- *     receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, buf.work.work);
-       unsigned long   flags;
-       struct tty_ldisc *disc;
-
-       disc = tty_ldisc_ref(tty);
-       if (disc == NULL)       /*  !TTY_LDISC */
-               return;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-               struct tty_buffer *head;
-               while ((head = tty->buf.head) != NULL) {
-                       int count;
-                       char *char_buf;
-                       unsigned char *flag_buf;
-
-                       count = head->commit - head->read;
-                       if (!count) {
-                               if (head->next == NULL)
-                                       break;
-                               tty->buf.head = head->next;
-                               tty_buffer_free(tty, head);
-                               continue;
-                       }
-                       /* Ldisc or user is trying to flush the buffers
-                          we are feeding to the ldisc, stop feeding the
-                          line discipline as we want to empty the queue */
-                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-                               break;
-                       if (!tty->receive_room) {
-                               schedule_delayed_work(&tty->buf.work, 1);
-                               break;
-                       }
-                       if (count > tty->receive_room)
-                               count = tty->receive_room;
-                       char_buf = head->char_buf_ptr + head->read;
-                       flag_buf = head->flag_buf_ptr + head->read;
-                       head->read += count;
-                       spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       disc->ops->receive_buf(tty, char_buf,
-                                                       flag_buf, count);
-                       spin_lock_irqsave(&tty->buf.lock, flags);
-               }
-               clear_bit(TTY_FLUSHING, &tty->flags);
-       }
-
-       /* We may have a deferred request to flush the input buffer,
-          if so pull the chain under the lock and empty the queue */
-       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-               __tty_buffer_flush(tty);
-               clear_bit(TTY_FLUSHPENDING, &tty->flags);
-               wake_up(&tty->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       tty_ldisc_deref(disc);
-}
-
-/**
- *     tty_flush_to_ldisc
- *     @tty: tty to push
- *
- *     Push the terminal flip buffers to the line discipline.
- *
- *     Must not be called from IRQ context.
- */
-void tty_flush_to_ldisc(struct tty_struct *tty)
-{
-       flush_delayed_work(&tty->buf.work);
-}
-
-/**
- *     tty_flip_buffer_push    -       terminal
- *     @tty: tty to push
- *
- *     Queue a push of the terminal flip buffers to the line discipline. This
- *     function must not be called from IRQ context if tty->low_latency is set.
- *
- *     In the event of the queue being busy for flipping the work will be
- *     held off and retried later.
- *
- *     Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       if (tty->low_latency)
-               flush_to_ldisc(&tty->buf.work.work);
-       else
-               schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-/**
- *     tty_buffer_init         -       prepare a tty buffer structure
- *     @tty: tty to initialise
- *
- *     Set up the initial state of the buffer management for a tty device.
- *     Must be called before the other tty buffer functions are used.
- *
- *     Locking: none
- */
-
-void tty_buffer_init(struct tty_struct *tty)
-{
-       spin_lock_init(&tty->buf.lock);
-       tty->buf.head = NULL;
-       tty->buf.tail = NULL;
-       tty->buf.free = NULL;
-       tty->buf.memory_used = 0;
-       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
-}
-
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
deleted file mode 100644 (file)
index c05c5af..0000000
+++ /dev/null
@@ -1,3263 +0,0 @@
-/*
- *  linux/drivers/char/tty_io.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures.  Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time.  Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c).  This
- * makes for cleaner and more compact code.  -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling.  No delays, but all
- * other bits should be there.
- *     -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- *     -- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- *     -- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- *      -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote tty_init_dev and tty_release_dev to eliminate races.
- *     -- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- *      -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context.  Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc()
- *                      -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-#include <linux/serial.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
-       .c_iflag = ICRNL | IXON,
-       .c_oflag = OPOST | ONLCR,
-       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
-       .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
-                  ECHOCTL | ECHOKE | IEXTEN,
-       .c_cc = INIT_C_CC,
-       .c_ispeed = 38400,
-       .c_ospeed = 38400
-};
-
-EXPORT_SYMBOL(tty_std_termios);
-
-/* This list gets poked at by procfs and various bits of boot up code. This
-   could do with some rationalisation such as pulling the tty proc function
-   into this file */
-
-LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
-
-/* Mutex to protect creating and releasing a tty. This is shared with
-   vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-/* Spinlock to protect the tty->tty_files list */
-DEFINE_SPINLOCK(tty_files_lock);
-
-static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg);
-#else
-#define tty_compat_ioctl NULL
-#endif
-static int __tty_fasync(int fd, struct file *filp, int on);
-static int tty_fasync(int fd, struct file *filp, int on);
-static void release_tty(struct tty_struct *tty, int idx);
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-
-/**
- *     alloc_tty_struct        -       allocate a tty object
- *
- *     Return a new empty tty structure. The data fields have not
- *     been initialized in any way but has been zeroed
- *
- *     Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
-       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
- *     free_tty_struct         -       free a disused tty
- *     @tty: tty struct to free
- *
- *     Free the write buffers, tty queue and tty memory itself.
- *
- *     Locking: none. Must be called after tty is definitely unused
- */
-
-void free_tty_struct(struct tty_struct *tty)
-{
-       if (tty->dev)
-               put_device(tty->dev);
-       kfree(tty->write_buf);
-       tty_buffer_free_all(tty);
-       kfree(tty);
-}
-
-static inline struct tty_struct *file_tty(struct file *file)
-{
-       return ((struct tty_file_private *)file->private_data)->tty;
-}
-
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
-{
-       struct tty_file_private *priv;
-
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->tty = tty;
-       priv->file = file;
-       file->private_data = priv;
-
-       spin_lock(&tty_files_lock);
-       list_add(&priv->list, &tty->tty_files);
-       spin_unlock(&tty_files_lock);
-
-       return 0;
-}
-
-/* Delete file from its tty */
-void tty_del_file(struct file *file)
-{
-       struct tty_file_private *priv = file->private_data;
-
-       spin_lock(&tty_files_lock);
-       list_del(&priv->list);
-       spin_unlock(&tty_files_lock);
-       file->private_data = NULL;
-       kfree(priv);
-}
-
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
-/**
- *     tty_name        -       return tty naming
- *     @tty: tty structure
- *     @buf: buffer for output
- *
- *     Convert a tty structure into a name. The name reflects the kernel
- *     naming policy and if udev is in use may not reflect user space
- *
- *     Locking: none
- */
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
-       if (!tty) /* Hmm.  NULL pointer.  That's fun. */
-               strcpy(buf, "NULL tty");
-       else
-               strcpy(buf, tty->name);
-       return buf;
-}
-
-EXPORT_SYMBOL(tty_name);
-
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
-                             const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
-       if (!tty) {
-               printk(KERN_WARNING
-                       "null TTY for (%d:%d) in %s\n",
-                       imajor(inode), iminor(inode), routine);
-               return 1;
-       }
-       if (tty->magic != TTY_MAGIC) {
-               printk(KERN_WARNING
-                       "bad magic number for tty struct (%d:%d) in %s\n",
-                       imajor(inode), iminor(inode), routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
-       struct list_head *p;
-       int count = 0;
-
-       spin_lock(&tty_files_lock);
-       list_for_each(p, &tty->tty_files) {
-               count++;
-       }
-       spin_unlock(&tty_files_lock);
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_SLAVE &&
-           tty->link && tty->link->count)
-               count++;
-       if (tty->count != count) {
-               printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
-                                   "!= #fd's(%d) in %s\n",
-                      tty->name, tty->count, count, routine);
-               return count;
-       }
-#endif
-       return 0;
-}
-
-/**
- *     get_tty_driver          -       find device of a tty
- *     @dev_t: device identifier
- *     @index: returns the index of the tty
- *
- *     This routine returns a tty driver structure, given a device number
- *     and also passes back the index number.
- *
- *     Locking: caller must hold tty_mutex
- */
-
-static struct tty_driver *get_tty_driver(dev_t device, int *index)
-{
-       struct tty_driver *p;
-
-       list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               dev_t base = MKDEV(p->major, p->minor_start);
-               if (device < base || device >= base + p->num)
-                       continue;
-               *index = device - base;
-               return tty_driver_kref_get(p);
-       }
-       return NULL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-/**
- *     tty_find_polling_driver -       find device of a polled tty
- *     @name: name string to match
- *     @line: pointer to resulting tty line nr
- *
- *     This routine returns a tty driver structure, given a name
- *     and the condition that the tty driver is capable of polled
- *     operation.
- */
-struct tty_driver *tty_find_polling_driver(char *name, int *line)
-{
-       struct tty_driver *p, *res = NULL;
-       int tty_line = 0;
-       int len;
-       char *str, *stp;
-
-       for (str = name; *str; str++)
-               if ((*str >= '0' && *str <= '9') || *str == ',')
-                       break;
-       if (!*str)
-               return NULL;
-
-       len = str - name;
-       tty_line = simple_strtoul(str, &str, 10);
-
-       mutex_lock(&tty_mutex);
-       /* Search through the tty devices to look for a match */
-       list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               if (strncmp(name, p->name, len) != 0)
-                       continue;
-               stp = str;
-               if (*stp == ',')
-                       stp++;
-               if (*stp == '\0')
-                       stp = NULL;
-
-               if (tty_line >= 0 && tty_line < p->num && p->ops &&
-                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
-                       res = tty_driver_kref_get(p);
-                       *line = tty_line;
-                       break;
-               }
-       }
-       mutex_unlock(&tty_mutex);
-
-       return res;
-}
-EXPORT_SYMBOL_GPL(tty_find_polling_driver);
-#endif
-
-/**
- *     tty_check_change        -       check for POSIX terminal changes
- *     @tty: tty to check
- *
- *     If we try to write to, or set the state of, a terminal and we're
- *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
- *     ignored, go ahead and perform the operation.  (POSIX 7.2)
- *
- *     Locking: ctrl_lock
- */
-
-int tty_check_change(struct tty_struct *tty)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (current->signal->tty != tty)
-               return 0;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-
-       if (!tty->pgrp) {
-               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
-               goto out_unlock;
-       }
-       if (task_pgrp(current) == tty->pgrp)
-               goto out_unlock;
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (is_ignored(SIGTTOU))
-               goto out;
-       if (is_current_pgrp_orphaned()) {
-               ret = -EIO;
-               goto out;
-       }
-       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
-       set_thread_flag(TIF_SIGPENDING);
-       ret = -ERESTARTSYS;
-out:
-       return ret;
-out_unlock:
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       return ret;
-}
-
-EXPORT_SYMBOL(tty_check_change);
-
-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
-{
-       return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
-               unsigned long arg)
-{
-       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static long hung_up_tty_compat_ioctl(struct file *file,
-                                    unsigned int cmd, unsigned long arg)
-{
-       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static const struct file_operations tty_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = tty_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-
-static const struct file_operations console_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = redirected_tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = tty_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-
-static const struct file_operations hung_up_tty_fops = {
-       .llseek         = no_llseek,
-       .read           = hung_up_tty_read,
-       .write          = hung_up_tty_write,
-       .poll           = hung_up_tty_poll,
-       .unlocked_ioctl = hung_up_tty_ioctl,
-       .compat_ioctl   = hung_up_tty_compat_ioctl,
-       .release        = tty_release,
-};
-
-static DEFINE_SPINLOCK(redirect_lock);
-static struct file *redirect;
-
-/**
- *     tty_wakeup      -       request more data
- *     @tty: terminal
- *
- *     Internal and external helper for wakeups of tty. This function
- *     informs the line discipline if present that the driver is ready
- *     to receive more output data.
- */
-
-void tty_wakeup(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
-               ld = tty_ldisc_ref(tty);
-               if (ld) {
-                       if (ld->ops->write_wakeup)
-                               ld->ops->write_wakeup(tty);
-                       tty_ldisc_deref(ld);
-               }
-       }
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-EXPORT_SYMBOL_GPL(tty_wakeup);
-
-/**
- *     __tty_hangup            -       actual handler for hangup events
- *     @work: tty device
- *
- *     This can be called by the "eventd" kernel thread.  That is process
- *     synchronous but doesn't hold any locks, so we need to make sure we
- *     have the appropriate locks for what we're doing.
- *
- *     The hangup event clears any pending redirections onto the hung up
- *     device. It ensures future writes will error and it does the needed
- *     line discipline hangup and signal delivery. The tty object itself
- *     remains intact.
- *
- *     Locking:
- *             BTM
- *               redirect lock for undoing redirection
- *               file list lock for manipulating list of ttys
- *               tty_ldisc_lock from called functions
- *               termios_mutex resetting termios data
- *               tasklist_lock to walk task list for hangup event
- *                 ->siglock to protect ->signal/->sighand
- */
-void __tty_hangup(struct tty_struct *tty)
-{
-       struct file *cons_filp = NULL;
-       struct file *filp, *f = NULL;
-       struct task_struct *p;
-       struct tty_file_private *priv;
-       int    closecount = 0, n;
-       unsigned long flags;
-       int refs = 0;
-
-       if (!tty)
-               return;
-
-
-       spin_lock(&redirect_lock);
-       if (redirect && file_tty(redirect) == tty) {
-               f = redirect;
-               redirect = NULL;
-       }
-       spin_unlock(&redirect_lock);
-
-       tty_lock();
-
-       /* inuse_filps is protected by the single tty lock,
-          this really needs to change if we want to flush the
-          workqueue with the lock held */
-       check_tty_count(tty, "tty_hangup");
-
-       spin_lock(&tty_files_lock);
-       /* This breaks for file handles being sent over AF_UNIX sockets ? */
-       list_for_each_entry(priv, &tty->tty_files, list) {
-               filp = priv->file;
-               if (filp->f_op->write == redirected_tty_write)
-                       cons_filp = filp;
-               if (filp->f_op->write != tty_write)
-                       continue;
-               closecount++;
-               __tty_fasync(-1, filp, 0);      /* can't block */
-               filp->f_op = &hung_up_tty_fops;
-       }
-       spin_unlock(&tty_files_lock);
-
-       tty_ldisc_hangup(tty);
-
-       read_lock(&tasklist_lock);
-       if (tty->session) {
-               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
-                       spin_lock_irq(&p->sighand->siglock);
-                       if (p->signal->tty == tty) {
-                               p->signal->tty = NULL;
-                               /* We defer the dereferences outside fo
-                                  the tasklist lock */
-                               refs++;
-                       }
-                       if (!p->signal->leader) {
-                               spin_unlock_irq(&p->sighand->siglock);
-                               continue;
-                       }
-                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (tty->pgrp)
-                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       spin_unlock_irq(&p->sighand->siglock);
-               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
-       }
-       read_unlock(&tasklist_lock);
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       clear_bit(TTY_THROTTLED, &tty->flags);
-       clear_bit(TTY_PUSH, &tty->flags);
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       put_pid(tty->session);
-       put_pid(tty->pgrp);
-       tty->session = NULL;
-       tty->pgrp = NULL;
-       tty->ctrl_status = 0;
-       set_bit(TTY_HUPPED, &tty->flags);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       /* Account for the p->signal references we killed */
-       while (refs--)
-               tty_kref_put(tty);
-
-       /*
-        * If one of the devices matches a console pointer, we
-        * cannot just call hangup() because that will cause
-        * tty->count and state->count to go out of sync.
-        * So we just call close() the right number of times.
-        */
-       if (cons_filp) {
-               if (tty->ops->close)
-                       for (n = 0; n < closecount; n++)
-                               tty->ops->close(tty, cons_filp);
-       } else if (tty->ops->hangup)
-               (tty->ops->hangup)(tty);
-       /*
-        * We don't want to have driver/ldisc interactions beyond
-        * the ones we did here. The driver layer expects no
-        * calls after ->hangup() from the ldisc side. However we
-        * can't yet guarantee all that.
-        */
-       set_bit(TTY_HUPPED, &tty->flags);
-       tty_ldisc_enable(tty);
-
-       tty_unlock();
-
-       if (f)
-               fput(f);
-}
-
-static void do_tty_hangup(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, hangup_work);
-
-       __tty_hangup(tty);
-}
-
-/**
- *     tty_hangup              -       trigger a hangup event
- *     @tty: tty to hangup
- *
- *     A carrier loss (virtual or otherwise) has occurred on this like
- *     schedule a hangup sequence to run after this event.
- */
-
-void tty_hangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-       char    buf[64];
-       printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
-       schedule_work(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_hangup);
-
-/**
- *     tty_vhangup             -       process vhangup
- *     @tty: tty to hangup
- *
- *     The user has asked via system call for the terminal to be hung up.
- *     We do this synchronously so that when the syscall returns the process
- *     is complete. That guarantee is necessary for security reasons.
- */
-
-void tty_vhangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-       char    buf[64];
-
-       printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
-       __tty_hangup(tty);
-}
-
-EXPORT_SYMBOL(tty_vhangup);
-
-
-/**
- *     tty_vhangup_self        -       process vhangup for own ctty
- *
- *     Perform a vhangup on the current controlling tty
- */
-
-void tty_vhangup_self(void)
-{
-       struct tty_struct *tty;
-
-       tty = get_current_tty();
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     tty_hung_up_p           -       was tty hung up
- *     @filp: file pointer of tty
- *
- *     Return true if the tty has been subject to a vhangup or a carrier
- *     loss
- */
-
-int tty_hung_up_p(struct file *filp)
-{
-       return (filp->f_op == &hung_up_tty_fops);
-}
-
-EXPORT_SYMBOL(tty_hung_up_p);
-
-static void session_clear_tty(struct pid *session)
-{
-       struct task_struct *p;
-       do_each_pid_task(session, PIDTYPE_SID, p) {
-               proc_clear_tty(p);
-       } while_each_pid_task(session, PIDTYPE_SID, p);
-}
-
-/**
- *     disassociate_ctty       -       disconnect controlling tty
- *     @on_exit: true if exiting so need to "hang up" the session
- *
- *     This function is typically called only by the session leader, when
- *     it wants to disassociate itself from its controlling tty.
- *
- *     It performs the following functions:
- *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
- *     (2)  Clears the tty from being controlling the session
- *     (3)  Clears the controlling tty for all processes in the
- *             session group.
- *
- *     The argument on_exit is set to 1 if called when a process is
- *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- *     Locking:
- *             BTM is taken for hysterical raisins, and held when
- *               called from no_tty().
- *               tty_mutex is taken to protect tty
- *               ->siglock is taken to protect ->signal/->sighand
- *               tasklist_lock is taken to walk process list for sessions
- *                 ->siglock is taken to protect ->signal/->sighand
- */
-
-void disassociate_ctty(int on_exit)
-{
-       struct tty_struct *tty;
-       struct pid *tty_pgrp = NULL;
-
-       if (!current->signal->leader)
-               return;
-
-       tty = get_current_tty();
-       if (tty) {
-               tty_pgrp = get_pid(tty->pgrp);
-               if (on_exit) {
-                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
-                               tty_vhangup(tty);
-               }
-               tty_kref_put(tty);
-       } else if (on_exit) {
-               struct pid *old_pgrp;
-               spin_lock_irq(&current->sighand->siglock);
-               old_pgrp = current->signal->tty_old_pgrp;
-               current->signal->tty_old_pgrp = NULL;
-               spin_unlock_irq(&current->sighand->siglock);
-               if (old_pgrp) {
-                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
-                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
-                       put_pid(old_pgrp);
-               }
-               return;
-       }
-       if (tty_pgrp) {
-               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-               if (!on_exit)
-                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-               put_pid(tty_pgrp);
-       }
-
-       spin_lock_irq(&current->sighand->siglock);
-       put_pid(current->signal->tty_old_pgrp);
-       current->signal->tty_old_pgrp = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
-
-       tty = get_current_tty();
-       if (tty) {
-               unsigned long flags;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               put_pid(tty->session);
-               put_pid(tty->pgrp);
-               tty->session = NULL;
-               tty->pgrp = NULL;
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               tty_kref_put(tty);
-       } else {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
-                      " = NULL", tty);
-#endif
-       }
-
-       /* Now clear signal->tty under the lock */
-       read_lock(&tasklist_lock);
-       session_clear_tty(task_session(current));
-       read_unlock(&tasklist_lock);
-}
-
-/**
- *
- *     no_tty  - Ensure the current process does not have a controlling tty
- */
-void no_tty(void)
-{
-       struct task_struct *tsk = current;
-       tty_lock();
-       disassociate_ctty(0);
-       tty_unlock();
-       proc_clear_tty(tsk);
-}
-
-
-/**
- *     stop_tty        -       propagate flow control
- *     @tty: tty to stop
- *
- *     Perform flow control to the driver. For PTY/TTY pairs we
- *     must also propagate the TIOCKPKT status. May be called
- *     on an already stopped device and will not re-call the driver
- *     method.
- *
- *     This functionality is used by both the line disciplines for
- *     halting incoming flow and by the driver. It may therefore be
- *     called from any context, may be under the tty atomic_write_lock
- *     but not always.
- *
- *     Locking:
- *             Uses the tty control lock internally
- */
-
-void stop_tty(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->stopped) {
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return;
-       }
-       tty->stopped = 1;
-       if (tty->link && tty->link->packet) {
-               tty->ctrl_status &= ~TIOCPKT_START;
-               tty->ctrl_status |= TIOCPKT_STOP;
-               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (tty->ops->stop)
-               (tty->ops->stop)(tty);
-}
-
-EXPORT_SYMBOL(stop_tty);
-
-/**
- *     start_tty       -       propagate flow control
- *     @tty: tty to start
- *
- *     Start a tty that has been stopped if at all possible. Perform
- *     any necessary wakeups and propagate the TIOCPKT status. If this
- *     is the tty was previous stopped and is being started then the
- *     driver start method is invoked and the line discipline woken.
- *
- *     Locking:
- *             ctrl_lock
- */
-
-void start_tty(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (!tty->stopped || tty->flow_stopped) {
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return;
-       }
-       tty->stopped = 0;
-       if (tty->link && tty->link->packet) {
-               tty->ctrl_status &= ~TIOCPKT_STOP;
-               tty->ctrl_status |= TIOCPKT_START;
-               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (tty->ops->start)
-               (tty->ops->start)(tty);
-       /* If we have a running line discipline it may need kicking */
-       tty_wakeup(tty);
-}
-
-EXPORT_SYMBOL(start_tty);
-
-/**
- *     tty_read        -       read method for tty device files
- *     @file: pointer to tty file
- *     @buf: user buffer
- *     @count: size of user buffer
- *     @ppos: unused
- *
- *     Perform the read system call function on this terminal device. Checks
- *     for hung up devices before calling the line discipline method.
- *
- *     Locking:
- *             Locks the line discipline internally while needed. Multiple
- *     read calls may be outstanding in parallel.
- */
-
-static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
-                       loff_t *ppos)
-{
-       int i;
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-
-       if (tty_paranoia_check(tty, inode, "tty_read"))
-               return -EIO;
-       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
-               return -EIO;
-
-       /* We want to wait for the line discipline to sort out in this
-          situation */
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->read)
-               i = (ld->ops->read)(tty, file, buf, count);
-       else
-               i = -EIO;
-       tty_ldisc_deref(ld);
-       if (i > 0)
-               inode->i_atime = current_fs_time(inode->i_sb);
-       return i;
-}
-
-void tty_write_unlock(struct tty_struct *tty)
-{
-       mutex_unlock(&tty->atomic_write_lock);
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-int tty_write_lock(struct tty_struct *tty, int ndelay)
-{
-       if (!mutex_trylock(&tty->atomic_write_lock)) {
-               if (ndelay)
-                       return -EAGAIN;
-               if (mutex_lock_interruptible(&tty->atomic_write_lock))
-                       return -ERESTARTSYS;
-       }
-       return 0;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
-       ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
-       struct tty_struct *tty,
-       struct file *file,
-       const char __user *buf,
-       size_t count)
-{
-       ssize_t ret, written = 0;
-       unsigned int chunk;
-
-       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * We chunk up writes into a temporary buffer. This
-        * simplifies low-level drivers immensely, since they
-        * don't have locking issues and user mode accesses.
-        *
-        * But if TTY_NO_WRITE_SPLIT is set, we should use a
-        * big chunk-size..
-        *
-        * The default chunk-size is 2kB, because the NTTY
-        * layer has problems with bigger chunks. It will
-        * claim to be able to handle more characters than
-        * it actually does.
-        *
-        * FIXME: This can probably go away now except that 64K chunks
-        * are too likely to fail unless switched to vmalloc...
-        */
-       chunk = 2048;
-       if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
-               chunk = 65536;
-       if (count < chunk)
-               chunk = count;
-
-       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
-       if (tty->write_cnt < chunk) {
-               unsigned char *buf_chunk;
-
-               if (chunk < 1024)
-                       chunk = 1024;
-
-               buf_chunk = kmalloc(chunk, GFP_KERNEL);
-               if (!buf_chunk) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               kfree(tty->write_buf);
-               tty->write_cnt = chunk;
-               tty->write_buf = buf_chunk;
-       }
-
-       /* Do the write .. */
-       for (;;) {
-               size_t size = count;
-               if (size > chunk)
-                       size = chunk;
-               ret = -EFAULT;
-               if (copy_from_user(tty->write_buf, buf, size))
-                       break;
-               ret = write(tty, file, tty->write_buf, size);
-               if (ret <= 0)
-                       break;
-               written += ret;
-               buf += ret;
-               count -= ret;
-               if (!count)
-                       break;
-               ret = -ERESTARTSYS;
-               if (signal_pending(current))
-                       break;
-               cond_resched();
-       }
-       if (written) {
-               struct inode *inode = file->f_path.dentry->d_inode;
-               inode->i_mtime = current_fs_time(inode->i_sb);
-               ret = written;
-       }
-out:
-       tty_write_unlock(tty);
-       return ret;
-}
-
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- *
- * We must still hold the BTM and test the CLOSING flag for the moment.
- */
-
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-       if (tty) {
-               mutex_lock(&tty->atomic_write_lock);
-               tty_lock();
-               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-                       tty_unlock();
-                       tty->ops->write(tty, msg, strlen(msg));
-               } else
-                       tty_unlock();
-               tty_write_unlock(tty);
-       }
-       return;
-}
-
-
-/**
- *     tty_write               -       write method for tty device file
- *     @file: tty file pointer
- *     @buf: user data to write
- *     @count: bytes to write
- *     @ppos: unused
- *
- *     Write data to a tty device via the line discipline.
- *
- *     Locking:
- *             Locks the line discipline as required
- *             Writes to the tty driver are serialized by the atomic_write_lock
- *     and are then processed in chunks to the device. The line discipline
- *     write method will not be invoked in parallel for each device.
- */
-
-static ssize_t tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-       ssize_t ret;
-
-       if (tty_paranoia_check(tty, inode, "tty_write"))
-               return -EIO;
-       if (!tty || !tty->ops->write ||
-               (test_bit(TTY_IO_ERROR, &tty->flags)))
-                       return -EIO;
-       /* Short term debug to catch buggy drivers */
-       if (tty->ops->write_room == NULL)
-               printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
-                       tty->driver->name);
-       ld = tty_ldisc_ref_wait(tty);
-       if (!ld->ops->write)
-               ret = -EIO;
-       else
-               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
-       tty_ldisc_deref(ld);
-       return ret;
-}
-
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct file *p = NULL;
-
-       spin_lock(&redirect_lock);
-       if (redirect) {
-               get_file(redirect);
-               p = redirect;
-       }
-       spin_unlock(&redirect_lock);
-
-       if (p) {
-               ssize_t res;
-               res = vfs_write(p, buf, count, &p->f_pos);
-               fput(p);
-               return res;
-       }
-       return tty_write(file, buf, count, ppos);
-}
-
-static char ptychar[] = "pqrstuvwxyzabcde";
-
-/**
- *     pty_line_name   -       generate name for a pty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 6 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
-{
-       int i = index + driver->name_base;
-       /* ->name is initialized to "ttyp", but "tty" is expected */
-       sprintf(p, "%s%c%x",
-               driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
-               ptychar[i >> 4 & 0xf], i & 0xf);
-}
-
-/**
- *     tty_line_name   -       generate name for a tty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 7 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
-{
-       sprintf(p, "%s%d", driver->name, index + driver->name_base);
-}
-
-/**
- *     tty_driver_lookup_tty() - find an existing tty, if any
- *     @driver: the driver for the tty
- *     @idx:    the minor number
- *
- *     Return the tty, if found or ERR_PTR() otherwise.
- *
- *     Locking: tty_mutex must be held. If tty is found, the mutex must
- *     be held until the 'fast-open' is also done. Will change once we
- *     have refcounting in the driver and per driver locking
- */
-static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
-               struct inode *inode, int idx)
-{
-       struct tty_struct *tty;
-
-       if (driver->ops->lookup)
-               return driver->ops->lookup(driver, inode, idx);
-
-       tty = driver->ttys[idx];
-       return tty;
-}
-
-/**
- *     tty_init_termios        -  helper for termios setup
- *     @tty: the tty to set up
- *
- *     Initialise the termios structures for this tty. Thus runs under
- *     the tty_mutex currently so we can be relaxed about ordering.
- */
-
-int tty_init_termios(struct tty_struct *tty)
-{
-       struct ktermios *tp;
-       int idx = tty->index;
-
-       tp = tty->driver->termios[idx];
-       if (tp == NULL) {
-               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-               if (tp == NULL)
-                       return -ENOMEM;
-               memcpy(tp, &tty->driver->init_termios,
-                                               sizeof(struct ktermios));
-               tty->driver->termios[idx] = tp;
-       }
-       tty->termios = tp;
-       tty->termios_locked = tp + 1;
-
-       /* Compatibility until drivers always set this */
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tty_init_termios);
-
-/**
- *     tty_driver_install_tty() - install a tty entry in the driver
- *     @driver: the driver for the tty
- *     @tty: the tty
- *
- *     Install a tty object into the driver tables. The tty->index field
- *     will be set by the time this is called. This method is responsible
- *     for ensuring any need additional structures are allocated and
- *     configured.
- *
- *     Locking: tty_mutex for now
- */
-static int tty_driver_install_tty(struct tty_driver *driver,
-                                               struct tty_struct *tty)
-{
-       int idx = tty->index;
-       int ret;
-
-       if (driver->ops->install) {
-               ret = driver->ops->install(driver, tty);
-               return ret;
-       }
-
-       if (tty_init_termios(tty) == 0) {
-               tty_driver_kref_get(driver);
-               tty->count++;
-               driver->ttys[idx] = tty;
-               return 0;
-       }
-       return -ENOMEM;
-}
-
-/**
- *     tty_driver_remove_tty() - remove a tty from the driver tables
- *     @driver: the driver for the tty
- *     @idx:    the minor number
- *
- *     Remvoe a tty object from the driver tables. The tty->index field
- *     will be set by the time this is called.
- *
- *     Locking: tty_mutex for now
- */
-static void tty_driver_remove_tty(struct tty_driver *driver,
-                                               struct tty_struct *tty)
-{
-       if (driver->ops->remove)
-               driver->ops->remove(driver, tty);
-       else
-               driver->ttys[tty->index] = NULL;
-}
-
-/*
- *     tty_reopen()    - fast re-open of an open tty
- *     @tty    - the tty to open
- *
- *     Return 0 on success, -errno on error.
- *
- *     Locking: tty_mutex must be held from the time the tty was found
- *              till this open completes.
- */
-static int tty_reopen(struct tty_struct *tty)
-{
-       struct tty_driver *driver = tty->driver;
-
-       if (test_bit(TTY_CLOSING, &tty->flags))
-               return -EIO;
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY &&
-           driver->subtype == PTY_TYPE_MASTER) {
-               /*
-                * special case for PTY masters: only one open permitted,
-                * and the slave side open count is incremented as well.
-                */
-               if (tty->count)
-                       return -EIO;
-
-               tty->link->count++;
-       }
-       tty->count++;
-       tty->driver = driver; /* N.B. why do this every time?? */
-
-       mutex_lock(&tty->ldisc_mutex);
-       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
-       mutex_unlock(&tty->ldisc_mutex);
-
-       return 0;
-}
-
-/**
- *     tty_init_dev            -       initialise a tty device
- *     @driver: tty driver we are opening a device on
- *     @idx: device index
- *     @ret_tty: returned tty structure
- *     @first_ok: ok to open a new device (used by ptmx)
- *
- *     Prepare a tty device. This may not be a "new" clean device but
- *     could also be an active device. The pty drivers require special
- *     handling because of this.
- *
- *     Locking:
- *             The function is called under the tty_mutex, which
- *     protects us from the tty struct or driver itself going away.
- *
- *     On exit the tty device has the line discipline attached and
- *     a reference count of 1. If a pair was created for pty/tty use
- *     and the other was a pty master then it too has a reference count of 1.
- *
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a mutex, so it's
- * really quite straightforward.  The mutex locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-                                                               int first_ok)
-{
-       struct tty_struct *tty;
-       int retval;
-
-       /* Check if pty master is being opened multiple times */
-       if (driver->subtype == PTY_TYPE_MASTER &&
-               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-               return ERR_PTR(-EIO);
-       }
-
-       /*
-        * First time open is complex, especially for PTY devices.
-        * This code guarantees that either everything succeeds and the
-        * TTY is ready for operation, or else the table slots are vacated
-        * and the allocated memory released.  (Except that the termios
-        * and locked termios may be retained.)
-        */
-
-       if (!try_module_get(driver->owner))
-               return ERR_PTR(-ENODEV);
-
-       tty = alloc_tty_struct();
-       if (!tty)
-               goto fail_no_mem;
-       initialize_tty_struct(tty, driver, idx);
-
-       retval = tty_driver_install_tty(driver, tty);
-       if (retval < 0) {
-               free_tty_struct(tty);
-               module_put(driver->owner);
-               return ERR_PTR(retval);
-       }
-
-       /*
-        * Structures all installed ... call the ldisc open routines.
-        * If we fail here just call release_tty to clean up.  No need
-        * to decrement the use counts, as release_tty doesn't care.
-        */
-       retval = tty_ldisc_setup(tty, tty->link);
-       if (retval)
-               goto release_mem_out;
-       return tty;
-
-fail_no_mem:
-       module_put(driver->owner);
-       return ERR_PTR(-ENOMEM);
-
-       /* call the tty release_tty routine to clean out this slot */
-release_mem_out:
-       if (printk_ratelimit())
-               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
-                                "clearing slot %d\n", idx);
-       release_tty(tty, idx);
-       return ERR_PTR(retval);
-}
-
-void tty_free_termios(struct tty_struct *tty)
-{
-       struct ktermios *tp;
-       int idx = tty->index;
-       /* Kill this flag and push into drivers for locking etc */
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               /* FIXME: Locking on ->termios array */
-               tp = tty->termios;
-               tty->driver->termios[idx] = NULL;
-               kfree(tp);
-       }
-}
-EXPORT_SYMBOL(tty_free_termios);
-
-void tty_shutdown(struct tty_struct *tty)
-{
-       tty_driver_remove_tty(tty->driver, tty);
-       tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
-
-/**
- *     release_one_tty         -       release tty structure memory
- *     @kref: kref of tty we are obliterating
- *
- *     Releases memory associated with a tty structure, and clears out the
- *     driver table slots. This function is called when a device is no longer
- *     in use. It also gets called when setup of a device fails.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *
- *     This method gets called from a work queue so that the driver private
- *     cleanup ops can sleep (needed for USB at least)
- */
-static void release_one_tty(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, hangup_work);
-       struct tty_driver *driver = tty->driver;
-
-       if (tty->ops->cleanup)
-               tty->ops->cleanup(tty);
-
-       tty->magic = 0;
-       tty_driver_kref_put(driver);
-       module_put(driver->owner);
-
-       spin_lock(&tty_files_lock);
-       list_del_init(&tty->tty_files);
-       spin_unlock(&tty_files_lock);
-
-       put_pid(tty->pgrp);
-       put_pid(tty->session);
-       free_tty_struct(tty);
-}
-
-static void queue_release_one_tty(struct kref *kref)
-{
-       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
-
-       if (tty->ops->shutdown)
-               tty->ops->shutdown(tty);
-       else
-               tty_shutdown(tty);
-
-       /* The hangup queue is now free so we can reuse it rather than
-          waste a chunk of memory for each port */
-       INIT_WORK(&tty->hangup_work, release_one_tty);
-       schedule_work(&tty->hangup_work);
-}
-
-/**
- *     tty_kref_put            -       release a tty kref
- *     @tty: tty device
- *
- *     Release a reference to a tty device and if need be let the kref
- *     layer destruct the object for us
- */
-
-void tty_kref_put(struct tty_struct *tty)
-{
-       if (tty)
-               kref_put(&tty->kref, queue_release_one_tty);
-}
-EXPORT_SYMBOL(tty_kref_put);
-
-/**
- *     release_tty             -       release tty structure memory
- *
- *     Release both @tty and a possible linked partner (think pty pair),
- *     and decrement the refcount of the backing module.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
- *
- */
-static void release_tty(struct tty_struct *tty, int idx)
-{
-       /* This should always be true but check for the moment */
-       WARN_ON(tty->index != idx);
-
-       if (tty->link)
-               tty_kref_put(tty->link);
-       tty_kref_put(tty);
-}
-
-/**
- *     tty_release             -       vfs callback for close
- *     @inode: inode of tty
- *     @filp: file pointer for handle to tty
- *
- *     Called the last time each file handle is closed that references
- *     this tty. There may however be several such references.
- *
- *     Locking:
- *             Takes bkl. See tty_release_dev
- *
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-
-int tty_release(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty = file_tty(filp);
-       struct tty_struct *o_tty;
-       int     pty_master, tty_closing, o_tty_closing, do_sleep;
-       int     devpts;
-       int     idx;
-       char    buf[64];
-
-       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-               return 0;
-
-       tty_lock();
-       check_tty_count(tty, "tty_release_dev");
-
-       __tty_fasync(-1, filp, 0);
-
-       idx = tty->index;
-       pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-                     tty->driver->subtype == PTY_TYPE_MASTER);
-       devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
-       o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
-       if (idx < 0 || idx >= tty->driver->num) {
-               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
-                                 "free (%s)\n", tty->name);
-               tty_unlock();
-               return 0;
-       }
-       if (!devpts) {
-               if (tty != tty->driver->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
-                              "for (%s)\n", idx, tty->name);
-                       return 0;
-               }
-               if (tty->termios != tty->driver->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
-                              "for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-       }
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
-              tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
-       if (tty->driver->other &&
-            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-               if (o_tty != tty->driver->other->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
-                                         "not o_tty for (%s)\n",
-                              idx, tty->name);
-                       return 0 ;
-               }
-               if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
-                                         "not o_termios for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-               if (o_tty->link != tty) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-                       return 0;
-               }
-       }
-#endif
-       if (tty->ops->close)
-               tty->ops->close(tty, filp);
-
-       tty_unlock();
-       /*
-        * Sanity check: if tty->count is going to zero, there shouldn't be
-        * any waiters on tty->read_wait or tty->write_wait.  We test the
-        * wait queues and kick everyone out _before_ actually starting to
-        * close.  This ensures that we won't block while releasing the tty
-        * structure.
-        *
-        * The test for the o_tty closing is necessary, since the master and
-        * slave sides may close in any order.  If the slave side closes out
-        * first, its count will be one, since the master side holds an open.
-        * Thus this test wouldn't be triggered at the time the slave closes,
-        * so we do it now.
-        *
-        * Note that it's possible for the tty to be opened again while we're
-        * flushing out waiters.  By recalculating the closing flags before
-        * each iteration we avoid any problems.
-        */
-       while (1) {
-               /* Guard against races with tty->count changes elsewhere and
-                  opens on /dev/tty */
-
-               mutex_lock(&tty_mutex);
-               tty_lock();
-               tty_closing = tty->count <= 1;
-               o_tty_closing = o_tty &&
-                       (o_tty->count <= (pty_master ? 1 : 0));
-               do_sleep = 0;
-
-               if (tty_closing) {
-                       if (waitqueue_active(&tty->read_wait)) {
-                               wake_up_poll(&tty->read_wait, POLLIN);
-                               do_sleep++;
-                       }
-                       if (waitqueue_active(&tty->write_wait)) {
-                               wake_up_poll(&tty->write_wait, POLLOUT);
-                               do_sleep++;
-                       }
-               }
-               if (o_tty_closing) {
-                       if (waitqueue_active(&o_tty->read_wait)) {
-                               wake_up_poll(&o_tty->read_wait, POLLIN);
-                               do_sleep++;
-                       }
-                       if (waitqueue_active(&o_tty->write_wait)) {
-                               wake_up_poll(&o_tty->write_wait, POLLOUT);
-                               do_sleep++;
-                       }
-               }
-               if (!do_sleep)
-                       break;
-
-               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
-                                   "active!\n", tty_name(tty, buf));
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               schedule();
-       }
-
-       /*
-        * The closing flags are now consistent with the open counts on
-        * both sides, and we've completed the last operation that could
-        * block, so it's safe to proceed with closing.
-        */
-       if (pty_master) {
-               if (--o_tty->count < 0) {
-                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
-                                           "(%d) for %s\n",
-                              o_tty->count, tty_name(o_tty, buf));
-                       o_tty->count = 0;
-               }
-       }
-       if (--tty->count < 0) {
-               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
-                      tty->count, tty_name(tty, buf));
-               tty->count = 0;
-       }
-
-       /*
-        * We've decremented tty->count, so we need to remove this file
-        * descriptor off the tty->tty_files list; this serves two
-        * purposes:
-        *  - check_tty_count sees the correct number of file descriptors
-        *    associated with this tty.
-        *  - do_tty_hangup no longer sees this file descriptor as
-        *    something that needs to be handled for hangups.
-        */
-       tty_del_file(filp);
-
-       /*
-        * Perform some housekeeping before deciding whether to return.
-        *
-        * Set the TTY_CLOSING flag if this was the last open.  In the
-        * case of a pty we may have to wait around for the other side
-        * to close, and TTY_CLOSING makes sure we can't be reopened.
-        */
-       if (tty_closing)
-               set_bit(TTY_CLOSING, &tty->flags);
-       if (o_tty_closing)
-               set_bit(TTY_CLOSING, &o_tty->flags);
-
-       /*
-        * If _either_ side is closing, make sure there aren't any
-        * processes that still think tty or o_tty is their controlling
-        * tty.
-        */
-       if (tty_closing || o_tty_closing) {
-               read_lock(&tasklist_lock);
-               session_clear_tty(tty->session);
-               if (o_tty)
-                       session_clear_tty(o_tty->session);
-               read_unlock(&tasklist_lock);
-       }
-
-       mutex_unlock(&tty_mutex);
-
-       /* check whether both sides are closing ... */
-       if (!tty_closing || (o_tty && !o_tty_closing)) {
-               tty_unlock();
-               return 0;
-       }
-
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "freeing tty structure...");
-#endif
-       /*
-        * Ask the line discipline code to release its structures
-        */
-       tty_ldisc_release(tty, o_tty);
-       /*
-        * The release_tty function takes care of the details of clearing
-        * the slots and preserving the termios structure.
-        */
-       release_tty(tty, idx);
-
-       /* Make this pty number available for reallocation */
-       if (devpts)
-               devpts_kill_index(inode, idx);
-       tty_unlock();
-       return 0;
-}
-
-/**
- *     tty_open                -       open a tty device
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     tty_open and tty_release keep up the tty count that contains the
- *     number of opens done on a tty. We cannot use the inode-count, as
- *     different inodes might point to the same tty.
- *
- *     Open-counting is needed for pty masters, as well as for keeping
- *     track of serial lines: DTR is dropped when the last close happens.
- *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
- *
- *     The termios state of a pty is reset on first open so that
- *     settings don't persist across reuse.
- *
- *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
- *              tty->count should protect the rest.
- *              ->siglock protects ->signal/->sighand
- */
-
-static int tty_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty = NULL;
-       int noctty, retval;
-       struct tty_driver *driver;
-       int index;
-       dev_t device = inode->i_rdev;
-       unsigned saved_flags = filp->f_flags;
-
-       nonseekable_open(inode, filp);
-
-retry_open:
-       noctty = filp->f_flags & O_NOCTTY;
-       index  = -1;
-       retval = 0;
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-
-       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
-               tty = get_current_tty();
-               if (!tty) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       return -ENXIO;
-               }
-               driver = tty_driver_kref_get(tty->driver);
-               index = tty->index;
-               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-               /* noctty = 1; */
-               /* FIXME: Should we take a driver reference ? */
-               tty_kref_put(tty);
-               goto got_driver;
-       }
-#ifdef CONFIG_VT
-       if (device == MKDEV(TTY_MAJOR, 0)) {
-               extern struct tty_driver *console_driver;
-               driver = tty_driver_kref_get(console_driver);
-               index = fg_console;
-               noctty = 1;
-               goto got_driver;
-       }
-#endif
-       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-               struct tty_driver *console_driver = console_device(&index);
-               if (console_driver) {
-                       driver = tty_driver_kref_get(console_driver);
-                       if (driver) {
-                               /* Don't let /dev/console block */
-                               filp->f_flags |= O_NONBLOCK;
-                               noctty = 1;
-                               goto got_driver;
-                       }
-               }
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               return -ENODEV;
-       }
-
-       driver = get_tty_driver(device, &index);
-       if (!driver) {
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               return -ENODEV;
-       }
-got_driver:
-       if (!tty) {
-               /* check whether we're reopening an existing tty */
-               tty = tty_driver_lookup_tty(driver, inode, index);
-
-               if (IS_ERR(tty)) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       return PTR_ERR(tty);
-               }
-       }
-
-       if (tty) {
-               retval = tty_reopen(tty);
-               if (retval)
-                       tty = ERR_PTR(retval);
-       } else
-               tty = tty_init_dev(driver, index, 0);
-
-       mutex_unlock(&tty_mutex);
-       tty_driver_kref_put(driver);
-       if (IS_ERR(tty)) {
-               tty_unlock();
-               return PTR_ERR(tty);
-       }
-
-       retval = tty_add_file(tty, filp);
-       if (retval) {
-               tty_unlock();
-               return retval;
-       }
-
-       check_tty_count(tty, "tty_open");
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "opening %s...", tty->name);
-#endif
-       if (!retval) {
-               if (tty->ops->open)
-                       retval = tty->ops->open(tty, filp);
-               else
-                       retval = -ENODEV;
-       }
-       filp->f_flags = saved_flags;
-
-       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
-                                               !capable(CAP_SYS_ADMIN))
-               retval = -EBUSY;
-
-       if (retval) {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error %d in opening %s...", retval,
-                      tty->name);
-#endif
-               tty_unlock(); /* need to call tty_release without BTM */
-               tty_release(inode, filp);
-               if (retval != -ERESTARTSYS)
-                       return retval;
-
-               if (signal_pending(current))
-                       return retval;
-
-               schedule();
-               /*
-                * Need to reset f_op in case a hangup happened.
-                */
-               tty_lock();
-               if (filp->f_op == &hung_up_tty_fops)
-                       filp->f_op = &tty_fops;
-               tty_unlock();
-               goto retry_open;
-       }
-       tty_unlock();
-
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-       spin_lock_irq(&current->sighand->siglock);
-       if (!noctty &&
-           current->signal->leader &&
-           !current->signal->tty &&
-           tty->session == NULL)
-               __proc_set_tty(current, tty);
-       spin_unlock_irq(&current->sighand->siglock);
-       tty_unlock();
-       mutex_unlock(&tty_mutex);
-       return 0;
-}
-
-
-
-/**
- *     tty_poll        -       check tty status
- *     @filp: file being polled
- *     @wait: poll wait structures to update
- *
- *     Call the line discipline polling method to obtain the poll
- *     status of the device.
- *
- *     Locking: locks called line discipline but ldisc poll method
- *     may be re-entered freely by other callers.
- */
-
-static unsigned int tty_poll(struct file *filp, poll_table *wait)
-{
-       struct tty_struct *tty = file_tty(filp);
-       struct tty_ldisc *ld;
-       int ret = 0;
-
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
-               return 0;
-
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->poll)
-               ret = (ld->ops->poll)(tty, filp, wait);
-       tty_ldisc_deref(ld);
-       return ret;
-}
-
-static int __tty_fasync(int fd, struct file *filp, int on)
-{
-       struct tty_struct *tty = file_tty(filp);
-       unsigned long flags;
-       int retval = 0;
-
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
-               goto out;
-
-       retval = fasync_helper(fd, filp, on, &tty->fasync);
-       if (retval <= 0)
-               goto out;
-
-       if (on) {
-               enum pid_type type;
-               struct pid *pid;
-               if (!waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = 1;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               if (tty->pgrp) {
-                       pid = tty->pgrp;
-                       type = PIDTYPE_PGID;
-               } else {
-                       pid = task_pid(current);
-                       type = PIDTYPE_PID;
-               }
-               get_pid(pid);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               retval = __f_setown(filp, pid, type, 0);
-               put_pid(pid);
-               if (retval)
-                       goto out;
-       } else {
-               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
-       }
-       retval = 0;
-out:
-       return retval;
-}
-
-static int tty_fasync(int fd, struct file *filp, int on)
-{
-       int retval;
-       tty_lock();
-       retval = __tty_fasync(fd, filp, on);
-       tty_unlock();
-       return retval;
-}
-
-/**
- *     tiocsti                 -       fake input character
- *     @tty: tty to fake input into
- *     @p: pointer to character
- *
- *     Fake input to a tty device. Does the necessary locking and
- *     input management.
- *
- *     FIXME: does not honour flow control ??
- *
- *     Locking:
- *             Called functions take tty_ldisc_lock
- *             current->signal->tty check is safe without locks
- *
- *     FIXME: may race normal receive processing
- */
-
-static int tiocsti(struct tty_struct *tty, char __user *p)
-{
-       char ch, mbz = 0;
-       struct tty_ldisc *ld;
-
-       if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (get_user(ch, p))
-               return -EFAULT;
-       tty_audit_tiocsti(tty, ch);
-       ld = tty_ldisc_ref_wait(tty);
-       ld->ops->receive_buf(tty, &ch, &mbz, 1);
-       tty_ldisc_deref(ld);
-       return 0;
-}
-
-/**
- *     tiocgwinsz              -       implement window query ioctl
- *     @tty; tty
- *     @arg: user buffer for result
- *
- *     Copies the kernel idea of the window size into the user buffer.
- *
- *     Locking: tty->termios_mutex is taken to ensure the winsize data
- *             is consistent.
- */
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-       int err;
-
-       mutex_lock(&tty->termios_mutex);
-       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-       mutex_unlock(&tty->termios_mutex);
-
-       return err ? -EFAULT: 0;
-}
-
-/**
- *     tty_do_resize           -       resize event
- *     @tty: tty being resized
- *     @rows: rows (character)
- *     @cols: cols (character)
- *
- *     Update the termios variables and send the necessary signals to
- *     peform a terminal resize correctly
- */
-
-int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
-{
-       struct pid *pgrp;
-       unsigned long flags;
-
-       /* Lock the tty */
-       mutex_lock(&tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-               goto done;
-       /* Get the PID values and reference them so we can
-          avoid holding the tty ctrl lock while sending signals */
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       if (pgrp)
-               kill_pgrp(pgrp, SIGWINCH, 1);
-       put_pid(pgrp);
-
-       tty->winsize = *ws;
-done:
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-/**
- *     tiocswinsz              -       implement window size set ioctl
- *     @tty; tty side of tty
- *     @arg: user buffer for result
- *
- *     Copies the user idea of the window size to the kernel. Traditionally
- *     this is just advisory information but for the Linux console it
- *     actually has driver level meaning and triggers a VC resize.
- *
- *     Locking:
- *             Driver dependant. The default do_resize method takes the
- *     tty termios mutex and ctrl_lock. The console takes its own lock
- *     then calls into the default method.
- */
-
-static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-       struct winsize tmp_ws;
-       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
-               return -EFAULT;
-
-       if (tty->ops->resize)
-               return tty->ops->resize(tty, &tmp_ws);
-       else
-               return tty_do_resize(tty, &tmp_ws);
-}
-
-/**
- *     tioccons        -       allow admin to move logical console
- *     @file: the file to become console
- *
- *     Allow the adminstrator to move the redirected console device
- *
- *     Locking: uses redirect_lock to guard the redirect information
- */
-
-static int tioccons(struct file *file)
-{
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (file->f_op->write == redirected_tty_write) {
-               struct file *f;
-               spin_lock(&redirect_lock);
-               f = redirect;
-               redirect = NULL;
-               spin_unlock(&redirect_lock);
-               if (f)
-                       fput(f);
-               return 0;
-       }
-       spin_lock(&redirect_lock);
-       if (redirect) {
-               spin_unlock(&redirect_lock);
-               return -EBUSY;
-       }
-       get_file(file);
-       redirect = file;
-       spin_unlock(&redirect_lock);
-       return 0;
-}
-
-/**
- *     fionbio         -       non blocking ioctl
- *     @file: file to set blocking value
- *     @p: user parameter
- *
- *     Historical tty interfaces had a blocking control ioctl before
- *     the generic functionality existed. This piece of history is preserved
- *     in the expected tty API of posix OS's.
- *
- *     Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
-       int nonblock;
-
-       if (get_user(nonblock, p))
-               return -EFAULT;
-
-       spin_lock(&file->f_lock);
-       if (nonblock)
-               file->f_flags |= O_NONBLOCK;
-       else
-               file->f_flags &= ~O_NONBLOCK;
-       spin_unlock(&file->f_lock);
-       return 0;
-}
-
-/**
- *     tiocsctty       -       set controlling tty
- *     @tty: tty structure
- *     @arg: user argument
- *
- *     This ioctl is used to manage job control. It permits a session
- *     leader to set this tty as the controlling tty for the session.
- *
- *     Locking:
- *             Takes tty_mutex() to protect tty instance
- *             Takes tasklist_lock internally to walk sessions
- *             Takes ->siglock() when updating signal->tty
- */
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
-       int ret = 0;
-       if (current->signal->leader && (task_session(current) == tty->session))
-               return ret;
-
-       mutex_lock(&tty_mutex);
-       /*
-        * The process must be a session leader and
-        * not have a controlling tty already.
-        */
-       if (!current->signal->leader || current->signal->tty) {
-               ret = -EPERM;
-               goto unlock;
-       }
-
-       if (tty->session) {
-               /*
-                * This tty is already the controlling
-                * tty for another session group!
-                */
-               if (arg == 1 && capable(CAP_SYS_ADMIN)) {
-                       /*
-                        * Steal it away
-                        */
-                       read_lock(&tasklist_lock);
-                       session_clear_tty(tty->session);
-                       read_unlock(&tasklist_lock);
-               } else {
-                       ret = -EPERM;
-                       goto unlock;
-               }
-       }
-       proc_set_tty(current, tty);
-unlock:
-       mutex_unlock(&tty_mutex);
-       return ret;
-}
-
-/**
- *     tty_get_pgrp    -       return a ref counted pgrp pid
- *     @tty: tty to read
- *
- *     Returns a refcounted instance of the pid struct for the process
- *     group controlling the tty.
- */
-
-struct pid *tty_get_pgrp(struct tty_struct *tty)
-{
-       unsigned long flags;
-       struct pid *pgrp;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       return pgrp;
-}
-EXPORT_SYMBOL_GPL(tty_get_pgrp);
-
-/**
- *     tiocgpgrp               -       get process group
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: returned pid
- *
- *     Obtain the process group of the tty. If there is no process group
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       struct pid *pid;
-       int ret;
-       /*
-        * (tty == real_tty) is a cheap way of
-        * testing if the tty is NOT a master pty.
-        */
-       if (tty == real_tty && current->signal->tty != real_tty)
-               return -ENOTTY;
-       pid = tty_get_pgrp(real_tty);
-       ret =  put_user(pid_vnr(pid), p);
-       put_pid(pid);
-       return ret;
-}
-
-/**
- *     tiocspgrp               -       attempt to set process group
- *     @tty: tty passed by user
- *     @real_tty: tty side device matching tty passed by user
- *     @p: pid pointer
- *
- *     Set the process group of the tty to the session passed. Only
- *     permitted where the tty session is our session.
- *
- *     Locking: RCU, ctrl lock
- */
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       struct pid *pgrp;
-       pid_t pgrp_nr;
-       int retval = tty_check_change(real_tty);
-       unsigned long flags;
-
-       if (retval == -EIO)
-               return -ENOTTY;
-       if (retval)
-               return retval;
-       if (!current->signal->tty ||
-           (current->signal->tty != real_tty) ||
-           (real_tty->session != task_session(current)))
-               return -ENOTTY;
-       if (get_user(pgrp_nr, p))
-               return -EFAULT;
-       if (pgrp_nr < 0)
-               return -EINVAL;
-       rcu_read_lock();
-       pgrp = find_vpid(pgrp_nr);
-       retval = -ESRCH;
-       if (!pgrp)
-               goto out_unlock;
-       retval = -EPERM;
-       if (session_of_pgrp(pgrp) != task_session(current))
-               goto out_unlock;
-       retval = 0;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       put_pid(real_tty->pgrp);
-       real_tty->pgrp = get_pid(pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_unlock:
-       rcu_read_unlock();
-       return retval;
-}
-
-/**
- *     tiocgsid                -       get session id
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: pointer to returned session id
- *
- *     Obtain the session id of the tty. If there is no session
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       /*
-        * (tty == real_tty) is a cheap way of
-        * testing if the tty is NOT a master pty.
-       */
-       if (tty == real_tty && current->signal->tty != real_tty)
-               return -ENOTTY;
-       if (!real_tty->session)
-               return -ENOTTY;
-       return put_user(pid_vnr(real_tty->session), p);
-}
-
-/**
- *     tiocsetd        -       set line discipline
- *     @tty: tty device
- *     @p: pointer to user data
- *
- *     Set the line discipline according to user request.
- *
- *     Locking: see tty_set_ldisc, this function is just a helper
- */
-
-static int tiocsetd(struct tty_struct *tty, int __user *p)
-{
-       int ldisc;
-       int ret;
-
-       if (get_user(ldisc, p))
-               return -EFAULT;
-
-       ret = tty_set_ldisc(tty, ldisc);
-
-       return ret;
-}
-
-/**
- *     send_break      -       performed time break
- *     @tty: device to break on
- *     @duration: timeout in mS
- *
- *     Perform a timed break on hardware that lacks its own driver level
- *     timed break functionality.
- *
- *     Locking:
- *             atomic_write_lock serializes
- *
- */
-
-static int send_break(struct tty_struct *tty, unsigned int duration)
-{
-       int retval;
-
-       if (tty->ops->break_ctl == NULL)
-               return 0;
-
-       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
-               retval = tty->ops->break_ctl(tty, duration);
-       else {
-               /* Do the work ourselves */
-               if (tty_write_lock(tty, 0) < 0)
-                       return -EINTR;
-               retval = tty->ops->break_ctl(tty, -1);
-               if (retval)
-                       goto out;
-               if (!signal_pending(current))
-                       msleep_interruptible(duration);
-               retval = tty->ops->break_ctl(tty, 0);
-out:
-               tty_write_unlock(tty);
-               if (signal_pending(current))
-                       retval = -EINTR;
-       }
-       return retval;
-}
-
-/**
- *     tty_tiocmget            -       get modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @p: pointer to result
- *
- *     Obtain the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
-{
-       int retval = -EINVAL;
-
-       if (tty->ops->tiocmget) {
-               retval = tty->ops->tiocmget(tty, file);
-
-               if (retval >= 0)
-                       retval = put_user(retval, p);
-       }
-       return retval;
-}
-
-/**
- *     tty_tiocmset            -       set modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @cmd: command - clear bits, set bits or set all
- *     @p: pointer to desired bits
- *
- *     Set the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
-            unsigned __user *p)
-{
-       int retval;
-       unsigned int set, clear, val;
-
-       if (tty->ops->tiocmset == NULL)
-               return -EINVAL;
-
-       retval = get_user(val, p);
-       if (retval)
-               return retval;
-       set = clear = 0;
-       switch (cmd) {
-       case TIOCMBIS:
-               set = val;
-               break;
-       case TIOCMBIC:
-               clear = val;
-               break;
-       case TIOCMSET:
-               set = val;
-               clear = ~val;
-               break;
-       }
-       set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-       clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-       return tty->ops->tiocmset(tty, file, set, clear);
-}
-
-static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
-{
-       int retval = -EINVAL;
-       struct serial_icounter_struct icount;
-       memset(&icount, 0, sizeof(icount));
-       if (tty->ops->get_icount)
-               retval = tty->ops->get_icount(tty, &icount);
-       if (retval != 0)
-               return retval;
-       if (copy_to_user(arg, &icount, sizeof(icount)))
-               return -EFAULT;
-       return 0;
-}
-
-struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
-{
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               tty = tty->link;
-       return tty;
-}
-EXPORT_SYMBOL(tty_pair_get_tty);
-
-struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
-{
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-           return tty;
-       return tty->link;
-}
-EXPORT_SYMBOL(tty_pair_get_pty);
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct tty_struct *tty = file_tty(file);
-       struct tty_struct *real_tty;
-       void __user *p = (void __user *)arg;
-       int retval;
-       struct tty_ldisc *ld;
-       struct inode *inode = file->f_dentry->d_inode;
-
-       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-               return -EINVAL;
-
-       real_tty = tty_pair_get_tty(tty);
-
-       /*
-        * Factor out some common prep work
-        */
-       switch (cmd) {
-       case TIOCSETD:
-       case TIOCSBRK:
-       case TIOCCBRK:
-       case TCSBRK:
-       case TCSBRKP:
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               if (cmd != TIOCCBRK) {
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-               }
-               break;
-       }
-
-       /*
-        *      Now do the stuff.
-        */
-       switch (cmd) {
-       case TIOCSTI:
-               return tiocsti(tty, p);
-       case TIOCGWINSZ:
-               return tiocgwinsz(real_tty, p);
-       case TIOCSWINSZ:
-               return tiocswinsz(real_tty, p);
-       case TIOCCONS:
-               return real_tty != tty ? -EINVAL : tioccons(file);
-       case FIONBIO:
-               return fionbio(file, p);
-       case TIOCEXCL:
-               set_bit(TTY_EXCLUSIVE, &tty->flags);
-               return 0;
-       case TIOCNXCL:
-               clear_bit(TTY_EXCLUSIVE, &tty->flags);
-               return 0;
-       case TIOCNOTTY:
-               if (current->signal->tty != tty)
-                       return -ENOTTY;
-               no_tty();
-               return 0;
-       case TIOCSCTTY:
-               return tiocsctty(tty, arg);
-       case TIOCGPGRP:
-               return tiocgpgrp(tty, real_tty, p);
-       case TIOCSPGRP:
-               return tiocspgrp(tty, real_tty, p);
-       case TIOCGSID:
-               return tiocgsid(tty, real_tty, p);
-       case TIOCGETD:
-               return put_user(tty->ldisc->ops->num, (int __user *)p);
-       case TIOCSETD:
-               return tiocsetd(tty, p);
-       /*
-        * Break handling
-        */
-       case TIOCSBRK:  /* Turn break on, unconditionally */
-               if (tty->ops->break_ctl)
-                       return tty->ops->break_ctl(tty, -1);
-               return 0;
-       case TIOCCBRK:  /* Turn break off, unconditionally */
-               if (tty->ops->break_ctl)
-                       return tty->ops->break_ctl(tty, 0);
-               return 0;
-       case TCSBRK:   /* SVID version: non-zero arg --> no break */
-               /* non-zero arg means wait for all output data
-                * to be sent (performed above) but don't send break.
-                * This is used by the tcdrain() termios function.
-                */
-               if (!arg)
-                       return send_break(tty, 250);
-               return 0;
-       case TCSBRKP:   /* support for POSIX tcsendbreak() */
-               return send_break(tty, arg ? arg*100 : 250);
-
-       case TIOCMGET:
-               return tty_tiocmget(tty, file, p);
-       case TIOCMSET:
-       case TIOCMBIC:
-       case TIOCMBIS:
-               return tty_tiocmset(tty, file, cmd, p);
-       case TIOCGICOUNT:
-               retval = tty_tiocgicount(tty, p);
-               /* For the moment allow fall through to the old method */
-               if (retval != -EINVAL)
-                       return retval;
-               break;
-       case TCFLSH:
-               switch (arg) {
-               case TCIFLUSH:
-               case TCIOFLUSH:
-               /* flush tty buffer and allow ldisc to process ioctl */
-                       tty_buffer_flush(tty);
-                       break;
-               }
-               break;
-       }
-       if (tty->ops->ioctl) {
-               retval = (tty->ops->ioctl)(tty, file, cmd, arg);
-               if (retval != -ENOIOCTLCMD)
-                       return retval;
-       }
-       ld = tty_ldisc_ref_wait(tty);
-       retval = -EINVAL;
-       if (ld->ops->ioctl) {
-               retval = ld->ops->ioctl(tty, file, cmd, arg);
-               if (retval == -ENOIOCTLCMD)
-                       retval = -EINVAL;
-       }
-       tty_ldisc_deref(ld);
-       return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct inode *inode = file->f_dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-       int retval = -ENOIOCTLCMD;
-
-       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-               return -EINVAL;
-
-       if (tty->ops->compat_ioctl) {
-               retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
-               if (retval != -ENOIOCTLCMD)
-                       return retval;
-       }
-
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->compat_ioctl)
-               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
-       tty_ldisc_deref(ld);
-
-       return retval;
-}
-#endif
-
-/*
- * This implements the "Secure Attention Key" ---  the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key".  Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal.  But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context.  This can
- * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
- */
-void __do_SAK(struct tty_struct *tty)
-{
-#ifdef TTY_SOFT_SAK
-       tty_hangup(tty);
-#else
-       struct task_struct *g, *p;
-       struct pid *session;
-       int             i;
-       struct file     *filp;
-       struct fdtable *fdt;
-
-       if (!tty)
-               return;
-       session = tty->session;
-
-       tty_ldisc_flush(tty);
-
-       tty_driver_flush_buffer(tty);
-
-       read_lock(&tasklist_lock);
-       /* Kill the entire session */
-       do_each_pid_task(session, PIDTYPE_SID, p) {
-               printk(KERN_NOTICE "SAK: killed process %d"
-                       " (%s): task_session(p)==tty->session\n",
-                       task_pid_nr(p), p->comm);
-               send_sig(SIGKILL, p, 1);
-       } while_each_pid_task(session, PIDTYPE_SID, p);
-       /* Now kill any processes that happen to have the
-        * tty open.
-        */
-       do_each_thread(g, p) {
-               if (p->signal->tty == tty) {
-                       printk(KERN_NOTICE "SAK: killed process %d"
-                           " (%s): task_session(p)==tty->session\n",
-                           task_pid_nr(p), p->comm);
-                       send_sig(SIGKILL, p, 1);
-                       continue;
-               }
-               task_lock(p);
-               if (p->files) {
-                       /*
-                        * We don't take a ref to the file, so we must
-                        * hold ->file_lock instead.
-                        */
-                       spin_lock(&p->files->file_lock);
-                       fdt = files_fdtable(p->files);
-                       for (i = 0; i < fdt->max_fds; i++) {
-                               filp = fcheck_files(p->files, i);
-                               if (!filp)
-                                       continue;
-                               if (filp->f_op->read == tty_read &&
-                                   file_tty(filp) == tty) {
-                                       printk(KERN_NOTICE "SAK: killed process %d"
-                                           " (%s): fd#%d opened to the tty\n",
-                                           task_pid_nr(p), p->comm, i);
-                                       force_sig(SIGKILL, p);
-                                       break;
-                               }
-                       }
-                       spin_unlock(&p->files->file_lock);
-               }
-               task_unlock(p);
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
-#endif
-}
-
-static void do_SAK_work(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, SAK_work);
-       __do_SAK(tty);
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_work may already be queued.
- * Fortunately we don't need to worry, because if ->SAK_work is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
-       if (!tty)
-               return;
-       schedule_work(&tty->SAK_work);
-}
-
-EXPORT_SYMBOL(do_SAK);
-
-static int dev_match_devt(struct device *dev, void *data)
-{
-       dev_t *devt = data;
-       return dev->devt == *devt;
-}
-
-/* Must put_device() after it's unused! */
-static struct device *tty_get_device(struct tty_struct *tty)
-{
-       dev_t devt = tty_devnum(tty);
-       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
-}
-
-
-/**
- *     initialize_tty_struct
- *     @tty: tty to initialize
- *
- *     This subroutine initializes a tty structure that has been newly
- *     allocated.
- *
- *     Locking: none - tty in question must not be exposed at this point
- */
-
-void initialize_tty_struct(struct tty_struct *tty,
-               struct tty_driver *driver, int idx)
-{
-       memset(tty, 0, sizeof(struct tty_struct));
-       kref_init(&tty->kref);
-       tty->magic = TTY_MAGIC;
-       tty_ldisc_init(tty);
-       tty->session = NULL;
-       tty->pgrp = NULL;
-       tty->overrun_time = jiffies;
-       tty->buf.head = tty->buf.tail = NULL;
-       tty_buffer_init(tty);
-       mutex_init(&tty->termios_mutex);
-       mutex_init(&tty->ldisc_mutex);
-       init_waitqueue_head(&tty->write_wait);
-       init_waitqueue_head(&tty->read_wait);
-       INIT_WORK(&tty->hangup_work, do_tty_hangup);
-       mutex_init(&tty->atomic_read_lock);
-       mutex_init(&tty->atomic_write_lock);
-       mutex_init(&tty->output_lock);
-       mutex_init(&tty->echo_lock);
-       spin_lock_init(&tty->read_lock);
-       spin_lock_init(&tty->ctrl_lock);
-       INIT_LIST_HEAD(&tty->tty_files);
-       INIT_WORK(&tty->SAK_work, do_SAK_work);
-
-       tty->driver = driver;
-       tty->ops = driver->ops;
-       tty->index = idx;
-       tty_line_name(driver, idx, tty->name);
-       tty->dev = tty_get_device(tty);
-}
-
-/**
- *     tty_put_char    -       write one character to a tty
- *     @tty: tty
- *     @ch: character
- *
- *     Write one byte to the tty using the provided put_char method
- *     if present. Returns the number of characters successfully output.
- *
- *     Note: the specific put_char operation in the driver layer may go
- *     away soon. Don't call it directly, use this method
- */
-
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       if (tty->ops->put_char)
-               return tty->ops->put_char(tty, ch);
-       return tty->ops->write(tty, &ch, 1);
-}
-EXPORT_SYMBOL_GPL(tty_put_char);
-
-struct class *tty_class;
-
-/**
- *     tty_register_device - register a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *     @device: a struct device that is associated with this tty device.
- *             This field is optional, if there is no known struct device
- *             for this tty device it can be set to NULL safely.
- *
- *     Returns a pointer to the struct device for this tty device
- *     (or ERR_PTR(-EFOO) on error).
- *
- *     This call is required to be made to register an individual tty device
- *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
- *     that bit is not set, this function should not be called by a tty
- *     driver.
- *
- *     Locking: ??
- */
-
-struct device *tty_register_device(struct tty_driver *driver, unsigned index,
-                                  struct device *device)
-{
-       char name[64];
-       dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-
-       if (index >= driver->num) {
-               printk(KERN_ERR "Attempt to register invalid tty line number "
-                      " (%d).\n", index);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY)
-               pty_line_name(driver, index, name);
-       else
-               tty_line_name(driver, index, name);
-
-       return device_create(tty_class, device, dev, NULL, name);
-}
-EXPORT_SYMBOL(tty_register_device);
-
-/**
- *     tty_unregister_device - unregister a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *
- *     If a tty device is registered with a call to tty_register_device() then
- *     this function must be called when the tty device is gone.
- *
- *     Locking: ??
- */
-
-void tty_unregister_device(struct tty_driver *driver, unsigned index)
-{
-       device_destroy(tty_class,
-               MKDEV(driver->major, driver->minor_start) + index);
-}
-EXPORT_SYMBOL(tty_unregister_device);
-
-struct tty_driver *alloc_tty_driver(int lines)
-{
-       struct tty_driver *driver;
-
-       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
-       if (driver) {
-               kref_init(&driver->kref);
-               driver->magic = TTY_DRIVER_MAGIC;
-               driver->num = lines;
-               /* later we'll move allocation of tables here */
-       }
-       return driver;
-}
-EXPORT_SYMBOL(alloc_tty_driver);
-
-static void destruct_tty_driver(struct kref *kref)
-{
-       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
-       int i;
-       struct ktermios *tp;
-       void *p;
-
-       if (driver->flags & TTY_DRIVER_INSTALLED) {
-               /*
-                * Free the termios and termios_locked structures because
-                * we don't want to get memory leaks when modular tty
-                * drivers are removed from the kernel.
-                */
-               for (i = 0; i < driver->num; i++) {
-                       tp = driver->termios[i];
-                       if (tp) {
-                               driver->termios[i] = NULL;
-                               kfree(tp);
-                       }
-                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-                               tty_unregister_device(driver, i);
-               }
-               p = driver->ttys;
-               proc_tty_unregister_driver(driver);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               cdev_del(&driver->cdev);
-       }
-       kfree(driver);
-}
-
-void tty_driver_kref_put(struct tty_driver *driver)
-{
-       kref_put(&driver->kref, destruct_tty_driver);
-}
-EXPORT_SYMBOL(tty_driver_kref_put);
-
-void tty_set_operations(struct tty_driver *driver,
-                       const struct tty_operations *op)
-{
-       driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
-       tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
-       int error;
-       int i;
-       dev_t dev;
-       void **p = NULL;
-       struct device *d;
-
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
-               if (!p)
-                       return -ENOMEM;
-       }
-
-       if (!driver->major) {
-               error = alloc_chrdev_region(&dev, driver->minor_start,
-                                               driver->num, driver->name);
-               if (!error) {
-                       driver->major = MAJOR(dev);
-                       driver->minor_start = MINOR(dev);
-               }
-       } else {
-               dev = MKDEV(driver->major, driver->minor_start);
-               error = register_chrdev_region(dev, driver->num, driver->name);
-       }
-       if (error < 0) {
-               kfree(p);
-               return error;
-       }
-
-       if (p) {
-               driver->ttys = (struct tty_struct **)p;
-               driver->termios = (struct ktermios **)(p + driver->num);
-       } else {
-               driver->ttys = NULL;
-               driver->termios = NULL;
-       }
-
-       cdev_init(&driver->cdev, &tty_fops);
-       driver->cdev.owner = driver->owner;
-       error = cdev_add(&driver->cdev, dev, driver->num);
-       if (error) {
-               unregister_chrdev_region(dev, driver->num);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               return error;
-       }
-
-       mutex_lock(&tty_mutex);
-       list_add(&driver->tty_drivers, &tty_drivers);
-       mutex_unlock(&tty_mutex);
-
-       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-               for (i = 0; i < driver->num; i++) {
-                       d = tty_register_device(driver, i, NULL);
-                       if (IS_ERR(d)) {
-                               error = PTR_ERR(d);
-                               goto err;
-                       }
-               }
-       }
-       proc_tty_register_driver(driver);
-       driver->flags |= TTY_DRIVER_INSTALLED;
-       return 0;
-
-err:
-       for (i--; i >= 0; i--)
-               tty_unregister_device(driver, i);
-
-       mutex_lock(&tty_mutex);
-       list_del(&driver->tty_drivers);
-       mutex_unlock(&tty_mutex);
-
-       unregister_chrdev_region(dev, driver->num);
-       driver->ttys = NULL;
-       driver->termios = NULL;
-       kfree(p);
-       return error;
-}
-
-EXPORT_SYMBOL(tty_register_driver);
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
-#if 0
-       /* FIXME */
-       if (driver->refcount)
-               return -EBUSY;
-#endif
-       unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
-                               driver->num);
-       mutex_lock(&tty_mutex);
-       list_del(&driver->tty_drivers);
-       mutex_unlock(&tty_mutex);
-       return 0;
-}
-
-EXPORT_SYMBOL(tty_unregister_driver);
-
-dev_t tty_devnum(struct tty_struct *tty)
-{
-       return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-EXPORT_SYMBOL(tty_devnum);
-
-void proc_clear_tty(struct task_struct *p)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-       spin_lock_irqsave(&p->sighand->siglock, flags);
-       tty = p->signal->tty;
-       p->signal->tty = NULL;
-       spin_unlock_irqrestore(&p->sighand->siglock, flags);
-       tty_kref_put(tty);
-}
-
-/* Called under the sighand lock */
-
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-       if (tty) {
-               unsigned long flags;
-               /* We should not have a session or pgrp to put here but.... */
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               put_pid(tty->session);
-               put_pid(tty->pgrp);
-               tty->pgrp = get_pid(task_pgrp(tsk));
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               tty->session = get_pid(task_session(tsk));
-               if (tsk->signal->tty) {
-                       printk(KERN_DEBUG "tty not NULL!!\n");
-                       tty_kref_put(tsk->signal->tty);
-               }
-       }
-       put_pid(tsk->signal->tty_old_pgrp);
-       tsk->signal->tty = tty_kref_get(tty);
-       tsk->signal->tty_old_pgrp = NULL;
-}
-
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-       spin_lock_irq(&tsk->sighand->siglock);
-       __proc_set_tty(tsk, tty);
-       spin_unlock_irq(&tsk->sighand->siglock);
-}
-
-struct tty_struct *get_current_tty(void)
-{
-       struct tty_struct *tty;
-       unsigned long flags;
-
-       spin_lock_irqsave(&current->sighand->siglock, flags);
-       tty = tty_kref_get(current->signal->tty);
-       spin_unlock_irqrestore(&current->sighand->siglock, flags);
-       return tty;
-}
-EXPORT_SYMBOL_GPL(get_current_tty);
-
-void tty_default_fops(struct file_operations *fops)
-{
-       *fops = tty_fops;
-}
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
-       initcall_t *call;
-
-       /* Setup the default TTY line discipline. */
-       tty_ldisc_begin();
-
-       /*
-        * set up the console device so that later boot sequences can
-        * inform about problems etc..
-        */
-       call = __con_initcall_start;
-       while (call < __con_initcall_end) {
-               (*call)();
-               call++;
-       }
-}
-
-static char *tty_devnode(struct device *dev, mode_t *mode)
-{
-       if (!mode)
-               return NULL;
-       if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
-           dev->devt == MKDEV(TTYAUX_MAJOR, 2))
-               *mode = 0666;
-       return NULL;
-}
-
-static int __init tty_class_init(void)
-{
-       tty_class = class_create(THIS_MODULE, "tty");
-       if (IS_ERR(tty_class))
-               return PTR_ERR(tty_class);
-       tty_class->devnode = tty_devnode;
-       return 0;
-}
-
-postcore_initcall(tty_class_init);
-
-/* 3/2004 jmc: why do these devices exist? */
-
-static struct cdev tty_cdev, console_cdev;
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-int __init tty_init(void)
-{
-       cdev_init(&tty_cdev, &tty_fops);
-       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
-               panic("Couldn't register /dev/tty driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
-                             "tty");
-
-       cdev_init(&console_cdev, &console_fops);
-       if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
-               panic("Couldn't register /dev/console driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
-                             "console");
-
-#ifdef CONFIG_VT
-       vty_init(&console_fops);
-#endif
-       return 0;
-}
-
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
deleted file mode 100644 (file)
index 0c18899..0000000
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*
- *  linux/drivers/char/tty_ioctl.c
- *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- */
-
-#include <linux/types.h>
-#include <linux/termios.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/tty.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#undef TTY_DEBUG_WAIT_UNTIL_SENT
-
-#undef DEBUG
-
-/*
- * Internal flag options for termios setting behavior
- */
-#define TERMIOS_FLUSH  1
-#define TERMIOS_WAIT   2
-#define TERMIOS_TERMIO 4
-#define TERMIOS_OLD    8
-
-
-/**
- *     tty_chars_in_buffer     -       characters pending
- *     @tty: terminal
- *
- *     Return the number of bytes of data in the device private
- *     output queue. If no private method is supplied there is assumed
- *     to be no queue on the device.
- */
-
-int tty_chars_in_buffer(struct tty_struct *tty)
-{
-       if (tty->ops->chars_in_buffer)
-               return tty->ops->chars_in_buffer(tty);
-       else
-               return 0;
-}
-EXPORT_SYMBOL(tty_chars_in_buffer);
-
-/**
- *     tty_write_room          -       write queue space
- *     @tty: terminal
- *
- *     Return the number of bytes that can be queued to this device
- *     at the present time. The result should be treated as a guarantee
- *     and the driver cannot offer a value it later shrinks by more than
- *     the number of bytes written. If no method is provided 2K is always
- *     returned and data may be lost as there will be no flow control.
- */
-int tty_write_room(struct tty_struct *tty)
-{
-       if (tty->ops->write_room)
-               return tty->ops->write_room(tty);
-       return 2048;
-}
-EXPORT_SYMBOL(tty_write_room);
-
-/**
- *     tty_driver_flush_buffer -       discard internal buffer
- *     @tty: terminal
- *
- *     Discard the internal output buffer for this device. If no method
- *     is provided then either the buffer cannot be hardware flushed or
- *     there is no buffer driver side.
- */
-void tty_driver_flush_buffer(struct tty_struct *tty)
-{
-       if (tty->ops->flush_buffer)
-               tty->ops->flush_buffer(tty);
-}
-EXPORT_SYMBOL(tty_driver_flush_buffer);
-
-/**
- *     tty_throttle            -       flow control
- *     @tty: terminal
- *
- *     Indicate that a tty should stop transmitting data down the stack.
- *     Takes the termios mutex to protect against parallel throttle/unthrottle
- *     and also to ensure the driver can consistently reference its own
- *     termios data at this point when implementing software flow control.
- */
-
-void tty_throttle(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       /* check TTY_THROTTLED first so it indicates our state */
-       if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
-           tty->ops->throttle)
-               tty->ops->throttle(tty);
-       mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_throttle);
-
-/**
- *     tty_unthrottle          -       flow control
- *     @tty: terminal
- *
- *     Indicate that a tty may continue transmitting data down the stack.
- *     Takes the termios mutex to protect against parallel throttle/unthrottle
- *     and also to ensure the driver can consistently reference its own
- *     termios data at this point when implementing software flow control.
- *
- *     Drivers should however remember that the stack can issue a throttle,
- *     then change flow control method, then unthrottle.
- */
-
-void tty_unthrottle(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
-           tty->ops->unthrottle)
-               tty->ops->unthrottle(tty);
-       mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_unthrottle);
-
-/**
- *     tty_wait_until_sent     -       wait for I/O to finish
- *     @tty: tty we are waiting for
- *     @timeout: how long we will wait
- *
- *     Wait for characters pending in a tty driver to hit the wire, or
- *     for a timeout to occur (eg due to flow control)
- *
- *     Locking: none
- */
-
-void tty_wait_until_sent(struct tty_struct *tty, long timeout)
-{
-#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
-       char buf[64];
-
-       printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
-#endif
-       if (!timeout)
-               timeout = MAX_SCHEDULE_TIMEOUT;
-       if (wait_event_interruptible_timeout(tty->write_wait,
-                       !tty_chars_in_buffer(tty), timeout) >= 0) {
-               if (tty->ops->wait_until_sent)
-                       tty->ops->wait_until_sent(tty, timeout);
-       }
-}
-EXPORT_SYMBOL(tty_wait_until_sent);
-
-
-/*
- *             Termios Helper Methods
- */
-
-static void unset_locked_termios(struct ktermios *termios,
-                                struct ktermios *old,
-                                struct ktermios *locked)
-{
-       int     i;
-
-#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
-
-       if (!locked) {
-               printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
-               return;
-       }
-
-       NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
-       NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
-       NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
-       NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
-       termios->c_line = locked->c_line ? old->c_line : termios->c_line;
-       for (i = 0; i < NCCS; i++)
-               termios->c_cc[i] = locked->c_cc[i] ?
-                       old->c_cc[i] : termios->c_cc[i];
-       /* FIXME: What should we do for i/ospeed */
-}
-
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static const speed_t baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
-       76800, 153600, 307200, 614400, 921600
-#else
-       500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
-       2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-#ifndef __sparc__
-static const tcflag_t baud_bits[] = {
-       B0, B50, B75, B110, B134, B150, B200, B300, B600,
-       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-       B57600, B115200, B230400, B460800, B500000, B576000,
-       B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
-       B3000000, B3500000, B4000000
-};
-#else
-static const tcflag_t baud_bits[] = {
-       B0, B50, B75, B110, B134, B150, B200, B300, B600,
-       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-       B57600, B115200, B230400, B460800, B76800, B153600,
-       B307200, B614400, B921600
-};
-#endif
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- *     tty_termios_baud_rate
- *     @termios: termios structure
- *
- *     Convert termios baud rate data into a speed. This should be called
- *     with the termios lock held if this termios is a terminal termios
- *     structure. May change the termios data. Device drivers can call this
- *     function but should use ->c_[io]speed directly as they are updated.
- *
- *     Locking: none
- */
-
-speed_t tty_termios_baud_rate(struct ktermios *termios)
-{
-       unsigned int cbaud;
-
-       cbaud = termios->c_cflag & CBAUD;
-
-#ifdef BOTHER
-       /* Magic token for arbitary speed via c_ispeed/c_ospeed */
-       if (cbaud == BOTHER)
-               return termios->c_ospeed;
-#endif
-       if (cbaud & CBAUDEX) {
-               cbaud &= ~CBAUDEX;
-
-               if (cbaud < 1 || cbaud + 15 > n_baud_table)
-                       termios->c_cflag &= ~CBAUDEX;
-               else
-                       cbaud += 15;
-       }
-       return baud_table[cbaud];
-}
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- *     tty_termios_input_baud_rate
- *     @termios: termios structure
- *
- *     Convert termios baud rate data into a speed. This should be called
- *     with the termios lock held if this termios is a terminal termios
- *     structure. May change the termios data. Device drivers can call this
- *     function but should use ->c_[io]speed directly as they are updated.
- *
- *     Locking: none
- */
-
-speed_t tty_termios_input_baud_rate(struct ktermios *termios)
-{
-#ifdef IBSHIFT
-       unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
-
-       if (cbaud == B0)
-               return tty_termios_baud_rate(termios);
-
-       /* Magic token for arbitary speed via c_ispeed*/
-       if (cbaud == BOTHER)
-               return termios->c_ispeed;
-
-       if (cbaud & CBAUDEX) {
-               cbaud &= ~CBAUDEX;
-
-               if (cbaud < 1 || cbaud + 15 > n_baud_table)
-                       termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
-               else
-                       cbaud += 15;
-       }
-       return baud_table[cbaud];
-#else
-       return tty_termios_baud_rate(termios);
-#endif
-}
-EXPORT_SYMBOL(tty_termios_input_baud_rate);
-
-/**
- *     tty_termios_encode_baud_rate
- *     @termios: ktermios structure holding user requested state
- *     @ispeed: input speed
- *     @ospeed: output speed
- *
- *     Encode the speeds set into the passed termios structure. This is
- *     used as a library helper for drivers os that they can report back
- *     the actual speed selected when it differs from the speed requested
- *
- *     For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
- *     we need to carefully set the bits when the user does not get the
- *     desired speed. We allow small margins and preserve as much of possible
- *     of the input intent to keep compatibility.
- *
- *     Locking: Caller should hold termios lock. This is already held
- *     when calling this function from the driver termios handler.
- *
- *     The ifdefs deal with platforms whose owners have yet to update them
- *     and will all go away once this is done.
- */
-
-void tty_termios_encode_baud_rate(struct ktermios *termios,
-                                 speed_t ibaud, speed_t obaud)
-{
-       int i = 0;
-       int ifound = -1, ofound = -1;
-       int iclose = ibaud/50, oclose = obaud/50;
-       int ibinput = 0;
-
-       if (obaud == 0)                 /* CD dropped             */
-               ibaud = 0;              /* Clear ibaud to be sure */
-
-       termios->c_ispeed = ibaud;
-       termios->c_ospeed = obaud;
-
-#ifdef BOTHER
-       /* If the user asked for a precise weird speed give a precise weird
-          answer. If they asked for a Bfoo speed they many have problems
-          digesting non-exact replies so fuzz a bit */
-
-       if ((termios->c_cflag & CBAUD) == BOTHER)
-               oclose = 0;
-       if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
-               iclose = 0;
-       if ((termios->c_cflag >> IBSHIFT) & CBAUD)
-               ibinput = 1;    /* An input speed was specified */
-#endif
-       termios->c_cflag &= ~CBAUD;
-
-       /*
-        *      Our goal is to find a close match to the standard baud rate
-        *      returned. Walk the baud rate table and if we get a very close
-        *      match then report back the speed as a POSIX Bxxxx value by
-        *      preference
-        */
-
-       do {
-               if (obaud - oclose <= baud_table[i] &&
-                   obaud + oclose >= baud_table[i]) {
-                       termios->c_cflag |= baud_bits[i];
-                       ofound = i;
-               }
-               if (ibaud - iclose <= baud_table[i] &&
-                   ibaud + iclose >= baud_table[i]) {
-                       /* For the case input == output don't set IBAUD bits
-                          if the user didn't do so */
-                       if (ofound == i && !ibinput)
-                               ifound  = i;
-#ifdef IBSHIFT
-                       else {
-                               ifound = i;
-                               termios->c_cflag |= (baud_bits[i] << IBSHIFT);
-                       }
-#endif
-               }
-       } while (++i < n_baud_table);
-
-       /*
-        *      If we found no match then use BOTHER if provided or warn
-        *      the user their platform maintainer needs to wake up if not.
-        */
-#ifdef BOTHER
-       if (ofound == -1)
-               termios->c_cflag |= BOTHER;
-       /* Set exact input bits only if the input and output differ or the
-          user already did */
-       if (ifound == -1 && (ibaud != obaud || ibinput))
-               termios->c_cflag |= (BOTHER << IBSHIFT);
-#else
-       if (ifound == -1 || ofound == -1) {
-               printk_once(KERN_WARNING "tty: Unable to return correct "
-                         "speed data as your architecture needs updating.\n");
-       }
-#endif
-}
-EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
-
-/**
- *     tty_encode_baud_rate            -       set baud rate of the tty
- *     @ibaud: input baud rate
- *     @obad: output baud rate
- *
- *     Update the current termios data for the tty with the new speed
- *     settings. The caller must hold the termios_mutex for the tty in
- *     question.
- */
-
-void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
-{
-       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
-}
-EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
-
-/**
- *     tty_get_baud_rate       -       get tty bit rates
- *     @tty: tty to query
- *
- *     Returns the baud rate as an integer for this terminal. The
- *     termios lock must be held by the caller and the terminal bit
- *     flags may be updated.
- *
- *     Locking: none
- */
-
-speed_t tty_get_baud_rate(struct tty_struct *tty)
-{
-       speed_t baud = tty_termios_baud_rate(tty->termios);
-
-       if (baud == 38400 && tty->alt_speed) {
-               if (!tty->warned) {
-                       printk(KERN_WARNING "Use of setserial/setrocket to "
-                                           "set SPD_* flags is deprecated\n");
-                       tty->warned = 1;
-               }
-               baud = tty->alt_speed;
-       }
-
-       return baud;
-}
-EXPORT_SYMBOL(tty_get_baud_rate);
-
-/**
- *     tty_termios_copy_hw     -       copy hardware settings
- *     @new: New termios
- *     @old: Old termios
- *
- *     Propogate the hardware specific terminal setting bits from
- *     the old termios structure to the new one. This is used in cases
- *     where the hardware does not support reconfiguration or as a helper
- *     in some cases where only minimal reconfiguration is supported
- */
-
-void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
-{
-       /* The bits a dumb device handles in software. Smart devices need
-          to always provide a set_termios method */
-       new->c_cflag &= HUPCL | CREAD | CLOCAL;
-       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
-       new->c_ispeed = old->c_ispeed;
-       new->c_ospeed = old->c_ospeed;
-}
-EXPORT_SYMBOL(tty_termios_copy_hw);
-
-/**
- *     tty_termios_hw_change   -       check for setting change
- *     @a: termios
- *     @b: termios to compare
- *
- *     Check if any of the bits that affect a dumb device have changed
- *     between the two termios structures, or a speed change is needed.
- */
-
-int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
-{
-       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
-               return 1;
-       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL(tty_termios_hw_change);
-
-/**
- *     change_termios          -       update termios values
- *     @tty: tty to update
- *     @new_termios: desired new value
- *
- *     Perform updates to the termios values set on this terminal. There
- *     is a bit of layering violation here with n_tty in terms of the
- *     internal knowledge of this function.
- *
- *     Locking: termios_mutex
- */
-
-static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
-{
-       struct ktermios old_termios;
-       struct tty_ldisc *ld;
-       unsigned long flags;
-
-       /*
-        *      Perform the actual termios internal changes under lock.
-        */
-
-
-       /* FIXME: we need to decide on some locking/ordering semantics
-          for the set_termios notification eventually */
-       mutex_lock(&tty->termios_mutex);
-       old_termios = *tty->termios;
-       *tty->termios = *new_termios;
-       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-
-       /* See if packet mode change of state. */
-       if (tty->link && tty->link->packet) {
-               int extproc = (old_termios.c_lflag & EXTPROC) |
-                               (tty->termios->c_lflag & EXTPROC);
-               int old_flow = ((old_termios.c_iflag & IXON) &&
-                               (old_termios.c_cc[VSTOP] == '\023') &&
-                               (old_termios.c_cc[VSTART] == '\021'));
-               int new_flow = (I_IXON(tty) &&
-                               STOP_CHAR(tty) == '\023' &&
-                               START_CHAR(tty) == '\021');
-               if ((old_flow != new_flow) || extproc) {
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (old_flow != new_flow) {
-                               tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
-                               if (new_flow)
-                                       tty->ctrl_status |= TIOCPKT_DOSTOP;
-                               else
-                                       tty->ctrl_status |= TIOCPKT_NOSTOP;
-                       }
-                       if (extproc)
-                               tty->ctrl_status |= TIOCPKT_IOCTL;
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       wake_up_interruptible(&tty->link->read_wait);
-               }
-       }
-
-       if (tty->ops->set_termios)
-               (*tty->ops->set_termios)(tty, &old_termios);
-       else
-               tty_termios_copy_hw(tty->termios, &old_termios);
-
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               if (ld->ops->set_termios)
-                       (ld->ops->set_termios)(tty, &old_termios);
-               tty_ldisc_deref(ld);
-       }
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *     set_termios             -       set termios values for a tty
- *     @tty: terminal device
- *     @arg: user data
- *     @opt: option information
- *
- *     Helper function to prepare termios data and run necessary other
- *     functions before using change_termios to do the actual changes.
- *
- *     Locking:
- *             Called functions take ldisc and termios_mutex locks
- */
-
-static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
-{
-       struct ktermios tmp_termios;
-       struct tty_ldisc *ld;
-       int retval = tty_check_change(tty);
-
-       if (retval)
-               return retval;
-
-       mutex_lock(&tty->termios_mutex);
-       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-
-       if (opt & TERMIOS_TERMIO) {
-               if (user_termio_to_kernel_termios(&tmp_termios,
-                                               (struct termio __user *)arg))
-                       return -EFAULT;
-#ifdef TCGETS2
-       } else if (opt & TERMIOS_OLD) {
-               if (user_termios_to_kernel_termios_1(&tmp_termios,
-                                               (struct termios __user *)arg))
-                       return -EFAULT;
-       } else {
-               if (user_termios_to_kernel_termios(&tmp_termios,
-                                               (struct termios2 __user *)arg))
-                       return -EFAULT;
-       }
-#else
-       } else if (user_termios_to_kernel_termios(&tmp_termios,
-                                       (struct termios __user *)arg))
-               return -EFAULT;
-#endif
-
-       /* If old style Bfoo values are used then load c_ispeed/c_ospeed
-        * with the real speed so its unconditionally usable */
-       tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
-       tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
-
-       ld = tty_ldisc_ref(tty);
-
-       if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-
-       if (opt & TERMIOS_WAIT) {
-               tty_wait_until_sent(tty, 0);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       change_termios(tty, &tmp_termios);
-
-       /* FIXME: Arguably if tmp_termios == tty->termios AND the
-          actual requested termios was not tmp_termios then we may
-          want to return an error as no user requested change has
-          succeeded */
-       return 0;
-}
-
-static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
-{
-       mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-}
-
-static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
-{
-       mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-}
-
-static int get_termio(struct tty_struct *tty, struct termio __user *termio)
-{
-       struct ktermios kterm;
-       copy_termios(tty, &kterm);
-       if (kernel_termios_to_user_termio(termio, &kterm))
-               return -EFAULT;
-       return 0;
-}
-
-
-#ifdef TCGETX
-
-/**
- *     set_termiox     -       set termiox fields if possible
- *     @tty: terminal
- *     @arg: termiox structure from user
- *     @opt: option flags for ioctl type
- *
- *     Implement the device calling points for the SYS5 termiox ioctl
- *     interface in Linux
- */
-
-static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
-{
-       struct termiox tnew;
-       struct tty_ldisc *ld;
-
-       if (tty->termiox == NULL)
-               return -EINVAL;
-       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
-               return -EFAULT;
-
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       if (opt & TERMIOS_WAIT) {
-               tty_wait_until_sent(tty, 0);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       mutex_lock(&tty->termios_mutex);
-       if (tty->ops->set_termiox)
-               tty->ops->set_termiox(tty, &tnew);
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-#endif
-
-
-#ifdef TIOCGETP
-/*
- * These are deprecated, but there is limited support..
- *
- * The "sg_flags" translation is a joke..
- */
-static int get_sgflags(struct tty_struct *tty)
-{
-       int flags = 0;
-
-       if (!(tty->termios->c_lflag & ICANON)) {
-               if (tty->termios->c_lflag & ISIG)
-                       flags |= 0x02;          /* cbreak */
-               else
-                       flags |= 0x20;          /* raw */
-       }
-       if (tty->termios->c_lflag & ECHO)
-               flags |= 0x08;                  /* echo */
-       if (tty->termios->c_oflag & OPOST)
-               if (tty->termios->c_oflag & ONLCR)
-                       flags |= 0x10;          /* crmod */
-       return flags;
-}
-
-static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-       struct sgttyb tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.sg_ispeed = tty->termios->c_ispeed;
-       tmp.sg_ospeed = tty->termios->c_ospeed;
-       tmp.sg_erase = tty->termios->c_cc[VERASE];
-       tmp.sg_kill = tty->termios->c_cc[VKILL];
-       tmp.sg_flags = get_sgflags(tty);
-       mutex_unlock(&tty->termios_mutex);
-
-       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static void set_sgflags(struct ktermios *termios, int flags)
-{
-       termios->c_iflag = ICRNL | IXON;
-       termios->c_oflag = 0;
-       termios->c_lflag = ISIG | ICANON;
-       if (flags & 0x02) {     /* cbreak */
-               termios->c_iflag = 0;
-               termios->c_lflag &= ~ICANON;
-       }
-       if (flags & 0x08) {             /* echo */
-               termios->c_lflag |= ECHO | ECHOE | ECHOK |
-                                   ECHOCTL | ECHOKE | IEXTEN;
-       }
-       if (flags & 0x10) {             /* crmod */
-               termios->c_oflag |= OPOST | ONLCR;
-       }
-       if (flags & 0x20) {     /* raw */
-               termios->c_iflag = 0;
-               termios->c_lflag &= ~(ISIG | ICANON);
-       }
-       if (!(termios->c_lflag & ICANON)) {
-               termios->c_cc[VMIN] = 1;
-               termios->c_cc[VTIME] = 0;
-       }
-}
-
-/**
- *     set_sgttyb              -       set legacy terminal values
- *     @tty: tty structure
- *     @sgttyb: pointer to old style terminal structure
- *
- *     Updates a terminal from the legacy BSD style terminal information
- *     structure.
- *
- *     Locking: termios_mutex
- */
-
-static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-       int retval;
-       struct sgttyb tmp;
-       struct ktermios termios;
-
-       retval = tty_check_change(tty);
-       if (retval)
-               return retval;
-
-       if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
-               return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
-       termios = *tty->termios;
-       termios.c_cc[VERASE] = tmp.sg_erase;
-       termios.c_cc[VKILL] = tmp.sg_kill;
-       set_sgflags(&termios, tmp.sg_flags);
-       /* Try and encode into Bfoo format */
-#ifdef BOTHER
-       tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
-                                               termios.c_ospeed);
-#endif
-       mutex_unlock(&tty->termios_mutex);
-       change_termios(tty, &termios);
-       return 0;
-}
-#endif
-
-#ifdef TIOCGETC
-static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-       struct tchars tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.t_intrc = tty->termios->c_cc[VINTR];
-       tmp.t_quitc = tty->termios->c_cc[VQUIT];
-       tmp.t_startc = tty->termios->c_cc[VSTART];
-       tmp.t_stopc = tty->termios->c_cc[VSTOP];
-       tmp.t_eofc = tty->termios->c_cc[VEOF];
-       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
-       mutex_unlock(&tty->termios_mutex);
-       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-       struct tchars tmp;
-
-       if (copy_from_user(&tmp, tchars, sizeof(tmp)))
-               return -EFAULT;
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VINTR] = tmp.t_intrc;
-       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
-       tty->termios->c_cc[VSTART] = tmp.t_startc;
-       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
-       tty->termios->c_cc[VEOF] = tmp.t_eofc;
-       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-#endif
-
-#ifdef TIOCGLTC
-static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-       struct ltchars tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.t_suspc = tty->termios->c_cc[VSUSP];
-       /* what is dsuspc anyway? */
-       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
-       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
-       /* what is flushc anyway? */
-       tmp.t_flushc = tty->termios->c_cc[VEOL2];
-       tmp.t_werasc = tty->termios->c_cc[VWERASE];
-       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
-       mutex_unlock(&tty->termios_mutex);
-       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-       struct ltchars tmp;
-
-       if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
-               return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
-       /* what is dsuspc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
-       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
-       /* what is flushc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
-       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
-       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-#endif
-
-/**
- *     send_prio_char          -       send priority character
- *
- *     Send a high priority character to the tty even if stopped
- *
- *     Locking: none for xchar method, write ordering for write method.
- */
-
-static int send_prio_char(struct tty_struct *tty, char ch)
-{
-       int     was_stopped = tty->stopped;
-
-       if (tty->ops->send_xchar) {
-               tty->ops->send_xchar(tty, ch);
-               return 0;
-       }
-
-       if (tty_write_lock(tty, 0) < 0)
-               return -ERESTARTSYS;
-
-       if (was_stopped)
-               start_tty(tty);
-       tty->ops->write(tty, &ch, 1);
-       if (was_stopped)
-               stop_tty(tty);
-       tty_write_unlock(tty);
-       return 0;
-}
-
-/**
- *     tty_change_softcar      -       carrier change ioctl helper
- *     @tty: tty to update
- *     @arg: enable/disable CLOCAL
- *
- *     Perform a change to the CLOCAL state and call into the driver
- *     layer to make it visible. All done with the termios mutex
- */
-
-static int tty_change_softcar(struct tty_struct *tty, int arg)
-{
-       int ret = 0;
-       int bit = arg ? CLOCAL : 0;
-       struct ktermios old;
-
-       mutex_lock(&tty->termios_mutex);
-       old = *tty->termios;
-       tty->termios->c_cflag &= ~CLOCAL;
-       tty->termios->c_cflag |= bit;
-       if (tty->ops->set_termios)
-               tty->ops->set_termios(tty, &old);
-       if ((tty->termios->c_cflag & CLOCAL) != bit)
-               ret = -EINVAL;
-       mutex_unlock(&tty->termios_mutex);
-       return ret;
-}
-
-/**
- *     tty_mode_ioctl          -       mode related ioctls
- *     @tty: tty for the ioctl
- *     @file: file pointer for the tty
- *     @cmd: command
- *     @arg: ioctl argument
- *
- *     Perform non line discipline specific mode control ioctls. This
- *     is designed to be called by line disciplines to ensure they provide
- *     consistent mode setting.
- */
-
-int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct tty_struct *real_tty;
-       void __user *p = (void __user *)arg;
-       int ret = 0;
-       struct ktermios kterm;
-
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               real_tty = tty->link;
-       else
-               real_tty = tty;
-
-       switch (cmd) {
-#ifdef TIOCGETP
-       case TIOCGETP:
-               return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
-       case TIOCSETP:
-       case TIOCSETN:
-               return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
-#endif
-#ifdef TIOCGETC
-       case TIOCGETC:
-               return get_tchars(real_tty, p);
-       case TIOCSETC:
-               return set_tchars(real_tty, p);
-#endif
-#ifdef TIOCGLTC
-       case TIOCGLTC:
-               return get_ltchars(real_tty, p);
-       case TIOCSLTC:
-               return set_ltchars(real_tty, p);
-#endif
-       case TCSETSF:
-               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
-       case TCSETSW:
-               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
-       case TCSETS:
-               return set_termios(real_tty, p, TERMIOS_OLD);
-#ifndef TCGETS2
-       case TCGETS:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-#else
-       case TCGETS:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TCGETS2:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TCSETSF2:
-               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
-       case TCSETSW2:
-               return set_termios(real_tty, p, TERMIOS_WAIT);
-       case TCSETS2:
-               return set_termios(real_tty, p, 0);
-#endif
-       case TCGETA:
-               return get_termio(real_tty, p);
-       case TCSETAF:
-               return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
-       case TCSETAW:
-               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
-       case TCSETA:
-               return set_termios(real_tty, p, TERMIOS_TERMIO);
-#ifndef TCGETS2
-       case TIOCGLCKTRMIOS:
-               copy_termios_locked(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TIOCSLCKTRMIOS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               copy_termios_locked(real_tty, &kterm);
-               if (user_termios_to_kernel_termios(&kterm,
-                                              (struct termios __user *) arg))
-                       return -EFAULT;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-               mutex_unlock(&real_tty->termios_mutex);
-               return 0;
-#else
-       case TIOCGLCKTRMIOS:
-               copy_termios_locked(real_tty, &kterm);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TIOCSLCKTRMIOS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               copy_termios_locked(real_tty, &kterm);
-               if (user_termios_to_kernel_termios_1(&kterm,
-                                              (struct termios __user *) arg))
-                       return -EFAULT;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-               mutex_unlock(&real_tty->termios_mutex);
-               return ret;
-#endif
-#ifdef TCGETX
-       case TCGETX: {
-               struct termiox ktermx;
-               if (real_tty->termiox == NULL)
-                       return -EINVAL;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
-               mutex_unlock(&real_tty->termios_mutex);
-               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
-                       ret = -EFAULT;
-               return ret;
-       }
-       case TCSETX:
-               return set_termiox(real_tty, p, 0);
-       case TCSETXW:
-               return set_termiox(real_tty, p, TERMIOS_WAIT);
-       case TCSETXF:
-               return set_termiox(real_tty, p, TERMIOS_FLUSH);
-#endif         
-       case TIOCGSOFTCAR:
-               copy_termios(real_tty, &kterm);
-               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
-                                               (int __user *)arg);
-               return ret;
-       case TIOCSSOFTCAR:
-               if (get_user(arg, (unsigned int __user *) arg))
-                       return -EFAULT;
-               return tty_change_softcar(real_tty, arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-EXPORT_SYMBOL_GPL(tty_mode_ioctl);
-
-int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
-{
-       struct tty_ldisc *ld;
-       int retval = tty_check_change(tty);
-       if (retval)
-               return retval;
-
-       ld = tty_ldisc_ref_wait(tty);
-       switch (arg) {
-       case TCIFLUSH:
-               if (ld && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               break;
-       case TCIOFLUSH:
-               if (ld && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               /* fall through */
-       case TCOFLUSH:
-               tty_driver_flush_buffer(tty);
-               break;
-       default:
-               tty_ldisc_deref(ld);
-               return -EINVAL;
-       }
-       tty_ldisc_deref(ld);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tty_perform_flush);
-
-int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       unsigned long flags;
-       int retval;
-
-       switch (cmd) {
-       case TCXONC:
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               switch (arg) {
-               case TCOOFF:
-                       if (!tty->flow_stopped) {
-                               tty->flow_stopped = 1;
-                               stop_tty(tty);
-                       }
-                       break;
-               case TCOON:
-                       if (tty->flow_stopped) {
-                               tty->flow_stopped = 0;
-                               start_tty(tty);
-                       }
-                       break;
-               case TCIOFF:
-                       if (STOP_CHAR(tty) != __DISABLED_CHAR)
-                               return send_prio_char(tty, STOP_CHAR(tty));
-                       break;
-               case TCION:
-                       if (START_CHAR(tty) != __DISABLED_CHAR)
-                               return send_prio_char(tty, START_CHAR(tty));
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       case TCFLSH:
-               return tty_perform_flush(tty, arg);
-       case TIOCPKT:
-       {
-               int pktmode;
-
-               if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
-                   tty->driver->subtype != PTY_TYPE_MASTER)
-                       return -ENOTTY;
-               if (get_user(pktmode, (int __user *) arg))
-                       return -EFAULT;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               if (pktmode) {
-                       if (!tty->packet) {
-                               tty->packet = 1;
-                               tty->link->ctrl_status = 0;
-                       }
-               } else
-                       tty->packet = 0;
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return 0;
-       }
-       default:
-               /* Try the mode commands */
-               return tty_mode_ioctl(tty, file, cmd, arg);
-       }
-}
-EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
deleted file mode 100644 (file)
index 412f977..0000000
+++ /dev/null
@@ -1,915 +0,0 @@
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/smp_lock.h>    /* For the moment */
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-/*
- *     This guards the refcounted line discipline lists. The lock
- *     must be taken with irqs off because there are hangup path
- *     callers who will do ldisc lookups and cannot sleep.
- */
-
-static DEFINE_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-/* Line disc dispatch table */
-static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
-
-static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
-{
-       if (ld)
-               atomic_inc(&ld->users);
-       return ld;
-}
-
-static void put_ldisc(struct tty_ldisc *ld)
-{
-       unsigned long flags;
-
-       if (WARN_ON_ONCE(!ld))
-               return;
-
-       /*
-        * If this is the last user, free the ldisc, and
-        * release the ldisc ops.
-        *
-        * We really want an "atomic_dec_and_lock_irqsave()",
-        * but we don't have it, so this does it by hand.
-        */
-       local_irq_save(flags);
-       if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
-               struct tty_ldisc_ops *ldo = ld->ops;
-
-               ldo->refcount--;
-               module_put(ldo->owner);
-               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-               kfree(ld);
-               return;
-       }
-       local_irq_restore(flags);
-}
-
-/**
- *     tty_register_ldisc      -       install a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Installs a new line discipline into the kernel. The discipline
- *     is set up as unreferenced and then made available to the kernel
- *     from this point onwards.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       tty_ldiscs[disc] = new_ldisc;
-       new_ldisc->num = disc;
-       new_ldisc->refcount = 0;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL(tty_register_ldisc);
-
-/**
- *     tty_unregister_ldisc    -       unload a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Remove a line discipline from the kernel providing it is not
- *     currently in use.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_unregister_ldisc(int disc)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       if (tty_ldiscs[disc]->refcount)
-               ret = -EBUSY;
-       else
-               tty_ldiscs[disc] = NULL;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL(tty_unregister_ldisc);
-
-static struct tty_ldisc_ops *get_ldops(int disc)
-{
-       unsigned long flags;
-       struct tty_ldisc_ops *ldops, *ret;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ret = ERR_PTR(-EINVAL);
-       ldops = tty_ldiscs[disc];
-       if (ldops) {
-               ret = ERR_PTR(-EAGAIN);
-               if (try_module_get(ldops->owner)) {
-                       ldops->refcount++;
-                       ret = ldops;
-               }
-       }
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ret;
-}
-
-static void put_ldops(struct tty_ldisc_ops *ldops)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ldops->refcount--;
-       module_put(ldops->owner);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-}
-
-/**
- *     tty_ldisc_get           -       take a reference to an ldisc
- *     @disc: ldisc number
- *
- *     Takes a reference to a line discipline. Deals with refcounts and
- *     module locking counts. Returns NULL if the discipline is not available.
- *     Returns a pointer to the discipline and bumps the ref count if it is
- *     available
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-static struct tty_ldisc *tty_ldisc_get(int disc)
-{
-       struct tty_ldisc *ld;
-       struct tty_ldisc_ops *ldops;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return ERR_PTR(-EINVAL);
-
-       /*
-        * Get the ldisc ops - we may need to request them to be loaded
-        * dynamically and try again.
-        */
-       ldops = get_ldops(disc);
-       if (IS_ERR(ldops)) {
-               request_module("tty-ldisc-%d", disc);
-               ldops = get_ldops(disc);
-               if (IS_ERR(ldops))
-                       return ERR_CAST(ldops);
-       }
-
-       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
-       if (ld == NULL) {
-               put_ldops(ldops);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       ld->ops = ldops;
-       atomic_set(&ld->users, 1);
-       return ld;
-}
-
-static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       (*pos)++;
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
-       int i = *(loff_t *)v;
-       struct tty_ldisc_ops *ldops;
-
-       ldops = get_ldops(i);
-       if (IS_ERR(ldops))
-               return 0;
-       seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
-       put_ldops(ldops);
-       return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
-       .start  = tty_ldiscs_seq_start,
-       .next   = tty_ldiscs_seq_next,
-       .stop   = tty_ldiscs_seq_stop,
-       .show   = tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-const struct file_operations tty_ldiscs_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_tty_ldiscs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-/**
- *     tty_ldisc_assign        -       set ldisc on a tty
- *     @tty: tty to assign
- *     @ld: line discipline
- *
- *     Install an instance of a line discipline into a tty structure. The
- *     ldisc must have a reference count above zero to ensure it remains.
- *     The tty instance refcount starts at zero.
- *
- *     Locking:
- *             Caller must hold references
- */
-
-static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       tty->ldisc = ld;
-}
-
-/**
- *     tty_ldisc_try           -       internal helper
- *     @tty: the tty
- *
- *     Make a single attempt to grab and bump the refcount on
- *     the tty ldisc. Return 0 on failure or 1 on success. This is
- *     used to implement both the waiting and non waiting versions
- *     of tty_ldisc_ref
- *
- *     Locking: takes tty_ldisc_lock
- */
-
-static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
-{
-       unsigned long flags;
-       struct tty_ldisc *ld;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ld = NULL;
-       if (test_bit(TTY_LDISC, &tty->flags))
-               ld = get_ldisc(tty->ldisc);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ld;
-}
-
-/**
- *     tty_ldisc_ref_wait      -       wait for the tty ldisc
- *     @tty: tty device
- *
- *     Dereference the line discipline for the terminal and take a
- *     reference to it. If the line discipline is in flux then
- *     wait patiently until it changes.
- *
- *     Note: Must not be called from an IRQ/timer context. The caller
- *     must also be careful not to hold other locks that will deadlock
- *     against a discipline change, such as an existing ldisc reference
- *     (which we check for)
- *
- *     Locking: call functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-
-       /* wait_event is a macro */
-       wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
-       return ld;
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
-
-/**
- *     tty_ldisc_ref           -       get the tty ldisc
- *     @tty: tty device
- *
- *     Dereference the line discipline for the terminal and take a
- *     reference to it. If the line discipline is in flux then
- *     return NULL. Can be called from IRQ and timer functions.
- *
- *     Locking: called functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
-{
-       return tty_ldisc_try(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref);
-
-/**
- *     tty_ldisc_deref         -       free a tty ldisc reference
- *     @ld: reference to free up
- *
- *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
- *     be called in IRQ context.
- *
- *     Locking: takes tty_ldisc_lock
- */
-
-void tty_ldisc_deref(struct tty_ldisc *ld)
-{
-       put_ldisc(ld);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
-{
-       put_ldisc(ld);
-}
-
-/**
- *     tty_ldisc_enable        -       allow ldisc use
- *     @tty: terminal to activate ldisc on
- *
- *     Set the TTY_LDISC flag when the line discipline can be called
- *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
- *     changing flag to indicate any ldisc change is now over.
- *
- *     Note: nobody should set the TTY_LDISC bit except via this function.
- *     Clearing directly is allowed.
- */
-
-void tty_ldisc_enable(struct tty_struct *tty)
-{
-       set_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-       wake_up(&tty_ldisc_wait);
-}
-
-/**
- *     tty_ldisc_flush -       flush line discipline queue
- *     @tty: tty
- *
- *     Flush the line discipline queue (if any) for this tty. If there
- *     is no line discipline active this is a no-op.
- */
-
-void tty_ldisc_flush(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       tty_buffer_flush(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_flush);
-
-/**
- *     tty_set_termios_ldisc           -       set ldisc field
- *     @tty: tty structure
- *     @num: line discipline number
- *
- *     This is probably overkill for real world processors but
- *     they are not on hot paths so a little discipline won't do
- *     any harm.
- *
- *     Locking: takes termios_mutex
- */
-
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
-{
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_line = num;
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *     tty_ldisc_open          -       open a line discipline
- *     @tty: tty we are opening the ldisc on
- *     @ld: discipline to open
- *
- *     A helper opening method. Also a convenient debugging and check
- *     point.
- *
- *     Locking: always called with BTM already held.
- */
-
-static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
-       if (ld->ops->open) {
-               int ret;
-                /* BTM here locks versus a hangup event */
-               WARN_ON(!tty_locked());
-               ret = ld->ops->open(tty);
-               return ret;
-       }
-       return 0;
-}
-
-/**
- *     tty_ldisc_close         -       close a line discipline
- *     @tty: tty we are opening the ldisc on
- *     @ld: discipline to close
- *
- *     A helper close method. Also a convenient debugging and check
- *     point.
- */
-
-static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
-       clear_bit(TTY_LDISC_OPEN, &tty->flags);
-       if (ld->ops->close)
-               ld->ops->close(tty);
-}
-
-/**
- *     tty_ldisc_restore       -       helper for tty ldisc change
- *     @tty: tty to recover
- *     @old: previous ldisc
- *
- *     Restore the previous line discipline or N_TTY when a line discipline
- *     change fails due to an open error
- */
-
-static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
-{
-       char buf[64];
-       struct tty_ldisc *new_ldisc;
-       int r;
-
-       /* There is an outstanding reference here so this is safe */
-       old = tty_ldisc_get(old->ops->num);
-       WARN_ON(IS_ERR(old));
-       tty_ldisc_assign(tty, old);
-       tty_set_termios_ldisc(tty, old->ops->num);
-       if (tty_ldisc_open(tty, old) < 0) {
-               tty_ldisc_put(old);
-               /* This driver is always present */
-               new_ldisc = tty_ldisc_get(N_TTY);
-               if (IS_ERR(new_ldisc))
-                       panic("n_tty: get");
-               tty_ldisc_assign(tty, new_ldisc);
-               tty_set_termios_ldisc(tty, N_TTY);
-               r = tty_ldisc_open(tty, new_ldisc);
-               if (r < 0)
-                       panic("Couldn't open N_TTY ldisc for "
-                             "%s --- error %d.",
-                             tty_name(tty, buf), r);
-       }
-}
-
-/**
- *     tty_ldisc_halt          -       shut down the line discipline
- *     @tty: tty device
- *
- *     Shut down the line discipline and work queue for this tty device.
- *     The TTY_LDISC flag being cleared ensures no further references can
- *     be obtained while the delayed work queue halt ensures that no more
- *     data is fed to the ldisc.
- *
- *     You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
- *     in order to make sure any currently executing ldisc work is also
- *     flushed.
- */
-
-static int tty_ldisc_halt(struct tty_struct *tty)
-{
-       clear_bit(TTY_LDISC, &tty->flags);
-       return cancel_delayed_work_sync(&tty->buf.work);
-}
-
-/**
- *     tty_set_ldisc           -       set line discipline
- *     @tty: the terminal to set
- *     @ldisc: the line discipline
- *
- *     Set the discipline of a tty line. Must be called from a process
- *     context. The ldisc change logic has to protect itself against any
- *     overlapping ldisc change (including on the other end of pty pairs),
- *     the close of one side of a tty/pty pair, and eventually hangup.
- *
- *     Locking: takes tty_ldisc_lock, termios_mutex
- */
-
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
-{
-       int retval;
-       struct tty_ldisc *o_ldisc, *new_ldisc;
-       int work, o_work = 0;
-       struct tty_struct *o_tty;
-
-       new_ldisc = tty_ldisc_get(ldisc);
-       if (IS_ERR(new_ldisc))
-               return PTR_ERR(new_ldisc);
-
-       tty_lock();
-       /*
-        *      We need to look at the tty locking here for pty/tty pairs
-        *      when both sides try to change in parallel.
-        */
-
-       o_tty = tty->link;      /* o_tty is the pty side or NULL */
-
-
-       /*
-        *      Check the no-op case
-        */
-
-       if (tty->ldisc->ops->num == ldisc) {
-               tty_unlock();
-               tty_ldisc_put(new_ldisc);
-               return 0;
-       }
-
-       tty_unlock();
-       /*
-        *      Problem: What do we do if this blocks ?
-        *      We could deadlock here
-        */
-
-       tty_wait_until_sent(tty, 0);
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-
-       /*
-        *      We could be midstream of another ldisc change which has
-        *      dropped the lock during processing. If so we need to wait.
-        */
-
-       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
-               mutex_unlock(&tty->ldisc_mutex);
-               tty_unlock();
-               wait_event(tty_ldisc_wait,
-                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-               tty_lock();
-               mutex_lock(&tty->ldisc_mutex);
-       }
-
-       set_bit(TTY_LDISC_CHANGING, &tty->flags);
-
-       /*
-        *      No more input please, we are switching. The new ldisc
-        *      will update this value in the ldisc open function
-        */
-
-       tty->receive_room = 0;
-
-       o_ldisc = tty->ldisc;
-
-       tty_unlock();
-       /*
-        *      Make sure we don't change while someone holds a
-        *      reference to the line discipline. The TTY_LDISC bit
-        *      prevents anyone taking a reference once it is clear.
-        *      We need the lock to avoid racing reference takers.
-        *
-        *      We must clear the TTY_LDISC bit here to avoid a livelock
-        *      with a userspace app continually trying to use the tty in
-        *      parallel to the change and re-referencing the tty.
-        */
-
-       work = tty_ldisc_halt(tty);
-       if (o_tty)
-               o_work = tty_ldisc_halt(o_tty);
-
-       /*
-        * Wait for ->hangup_work and ->buf.work handlers to terminate.
-        * We must drop the mutex here in case a hangup is also in process.
-        */
-
-       mutex_unlock(&tty->ldisc_mutex);
-
-       flush_scheduled_work();
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-       if (test_bit(TTY_HUPPED, &tty->flags)) {
-               /* We were raced by the hangup method. It will have stomped
-                  the ldisc data and closed the ldisc down */
-               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-               mutex_unlock(&tty->ldisc_mutex);
-               tty_ldisc_put(new_ldisc);
-               tty_unlock();
-               return -EIO;
-       }
-
-       /* Shutdown the current discipline. */
-       tty_ldisc_close(tty, o_ldisc);
-
-       /* Now set up the new line discipline. */
-       tty_ldisc_assign(tty, new_ldisc);
-       tty_set_termios_ldisc(tty, ldisc);
-
-       retval = tty_ldisc_open(tty, new_ldisc);
-       if (retval < 0) {
-               /* Back to the old one or N_TTY if we can't */
-               tty_ldisc_put(new_ldisc);
-               tty_ldisc_restore(tty, o_ldisc);
-       }
-
-       /* At this point we hold a reference to the new ldisc and a
-          a reference to the old ldisc. If we ended up flipping back
-          to the existing ldisc we have two references to it */
-
-       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
-               tty->ops->set_ldisc(tty);
-
-       tty_ldisc_put(o_ldisc);
-
-       /*
-        *      Allow ldisc referencing to occur again
-        */
-
-       tty_ldisc_enable(tty);
-       if (o_tty)
-               tty_ldisc_enable(o_tty);
-
-       /* Restart the work queue in case no characters kick it off. Safe if
-          already running */
-       if (work)
-               schedule_delayed_work(&tty->buf.work, 1);
-       if (o_work)
-               schedule_delayed_work(&o_tty->buf.work, 1);
-       mutex_unlock(&tty->ldisc_mutex);
-       tty_unlock();
-       return retval;
-}
-
-/**
- *     tty_reset_termios       -       reset terminal state
- *     @tty: tty to reset
- *
- *     Restore a terminal to the driver default state.
- */
-
-static void tty_reset_termios(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       *tty->termios = tty->driver->init_termios;
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       mutex_unlock(&tty->termios_mutex);
-}
-
-
-/**
- *     tty_ldisc_reinit        -       reinitialise the tty ldisc
- *     @tty: tty to reinit
- *     @ldisc: line discipline to reinitialize
- *
- *     Switch the tty to a line discipline and leave the ldisc
- *     state closed
- */
-
-static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
-{
-       struct tty_ldisc *ld;
-
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       tty->ldisc = NULL;
-       /*
-        *      Switch the line discipline back
-        */
-       ld = tty_ldisc_get(ldisc);
-       BUG_ON(IS_ERR(ld));
-       tty_ldisc_assign(tty, ld);
-       tty_set_termios_ldisc(tty, ldisc);
-}
-
-/**
- *     tty_ldisc_hangup                -       hangup ldisc reset
- *     @tty: tty being hung up
- *
- *     Some tty devices reset their termios when they receive a hangup
- *     event. In that situation we must also switch back to N_TTY properly
- *     before we reset the termios data.
- *
- *     Locking: We can take the ldisc mutex as the rest of the code is
- *     careful to allow for this.
- *
- *     In the pty pair case this occurs in the close() path of the
- *     tty itself so we must be careful about locking rules.
- */
-
-void tty_ldisc_hangup(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-       int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
-       int err = 0;
-
-       /*
-        * FIXME! What are the locking issues here? This may me overdoing
-        * things... This question is especially important now that we've
-        * removed the irqlock.
-        */
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               /* We may have no line discipline at this point */
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-                   ld->ops->write_wakeup)
-                       ld->ops->write_wakeup(tty);
-               if (ld->ops->hangup)
-                       ld->ops->hangup(tty);
-               tty_ldisc_deref(ld);
-       }
-       /*
-        * FIXME: Once we trust the LDISC code better we can wait here for
-        * ldisc completion and fix the driver call race
-        */
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
-       /*
-        * Shutdown the current line discipline, and reset it to
-        * N_TTY if need be.
-        *
-        * Avoid racing set_ldisc or tty_ldisc_release
-        */
-       mutex_lock(&tty->ldisc_mutex);
-
-       /*
-        * this is like tty_ldisc_halt, but we need to give up
-        * the BTM before calling cancel_delayed_work_sync,
-        * which may need to wait for another function taking the BTM
-        */
-       clear_bit(TTY_LDISC, &tty->flags);
-       tty_unlock();
-       cancel_delayed_work_sync(&tty->buf.work);
-       mutex_unlock(&tty->ldisc_mutex);
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-
-       /* At this point we have a closed ldisc and we want to
-          reopen it. We could defer this to the next open but
-          it means auditing a lot of other paths so this is
-          a FIXME */
-       if (tty->ldisc) {       /* Not yet closed */
-               if (reset == 0) {
-                       tty_ldisc_reinit(tty, tty->termios->c_line);
-                       err = tty_ldisc_open(tty, tty->ldisc);
-               }
-               /* If the re-open fails or we reset then go to N_TTY. The
-                  N_TTY open cannot fail */
-               if (reset || err) {
-                       tty_ldisc_reinit(tty, N_TTY);
-                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-               }
-               tty_ldisc_enable(tty);
-       }
-       mutex_unlock(&tty->ldisc_mutex);
-       if (reset)
-               tty_reset_termios(tty);
-}
-
-/**
- *     tty_ldisc_setup                 -       open line discipline
- *     @tty: tty being shut down
- *     @o_tty: pair tty for pty/tty pairs
- *
- *     Called during the initial open of a tty/pty pair in order to set up the
- *     line disciplines and bind them to the tty. This has no locking issues
- *     as the device isn't yet active.
- */
-
-int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-       struct tty_ldisc *ld = tty->ldisc;
-       int retval;
-
-       retval = tty_ldisc_open(tty, ld);
-       if (retval)
-               return retval;
-
-       if (o_tty) {
-               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
-               if (retval) {
-                       tty_ldisc_close(tty, ld);
-                       return retval;
-               }
-               tty_ldisc_enable(o_tty);
-       }
-       tty_ldisc_enable(tty);
-       return 0;
-}
-/**
- *     tty_ldisc_release               -       release line discipline
- *     @tty: tty being shut down
- *     @o_tty: pair tty for pty/tty pairs
- *
- *     Called during the final close of a tty/pty pair in order to shut down
- *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
- *     ldisc has not been opened.
- */
-
-void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-       /*
-        * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
-        * kill any delayed work. As this is the final close it does not
-        * race with the set_ldisc code path.
-        */
-
-       tty_unlock();
-       tty_ldisc_halt(tty);
-       flush_scheduled_work();
-       tty_lock();
-
-       mutex_lock(&tty->ldisc_mutex);
-       /*
-        * Now kill off the ldisc
-        */
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       /* Force an oops if we mess this up */
-       tty->ldisc = NULL;
-
-       /* Ensure the next open requests the N_TTY ldisc */
-       tty_set_termios_ldisc(tty, N_TTY);
-       mutex_unlock(&tty->ldisc_mutex);
-
-       /* This will need doing differently if we need to lock */
-       if (o_tty)
-               tty_ldisc_release(o_tty, NULL);
-
-       /* And the memory resources remaining (buffers, termios) will be
-          disposed of when the kref hits zero */
-}
-
-/**
- *     tty_ldisc_init          -       ldisc setup for new tty
- *     @tty: tty being allocated
- *
- *     Set up the line discipline objects for a newly allocated tty. Note that
- *     the tty structure is not completely set up when this call is made.
- */
-
-void tty_ldisc_init(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
-       if (IS_ERR(ld))
-               panic("n_tty: init_tty");
-       tty_ldisc_assign(tty, ld);
-}
-
-void tty_ldisc_begin(void)
-{
-       /* Setup the default TTY line discipline. */
-       (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-}
diff --git a/drivers/char/tty_mutex.c b/drivers/char/tty_mutex.c
deleted file mode 100644 (file)
index 1336975..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * drivers/char/tty_lock.c
- */
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/semaphore.h>
-#include <linux/sched.h>
-
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
-struct task_struct *__big_tty_mutex_owner;
-EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
-
-/*
- * Getting the big tty mutex.
- */
-void __lockfunc tty_lock(void)
-{
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner == task);
-
-       mutex_lock(&big_tty_mutex);
-       __big_tty_mutex_owner = task;
-}
-EXPORT_SYMBOL(tty_lock);
-
-void __lockfunc tty_unlock(void)
-{
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner != task);
-       __big_tty_mutex_owner = NULL;
-
-       mutex_unlock(&big_tty_mutex);
-}
-EXPORT_SYMBOL(tty_unlock);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
deleted file mode 100644 (file)
index 33d37d2..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Tty port functions
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-void tty_port_init(struct tty_port *port)
-{
-       memset(port, 0, sizeof(*port));
-       init_waitqueue_head(&port->open_wait);
-       init_waitqueue_head(&port->close_wait);
-       init_waitqueue_head(&port->delta_msr_wait);
-       mutex_init(&port->mutex);
-       mutex_init(&port->buf_mutex);
-       spin_lock_init(&port->lock);
-       port->close_delay = (50 * HZ) / 100;
-       port->closing_wait = (3000 * HZ) / 100;
-       kref_init(&port->kref);
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-       /* We may sleep in get_zeroed_page() */
-       mutex_lock(&port->buf_mutex);
-       if (port->xmit_buf == NULL)
-               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-       mutex_unlock(&port->buf_mutex);
-       if (port->xmit_buf == NULL)
-               return -ENOMEM;
-       return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-       mutex_lock(&port->buf_mutex);
-       if (port->xmit_buf != NULL) {
-               free_page((unsigned long)port->xmit_buf);
-               port->xmit_buf = NULL;
-       }
-       mutex_unlock(&port->buf_mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-static void tty_port_destructor(struct kref *kref)
-{
-       struct tty_port *port = container_of(kref, struct tty_port, kref);
-       if (port->xmit_buf)
-               free_page((unsigned long)port->xmit_buf);
-       if (port->ops->destruct)
-               port->ops->destruct(port);
-       else
-               kfree(port);
-}
-
-void tty_port_put(struct tty_port *port)
-{
-       if (port)
-               kref_put(&port->kref, tty_port_destructor);
-}
-EXPORT_SYMBOL(tty_port_put);
-
-/**
- *     tty_port_tty_get        -       get a tty reference
- *     @port: tty port
- *
- *     Return a refcount protected tty instance or NULL if the port is not
- *     associated with a tty (eg due to close or hangup)
- */
-
-struct tty_struct *tty_port_tty_get(struct tty_port *port)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty = tty_kref_get(port->tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return tty;
-}
-EXPORT_SYMBOL(tty_port_tty_get);
-
-/**
- *     tty_port_tty_set        -       set the tty of a port
- *     @port: tty port
- *     @tty: the tty
- *
- *     Associate the port and tty pair. Manages any internal refcounts.
- *     Pass NULL to deassociate a port
- */
-
-void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (port->tty)
-               tty_kref_put(port->tty);
-       port->tty = tty_kref_get(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_tty_set);
-
-static void tty_port_shutdown(struct tty_port *port)
-{
-       mutex_lock(&port->mutex);
-       if (port->ops->shutdown && !port->console &&
-               test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
-                       port->ops->shutdown(port);
-       mutex_unlock(&port->mutex);
-}
-
-/**
- *     tty_port_hangup         -       hangup helper
- *     @port: tty port
- *
- *     Perform port level tty hangup flag and count changes. Drop the tty
- *     reference.
- */
-
-void tty_port_hangup(struct tty_port *port)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->count = 0;
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
-       if (port->tty) {
-               set_bit(TTY_IO_ERROR, &port->tty->flags);
-               tty_kref_put(port->tty);
-       }
-       port->tty = NULL;
-       spin_unlock_irqrestore(&port->lock, flags);
-       wake_up_interruptible(&port->open_wait);
-       wake_up_interruptible(&port->delta_msr_wait);
-       tty_port_shutdown(port);
-}
-EXPORT_SYMBOL(tty_port_hangup);
-
-/**
- *     tty_port_carrier_raised -       carrier raised check
- *     @port: tty port
- *
- *     Wrapper for the carrier detect logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-int tty_port_carrier_raised(struct tty_port *port)
-{
-       if (port->ops->carrier_raised == NULL)
-               return 1;
-       return port->ops->carrier_raised(port);
-}
-EXPORT_SYMBOL(tty_port_carrier_raised);
-
-/**
- *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
- *     @port: tty port
- *
- *     Wrapper for the DTR/RTS raise logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-void tty_port_raise_dtr_rts(struct tty_port *port)
-{
-       if (port->ops->dtr_rts)
-               port->ops->dtr_rts(port, 1);
-}
-EXPORT_SYMBOL(tty_port_raise_dtr_rts);
-
-/**
- *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
- *     @port: tty port
- *
- *     Wrapper for the DTR/RTS raise logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-void tty_port_lower_dtr_rts(struct tty_port *port)
-{
-       if (port->ops->dtr_rts)
-               port->ops->dtr_rts(port, 0);
-}
-EXPORT_SYMBOL(tty_port_lower_dtr_rts);
-
-/**
- *     tty_port_block_til_ready        -       Waiting logic for tty open
- *     @port: the tty port being opened
- *     @tty: the tty device being bound
- *     @filp: the file pointer of the opener
- *
- *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
- *     Handles:
- *             - hangup (both before and during)
- *             - non blocking open
- *             - rts/dtr/dcd
- *             - signals
- *             - port flags and counts
- *
- *     The passed tty_port must implement the carrier_raised method if it can
- *     do carrier detect and the dtr_rts method if it supports software
- *     management of these lines. Note that the dtr/rts raise is done each
- *     iteration as a hangup may have previously dropped them while we wait.
- */
-
-int tty_port_block_til_ready(struct tty_port *port,
-                               struct tty_struct *tty, struct file *filp)
-{
-       int do_clocal = 0, retval;
-       unsigned long flags;
-       DEFINE_WAIT(wait);
-       int cd;
-
-       /* block if port is in the process of being closed */
-       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(port->close_wait,
-                               !(port->flags & ASYNC_CLOSING));
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       /* if non-blocking mode is set we can pass directly to open unless
-          the port has just hung up or is in another error state */
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-       if (filp->f_flags & O_NONBLOCK) {
-               /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
-                       tty_port_raise_dtr_rts(port);
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (C_CLOCAL(tty))
-               do_clocal = 1;
-
-       /* Block waiting until we can proceed. We may need to wait for the
-          carrier, but we must also wait for any close that is in progress
-          before the next open may complete */
-
-       retval = 0;
-
-       /* The port lock protects the port counts */
-       spin_lock_irqsave(&port->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       port->blocked_open++;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       while (1) {
-               /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
-                       tty_port_raise_dtr_rts(port);
-
-               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
-               /* Check for a hangup or uninitialised port.
-                                                       Return accordingly */
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               /* Probe the carrier. For devices with no carrier detect this
-                  will always return true */
-               cd = tty_port_carrier_raised(port);
-               if (!(port->flags & ASYNC_CLOSING) &&
-                               (do_clocal || cd))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       finish_wait(&port->open_wait, &wait);
-
-       /* Update counts. A parallel hangup will have set count to zero and
-          we must not mess that up further */
-       spin_lock_irqsave(&port->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-       if (retval == 0)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-       spin_unlock_irqrestore(&port->lock, flags);
-       return retval;
-}
-EXPORT_SYMBOL(tty_port_block_til_ready);
-
-int tty_port_close_start(struct tty_port *port,
-                               struct tty_struct *tty, struct file *filp)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               return 0;
-       }
-
-       if (tty->count == 1 && port->count != 1) {
-               printk(KERN_WARNING
-                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
-                                                               port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0) {
-               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
-                                                               port->count);
-               port->count = 0;
-       }
-
-       if (port->count) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->ops->drop)
-                       port->ops->drop(port);
-               return 0;
-       }
-       set_bit(ASYNCB_CLOSING, &port->flags);
-       tty->closing = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-       /* Don't block on a stalled port, just pull the chain */
-       if (tty->flow_stopped)
-               tty_driver_flush_buffer(tty);
-       if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
-                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, port->closing_wait);
-       if (port->drain_delay) {
-               unsigned int bps = tty_get_baud_rate(tty);
-               long timeout;
-
-               if (bps > 1200)
-                       timeout = max_t(long,
-                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
-               else
-                       timeout = 2 * HZ;
-               schedule_timeout_interruptible(timeout);
-       }
-       /* Flush the ldisc buffering */
-       tty_ldisc_flush(tty);
-
-       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
-          hang up the line */
-       if (tty->termios->c_cflag & HUPCL)
-               tty_port_lower_dtr_rts(port);
-
-       /* Don't call port->drop for the last reference. Callers will want
-          to drop the last active reference in ->shutdown() or the tty
-          shutdown path */
-       return 1;
-}
-EXPORT_SYMBOL(tty_port_close_start);
-
-void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty->closing = 0;
-
-       if (port->blocked_open) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->close_delay) {
-                       msleep_interruptible(
-                               jiffies_to_msecs(port->close_delay));
-               }
-               spin_lock_irqsave(&port->lock, flags);
-               wake_up_interruptible(&port->open_wait);
-       }
-       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_close_end);
-
-void tty_port_close(struct tty_port *port, struct tty_struct *tty,
-                                                       struct file *filp)
-{
-       if (tty_port_close_start(port, tty, filp) == 0)
-               return;
-       tty_port_shutdown(port);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_port_close_end(port, tty);
-       tty_port_tty_set(port, NULL);
-}
-EXPORT_SYMBOL(tty_port_close);
-
-int tty_port_open(struct tty_port *port, struct tty_struct *tty,
-                                                       struct file *filp)
-{
-       spin_lock_irq(&port->lock);
-       if (!tty_hung_up_p(filp))
-               ++port->count;
-       spin_unlock_irq(&port->lock);
-       tty_port_tty_set(port, tty);
-
-       /*
-        * Do the device-specific open only if the hardware isn't
-        * already initialized. Serialize open and shutdown using the
-        * port mutex.
-        */
-
-       mutex_lock(&port->mutex);
-
-       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-               if (port->ops->activate) {
-                       int retval = port->ops->activate(port, tty);
-                       if (retval) {
-                               mutex_unlock(&port->mutex);
-                               return retval;
-                       }
-               }
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
-       }
-       mutex_unlock(&port->mutex);
-       return tty_port_block_til_ready(port, tty, filp);
-}
-
-EXPORT_SYMBOL(tty_port_open);
index 493b47a0d511bd1a01dcd8985b76666f66a03971..956ebe2080a584d4a8e7843a9e4110edbc15f7b6 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/math64.h>
-#include <linux/smp_lock.h>
 
 #include <asm/genapic.h>
 #include <asm/uv/uv_hub.h>
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
deleted file mode 100644 (file)
index 273ab44..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * linux/drivers/char/vc_screen.c
- *
- * Provide access to virtual console memory.
- * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
- * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
- *            [minor: N]
- *
- * /dev/vcsaN: idem, but including attributes, and prefixed with
- *     the 4 bytes lines,columns,x,y (as screendump used to give).
- *     Attribute/character pair is in native endianity.
- *            [minor: N+128]
- *
- * This replaces screendump and part of selection, so that the system
- * administrator can control access using file system permissions.
- *
- * aeb@cwi.nl - efter Friedas begravelse - 950211
- *
- * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
- *      - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
- *      - making it shorter - scr_readw are macros which expand in PRETTY long code
- */
-
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/kbd_kern.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/smp_lock.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-#undef attr
-#undef org
-#undef addr
-#define HEADER_SIZE    4
-
-struct vcs_poll_data {
-       struct notifier_block notifier;
-       unsigned int cons_num;
-       bool seen_last_update;
-       wait_queue_head_t waitq;
-       struct fasync_struct *fasync;
-};
-
-static int
-vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
-{
-       struct vt_notifier_param *param = _param;
-       struct vc_data *vc = param->vc;
-       struct vcs_poll_data *poll =
-               container_of(nb, struct vcs_poll_data, notifier);
-       int currcons = poll->cons_num;
-
-       if (code != VT_UPDATE)
-               return NOTIFY_DONE;
-
-       if (currcons == 0)
-               currcons = fg_console;
-       else
-               currcons--;
-       if (currcons != vc->vc_num)
-               return NOTIFY_DONE;
-
-       poll->seen_last_update = false;
-       wake_up_interruptible(&poll->waitq);
-       kill_fasync(&poll->fasync, SIGIO, POLL_IN);
-       return NOTIFY_OK;
-}
-
-static void
-vcs_poll_data_free(struct vcs_poll_data *poll)
-{
-       unregister_vt_notifier(&poll->notifier);
-       kfree(poll);
-}
-
-static struct vcs_poll_data *
-vcs_poll_data_get(struct file *file)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (poll)
-               return poll;
-
-       poll = kzalloc(sizeof(*poll), GFP_KERNEL);
-       if (!poll)
-               return NULL;
-       poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
-       init_waitqueue_head(&poll->waitq);
-       poll->notifier.notifier_call = vcs_notifier;
-       if (register_vt_notifier(&poll->notifier) != 0) {
-               kfree(poll);
-               return NULL;
-       }
-
-       /*
-        * This code may be called either through ->poll() or ->fasync().
-        * If we have two threads using the same file descriptor, they could
-        * both enter this function, both notice that the structure hasn't
-        * been allocated yet and go ahead allocating it in parallel, but
-        * only one of them must survive and be shared otherwise we'd leak
-        * memory with a dangling notifier callback.
-        */
-       spin_lock(&file->f_lock);
-       if (!file->private_data) {
-               file->private_data = poll;
-       } else {
-               /* someone else raced ahead of us */
-               vcs_poll_data_free(poll);
-               poll = file->private_data;
-       }
-       spin_unlock(&file->f_lock);
-
-       return poll;
-}
-
-static int
-vcs_size(struct inode *inode)
-{
-       int size;
-       int minor = iminor(inode);
-       int currcons = minor & 127;
-       struct vc_data *vc;
-
-       if (currcons == 0)
-               currcons = fg_console;
-       else
-               currcons--;
-       if (!vc_cons_allocated(currcons))
-               return -ENXIO;
-       vc = vc_cons[currcons].d;
-
-       size = vc->vc_rows * vc->vc_cols;
-
-       if (minor & 128)
-               size = 2*size + HEADER_SIZE;
-       return size;
-}
-
-static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
-{
-       int size;
-
-       mutex_lock(&con_buf_mtx);
-       size = vcs_size(file->f_path.dentry->d_inode);
-       switch (orig) {
-               default:
-                       mutex_unlock(&con_buf_mtx);
-                       return -EINVAL;
-               case 2:
-                       offset += size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-               case 0:
-                       break;
-       }
-       if (offset < 0 || offset > size) {
-               mutex_unlock(&con_buf_mtx);
-               return -EINVAL;
-       }
-       file->f_pos = offset;
-       mutex_unlock(&con_buf_mtx);
-       return file->f_pos;
-}
-
-
-static ssize_t
-vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       unsigned int currcons = iminor(inode);
-       struct vc_data *vc;
-       struct vcs_poll_data *poll;
-       long pos;
-       long viewed, attr, read;
-       int col, maxcol;
-       unsigned short *org = NULL;
-       ssize_t ret;
-
-       mutex_lock(&con_buf_mtx);
-
-       pos = *ppos;
-
-       /* Select the proper current console and verify
-        * sanity of the situation under the console lock.
-        */
-       acquire_console_sem();
-
-       attr = (currcons & 128);
-       currcons = (currcons & 127);
-       if (currcons == 0) {
-               currcons = fg_console;
-               viewed = 1;
-       } else {
-               currcons--;
-               viewed = 0;
-       }
-       ret = -ENXIO;
-       if (!vc_cons_allocated(currcons))
-               goto unlock_out;
-       vc = vc_cons[currcons].d;
-
-       ret = -EINVAL;
-       if (pos < 0)
-               goto unlock_out;
-       poll = file->private_data;
-       if (count && poll)
-               poll->seen_last_update = true;
-       read = 0;
-       ret = 0;
-       while (count) {
-               char *con_buf0, *con_buf_start;
-               long this_round, size;
-               ssize_t orig_count;
-               long p = pos;
-
-               /* Check whether we are above size each round,
-                * as copy_to_user at the end of this loop
-                * could sleep.
-                */
-               size = vcs_size(inode);
-               if (pos >= size)
-                       break;
-               if (count > size - pos)
-                       count = size - pos;
-
-               this_round = count;
-               if (this_round > CON_BUF_SIZE)
-                       this_round = CON_BUF_SIZE;
-
-               /* Perform the whole read into the local con_buf.
-                * Then we can drop the console spinlock and safely
-                * attempt to move it to userspace.
-                */
-
-               con_buf_start = con_buf0 = con_buf;
-               orig_count = this_round;
-               maxcol = vc->vc_cols;
-               if (!attr) {
-                       org = screen_pos(vc, p, viewed);
-                       col = p % maxcol;
-                       p += maxcol - col;
-                       while (this_round-- > 0) {
-                               *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-               } else {
-                       if (p < HEADER_SIZE) {
-                               size_t tmp_count;
-
-                               con_buf0[0] = (char)vc->vc_rows;
-                               con_buf0[1] = (char)vc->vc_cols;
-                               getconsxy(vc, con_buf0 + 2);
-
-                               con_buf_start += p;
-                               this_round += p;
-                               if (this_round > CON_BUF_SIZE) {
-                                       this_round = CON_BUF_SIZE;
-                                       orig_count = this_round - p;
-                               }
-
-                               tmp_count = HEADER_SIZE;
-                               if (tmp_count > this_round)
-                                       tmp_count = this_round;
-
-                               /* Advance state pointers and move on. */
-                               this_round -= tmp_count;
-                               p = HEADER_SIZE;
-                               con_buf0 = con_buf + HEADER_SIZE;
-                               /* If this_round >= 0, then p is even... */
-                       } else if (p & 1) {
-                               /* Skip first byte for output if start address is odd
-                                * Update region sizes up/down depending on free
-                                * space in buffer.
-                                */
-                               con_buf_start++;
-                               if (this_round < CON_BUF_SIZE)
-                                       this_round++;
-                               else
-                                       orig_count--;
-                       }
-                       if (this_round > 0) {
-                               unsigned short *tmp_buf = (unsigned short *)con_buf0;
-
-                               p -= HEADER_SIZE;
-                               p /= 2;
-                               col = p % maxcol;
-
-                               org = screen_pos(vc, p, viewed);
-                               p += maxcol - col;
-
-                               /* Buffer has even length, so we can always copy
-                                * character + attribute. We do not copy last byte
-                                * to userspace if this_round is odd.
-                                */
-                               this_round = (this_round + 1) >> 1;
-
-                               while (this_round) {
-                                       *tmp_buf++ = vcs_scr_readw(vc, org++);
-                                       this_round --;
-                                       if (++col == maxcol) {
-                                               org = screen_pos(vc, p, viewed);
-                                               col = 0;
-                                               p += maxcol;
-                                       }
-                               }
-                       }
-               }
-
-               /* Finally, release the console semaphore while we push
-                * all the data to userspace from our temporary buffer.
-                *
-                * AKPM: Even though it's a semaphore, we should drop it because
-                * the pagefault handling code may want to call printk().
-                */
-
-               release_console_sem();
-               ret = copy_to_user(buf, con_buf_start, orig_count);
-               acquire_console_sem();
-
-               if (ret) {
-                       read += (orig_count - ret);
-                       ret = -EFAULT;
-                       break;
-               }
-               buf += orig_count;
-               pos += orig_count;
-               read += orig_count;
-               count -= orig_count;
-       }
-       *ppos += read;
-       if (read)
-               ret = read;
-unlock_out:
-       release_console_sem();
-       mutex_unlock(&con_buf_mtx);
-       return ret;
-}
-
-static ssize_t
-vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       unsigned int currcons = iminor(inode);
-       struct vc_data *vc;
-       long pos;
-       long viewed, attr, size, written;
-       char *con_buf0;
-       int col, maxcol;
-       u16 *org0 = NULL, *org = NULL;
-       size_t ret;
-
-       mutex_lock(&con_buf_mtx);
-
-       pos = *ppos;
-
-       /* Select the proper current console and verify
-        * sanity of the situation under the console lock.
-        */
-       acquire_console_sem();
-
-       attr = (currcons & 128);
-       currcons = (currcons & 127);
-
-       if (currcons == 0) {
-               currcons = fg_console;
-               viewed = 1;
-       } else {
-               currcons--;
-               viewed = 0;
-       }
-       ret = -ENXIO;
-       if (!vc_cons_allocated(currcons))
-               goto unlock_out;
-       vc = vc_cons[currcons].d;
-
-       size = vcs_size(inode);
-       ret = -EINVAL;
-       if (pos < 0 || pos > size)
-               goto unlock_out;
-       if (count > size - pos)
-               count = size - pos;
-       written = 0;
-       while (count) {
-               long this_round = count;
-               size_t orig_count;
-               long p;
-
-               if (this_round > CON_BUF_SIZE)
-                       this_round = CON_BUF_SIZE;
-
-               /* Temporarily drop the console lock so that we can read
-                * in the write data from userspace safely.
-                */
-               release_console_sem();
-               ret = copy_from_user(con_buf, buf, this_round);
-               acquire_console_sem();
-
-               if (ret) {
-                       this_round -= ret;
-                       if (!this_round) {
-                               /* Abort loop if no data were copied. Otherwise
-                                * fail with -EFAULT.
-                                */
-                               if (written)
-                                       break;
-                               ret = -EFAULT;
-                               goto unlock_out;
-                       }
-               }
-
-               /* The vcs_size might have changed while we slept to grab
-                * the user buffer, so recheck.
-                * Return data written up to now on failure.
-                */
-               size = vcs_size(inode);
-               if (pos >= size)
-                       break;
-               if (this_round > size - pos)
-                       this_round = size - pos;
-
-               /* OK, now actually push the write to the console
-                * under the lock using the local kernel buffer.
-                */
-
-               con_buf0 = con_buf;
-               orig_count = this_round;
-               maxcol = vc->vc_cols;
-               p = pos;
-               if (!attr) {
-                       org0 = org = screen_pos(vc, p, viewed);
-                       col = p % maxcol;
-                       p += maxcol - col;
-
-                       while (this_round > 0) {
-                               unsigned char c = *con_buf0++;
-
-                               this_round--;
-                               vcs_scr_writew(vc,
-                                              (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-                               org++;
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-               } else {
-                       if (p < HEADER_SIZE) {
-                               char header[HEADER_SIZE];
-
-                               getconsxy(vc, header + 2);
-                               while (p < HEADER_SIZE && this_round > 0) {
-                                       this_round--;
-                                       header[p++] = *con_buf0++;
-                               }
-                               if (!viewed)
-                                       putconsxy(vc, header + 2);
-                       }
-                       p -= HEADER_SIZE;
-                       col = (p/2) % maxcol;
-                       if (this_round > 0) {
-                               org0 = org = screen_pos(vc, p/2, viewed);
-                               if ((p & 1) && this_round > 0) {
-                                       char c;
-
-                                       this_round--;
-                                       c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-                                       vcs_scr_writew(vc, c |
-                                            (vcs_scr_readw(vc, org) & 0xff00), org);
-#else
-                                       vcs_scr_writew(vc, (c << 8) |
-                                            (vcs_scr_readw(vc, org) & 0xff), org);
-#endif
-                                       org++;
-                                       p++;
-                                       if (++col == maxcol) {
-                                               org = screen_pos(vc, p/2, viewed);
-                                               col = 0;
-                                       }
-                               }
-                               p /= 2;
-                               p += maxcol - col;
-                       }
-                       while (this_round > 1) {
-                               unsigned short w;
-
-                               w = get_unaligned(((unsigned short *)con_buf0));
-                               vcs_scr_writew(vc, w, org++);
-                               con_buf0 += 2;
-                               this_round -= 2;
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-                       if (this_round > 0) {
-                               unsigned char c;
-
-                               c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
-#else
-                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-#endif
-                       }
-               }
-               count -= orig_count;
-               written += orig_count;
-               buf += orig_count;
-               pos += orig_count;
-               if (org0)
-                       update_region(vc, (unsigned long)(org0), org - org0);
-       }
-       *ppos += written;
-       ret = written;
-       if (written)
-               vcs_scr_updated(vc);
-
-unlock_out:
-       release_console_sem();
-
-       mutex_unlock(&con_buf_mtx);
-
-       return ret;
-}
-
-static unsigned int
-vcs_poll(struct file *file, poll_table *wait)
-{
-       struct vcs_poll_data *poll = vcs_poll_data_get(file);
-       int ret = 0;
-
-       if (poll) {
-               poll_wait(file, &poll->waitq, wait);
-               if (!poll->seen_last_update)
-                       ret = POLLIN | POLLRDNORM;
-       }
-       return ret;
-}
-
-static int
-vcs_fasync(int fd, struct file *file, int on)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (!poll) {
-               /* don't allocate anything if all we want is disable fasync */
-               if (!on)
-                       return 0;
-               poll = vcs_poll_data_get(file);
-               if (!poll)
-                       return -ENOMEM;
-       }
-
-       return fasync_helper(fd, file, on, &poll->fasync);
-}
-
-static int
-vcs_open(struct inode *inode, struct file *filp)
-{
-       unsigned int currcons = iminor(inode) & 127;
-       int ret = 0;
-       
-       tty_lock();
-       if(currcons && !vc_cons_allocated(currcons-1))
-               ret = -ENXIO;
-       tty_unlock();
-       return ret;
-}
-
-static int vcs_release(struct inode *inode, struct file *file)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (poll)
-               vcs_poll_data_free(poll);
-       return 0;
-}
-
-static const struct file_operations vcs_fops = {
-       .llseek         = vcs_lseek,
-       .read           = vcs_read,
-       .write          = vcs_write,
-       .poll           = vcs_poll,
-       .fasync         = vcs_fasync,
-       .open           = vcs_open,
-       .release        = vcs_release,
-};
-
-static struct class *vc_class;
-
-void vcs_make_sysfs(int index)
-{
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
-                     "vcs%u", index + 1);
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
-                     "vcsa%u", index + 1);
-}
-
-void vcs_remove_sysfs(int index)
-{
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
-}
-
-int __init vcs_init(void)
-{
-       unsigned int i;
-
-       if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
-               panic("unable to get major %d for vcs device", VCS_MAJOR);
-       vc_class = class_create(THIS_MODULE, "vc");
-
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
-       for (i = 0; i < MIN_NR_CONSOLES; i++)
-               vcs_make_sysfs(i);
-       return 0;
-}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
deleted file mode 100644 (file)
index a8ec48e..0000000
+++ /dev/null
@@ -1,4209 +0,0 @@
-/*
- *  linux/drivers/char/vt.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * Hopefully this will be a rather complete VT102 implementation.
- *
- * Beeping thanks to John T Kohl.
- *
- * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
- *   Chars, and VT100 enhancements by Peter MacDonald.
- *
- * Copy and paste function by Andrew Haylett,
- *   some enhancements by Alessandro Rubini.
- *
- * Code to check for different video-cards mostly by Galen Hunt,
- * <g-hunt@ee.utah.edu>
- *
- * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
- * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
- *
- * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
- * Resizing of consoles, aeb, 940926
- *
- * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
- * <poe@daimi.aau.dk>
- *
- * User-defined bell sound, new setterm control sequences and printk
- * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
- *
- * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
- *
- * Merge with the abstract console driver by Geert Uytterhoeven
- * <geert@linux-m68k.org>, Jan 1997.
- *
- *   Original m68k console driver modifications by
- *
- *     - Arno Griffioen <arno@usn.nl>
- *     - David Carter <carter@cs.bris.ac.uk>
- * 
- *   The abstract console driver provides a generic interface for a text
- *   console. It supports VGA text mode, frame buffer based graphical consoles
- *   and special graphics processors that are only accessible through some
- *   registers (e.g. a TMS340x0 GSP).
- *
- *   The interface to the hardware is specified using a special structure
- *   (struct consw) which contains function pointers to console operations
- *   (see <linux/console.h> for more information).
- *
- * Support for changeable cursor shape
- * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
- *
- * Ported to i386 and con_scrolldelta fixed
- * by Emmanuel Marty <core@ggi-project.org>, April 1998
- *
- * Resurrected character buffers in videoram plus lots of other trickery
- * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
- *
- * Removed old-style timers, introduced console_timer, made timer
- * deletion SMP-safe.  17Jun00, Andrew Morton
- *
- * Removed console_lock, enabled interrupts across all console operations
- * 13 March 2001, Andrew Morton
- *
- * Fixed UTF-8 mode so alternate charset modes always work according
- * to control sequences interpreted in do_con_trol function
- * preserving backward VT100 semigraphics compatibility,
- * malformed UTF sequences represented as sequences of replacement glyphs,
- * original codes or '?' as a last resort if replacement glyph is undefined
- * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/smp_lock.h>
-#include <linux/tiocl.h>
-#include <linux/kbd_kern.h>
-#include <linux/consolemap.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/pm.h>
-#include <linux/font.h>
-#include <linux/bitops.h>
-#include <linux/notifier.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <linux/kdb.h>
-#include <linux/ctype.h>
-
-#define MAX_NR_CON_DRIVER 16
-
-#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT   2
-#define CON_DRIVER_FLAG_ATTR   4
-
-struct con_driver {
-       const struct consw *con;
-       const char *desc;
-       struct device *dev;
-       int node;
-       int first;
-       int last;
-       int flag;
-};
-
-static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
-const struct consw *conswitchp;
-
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-
-/*
- * Here is the default bell parameters: 750HZ, 1/8th of a second
- */
-#define DEFAULT_BELL_PITCH     750
-#define DEFAULT_BELL_DURATION  (HZ/8)
-
-struct vc vc_cons [MAX_NR_CONSOLES];
-
-#ifndef VT_SINGLE_DRIVER
-static const struct consw *con_driver_map[MAX_NR_CONSOLES];
-#endif
-
-static int con_open(struct tty_struct *, struct file *);
-static void vc_init(struct vc_data *vc, unsigned int rows,
-                   unsigned int cols, int do_clear);
-static void gotoxy(struct vc_data *vc, int new_x, int new_y);
-static void save_cur(struct vc_data *vc);
-static void reset_terminal(struct vc_data *vc, int do_clear);
-static void con_flush_chars(struct tty_struct *tty);
-static int set_vesa_blanking(char __user *p);
-static void set_cursor(struct vc_data *vc);
-static void hide_cursor(struct vc_data *vc);
-static void console_callback(struct work_struct *ignored);
-static void blank_screen_t(unsigned long dummy);
-static void set_palette(struct vc_data *vc);
-
-static int printable;          /* Is console ready for printing? */
-int default_utf8 = true;
-module_param(default_utf8, int, S_IRUGO | S_IWUSR);
-int global_cursor_default = -1;
-module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
-
-static int cur_default = CUR_DEFAULT;
-module_param(cur_default, int, S_IRUGO | S_IWUSR);
-
-/*
- * ignore_poke: don't unblank the screen when things are typed.  This is
- * mainly for the privacy of braille terminal users.
- */
-static int ignore_poke;
-
-int do_poke_blanked_console;
-int console_blanked;
-
-static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static int vesa_off_interval;
-static int blankinterval = 10*60;
-core_param(consoleblank, blankinterval, int, 0444);
-
-static DECLARE_WORK(console_work, console_callback);
-
-/*
- * fg_console is the current virtual console,
- * last_console is the last used one,
- * want_console is the console we want to switch to,
- * saved_* variants are for save/restore around kernel debugger enter/leave
- */
-int fg_console;
-int last_console;
-int want_console = -1;
-static int saved_fg_console;
-static int saved_last_console;
-static int saved_want_console;
-static int saved_vc_mode;
-static int saved_console_blanked;
-
-/*
- * For each existing display, we have a pointer to console currently visible
- * on that display, allowing consoles other than fg_console to be refreshed
- * appropriately. Unless the low-level driver supplies its own display_fg
- * variable, we use this one for the "master display".
- */
-static struct vc_data *master_display_fg;
-
-/*
- * Unfortunately, we need to delay tty echo when we're currently writing to the
- * console since the code is (and always was) not re-entrant, so we schedule
- * all flip requests to process context with schedule-task() and run it from
- * console_callback().
- */
-
-/*
- * For the same reason, we defer scrollback to the console callback.
- */
-static int scrollback_delta;
-
-/*
- * Hook so that the power management routines can (un)blank
- * the console on our behalf.
- */
-int (*console_blank_hook)(int);
-
-static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
-static int blank_state;
-static int blank_timer_expired;
-enum {
-       blank_off = 0,
-       blank_normal_wait,
-       blank_vesa_wait,
-};
-
-/*
- * Notifier list for console events.
- */
-static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
-
-int register_vt_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_vt_notifier);
-
-int unregister_vt_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_vt_notifier);
-
-static void notify_write(struct vc_data *vc, unsigned int unicode)
-{
-       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
-       atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
-}
-
-static void notify_update(struct vc_data *vc)
-{
-       struct vt_notifier_param param = { .vc = vc };
-       atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
-}
-/*
- *     Low-Level Functions
- */
-
-#define IS_FG(vc)      ((vc)->vc_num == fg_console)
-
-#ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE(vc)  0
-#else
-#define DO_UPDATE(vc)  (CON_IS_VISIBLE(vc) && !console_blanked)
-#endif
-
-static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
-{
-       unsigned short *p;
-       
-       if (!viewed)
-               p = (unsigned short *)(vc->vc_origin + offset);
-       else if (!vc->vc_sw->con_screen_pos)
-               p = (unsigned short *)(vc->vc_visible_origin + offset);
-       else
-               p = vc->vc_sw->con_screen_pos(vc, offset);
-       return p;
-}
-
-/* Called  from the keyboard irq path.. */
-static inline void scrolldelta(int lines)
-{
-       /* FIXME */
-       /* scrolldelta needs some kind of consistency lock, but the BKL was
-          and still is not protecting versus the scheduled back end */
-       scrollback_delta += lines;
-       schedule_console_callback();
-}
-
-void schedule_console_callback(void)
-{
-       schedule_work(&console_work);
-}
-
-static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-       unsigned short *d, *s;
-
-       if (t+nr >= b)
-               nr = b - t - 1;
-       if (b > vc->vc_rows || t >= b || nr < 1)
-               return;
-       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
-               return;
-       d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
-       scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
-                   vc->vc_size_row * nr);
-}
-
-static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-       unsigned short *s;
-       unsigned int step;
-
-       if (t+nr >= b)
-               nr = b - t - 1;
-       if (b > vc->vc_rows || t >= b || nr < 1)
-               return;
-       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
-               return;
-       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-       step = vc->vc_cols * nr;
-       scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
-}
-
-static void do_update_region(struct vc_data *vc, unsigned long start, int count)
-{
-#ifndef VT_BUF_VRAM_ONLY
-       unsigned int xx, yy, offset;
-       u16 *p;
-
-       p = (u16 *) start;
-       if (!vc->vc_sw->con_getxy) {
-               offset = (start - vc->vc_origin) / 2;
-               xx = offset % vc->vc_cols;
-               yy = offset / vc->vc_cols;
-       } else {
-               int nxx, nyy;
-               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
-               xx = nxx; yy = nyy;
-       }
-       for(;;) {
-               u16 attrib = scr_readw(p) & 0xff00;
-               int startx = xx;
-               u16 *q = p;
-               while (xx < vc->vc_cols && count) {
-                       if (attrib != (scr_readw(p) & 0xff00)) {
-                               if (p > q)
-                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-                               startx = xx;
-                               q = p;
-                               attrib = scr_readw(p) & 0xff00;
-                       }
-                       p++;
-                       xx++;
-                       count--;
-               }
-               if (p > q)
-                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-               if (!count)
-                       break;
-               xx = 0;
-               yy++;
-               if (vc->vc_sw->con_getxy) {
-                       p = (u16 *)start;
-                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
-               }
-       }
-#endif
-}
-
-void update_region(struct vc_data *vc, unsigned long start, int count)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (DO_UPDATE(vc)) {
-               hide_cursor(vc);
-               do_update_region(vc, start, count);
-               set_cursor(vc);
-       }
-}
-
-/* Structure of attributes is hardware-dependent */
-
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
-    u8 _underline, u8 _reverse, u8 _italic)
-{
-       if (vc->vc_sw->con_build_attr)
-               return vc->vc_sw->con_build_attr(vc, _color, _intensity,
-                      _blink, _underline, _reverse, _italic);
-
-#ifndef VT_BUF_VRAM_ONLY
-/*
- * ++roman: I completely changed the attribute format for monochrome
- * mode (!can_do_color). The formerly used MDA (monochrome display
- * adapter) format didn't allow the combination of certain effects.
- * Now the attribute is just a bit vector:
- *  Bit 0..1: intensity (0..2)
- *  Bit 2   : underline
- *  Bit 3   : reverse
- *  Bit 7   : blink
- */
-       {
-       u8 a = _color;
-       if (!vc->vc_can_do_color)
-               return _intensity |
-                      (_italic ? 2 : 0) |
-                      (_underline ? 4 : 0) |
-                      (_reverse ? 8 : 0) |
-                      (_blink ? 0x80 : 0);
-       if (_italic)
-               a = (a & 0xF0) | vc->vc_itcolor;
-       else if (_underline)
-               a = (a & 0xf0) | vc->vc_ulcolor;
-       else if (_intensity == 0)
-               a = (a & 0xf0) | vc->vc_ulcolor;
-       if (_reverse)
-               a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
-       if (_blink)
-               a ^= 0x80;
-       if (_intensity == 2)
-               a ^= 0x08;
-       if (vc->vc_hi_font_mask == 0x100)
-               a <<= 1;
-       return a;
-       }
-#else
-       return 0;
-#endif
-}
-
-static void update_attr(struct vc_data *vc)
-{
-       vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
-                     vc->vc_blink, vc->vc_underline,
-                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
-       vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
-{
-       unsigned short *p;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       count /= 2;
-       p = screenpos(vc, offset, viewed);
-       if (vc->vc_sw->con_invert_region)
-               vc->vc_sw->con_invert_region(vc, p, count);
-#ifndef VT_BUF_VRAM_ONLY
-       else {
-               u16 *q = p;
-               int cnt = count;
-               u16 a;
-
-               if (!vc->vc_can_do_color) {
-                       while (cnt--) {
-                           a = scr_readw(q);
-                           a ^= 0x0800;
-                           scr_writew(a, q);
-                           q++;
-                       }
-               } else if (vc->vc_hi_font_mask == 0x100) {
-                       while (cnt--) {
-                               a = scr_readw(q);
-                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
-                               scr_writew(a, q);
-                               q++;
-                       }
-               } else {
-                       while (cnt--) {
-                               a = scr_readw(q);
-                               a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-                               scr_writew(a, q);
-                               q++;
-                       }
-               }
-       }
-#endif
-       if (DO_UPDATE(vc))
-               do_update_region(vc, (unsigned long) p, count);
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(struct vc_data *vc, int offset)
-{
-       static int old_offset = -1;
-       static unsigned short old;
-       static unsigned short oldx, oldy;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (old_offset != -1 && old_offset >= 0 &&
-           old_offset < vc->vc_screenbuf_size) {
-               scr_writew(old, screenpos(vc, old_offset, 1));
-               if (DO_UPDATE(vc))
-                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
-       }
-
-       old_offset = offset;
-
-       if (offset != -1 && offset >= 0 &&
-           offset < vc->vc_screenbuf_size) {
-               unsigned short new;
-               unsigned short *p;
-               p = screenpos(vc, offset, 1);
-               old = scr_readw(p);
-               new = old ^ vc->vc_complement_mask;
-               scr_writew(new, p);
-               if (DO_UPDATE(vc)) {
-                       oldx = (offset >> 1) % vc->vc_cols;
-                       oldy = (offset >> 1) / vc->vc_cols;
-                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
-               }
-       }
-
-}
-
-static void insert_char(struct vc_data *vc, unsigned int nr)
-{
-       unsigned short *p, *q = (unsigned short *)vc->vc_pos;
-
-       p = q + vc->vc_cols - nr - vc->vc_x;
-       while (--p >= q)
-               scr_writew(scr_readw(p), p + nr);
-       scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
-       vc->vc_need_wrap = 0;
-       if (DO_UPDATE(vc)) {
-               unsigned short oldattr = vc->vc_attr;
-               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
-                                    vc->vc_cols - vc->vc_x - nr);
-               vc->vc_attr = vc->vc_video_erase_char >> 8;
-               while (nr--)
-                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
-               vc->vc_attr = oldattr;
-       }
-}
-
-static void delete_char(struct vc_data *vc, unsigned int nr)
-{
-       unsigned int i = vc->vc_x;
-       unsigned short *p = (unsigned short *)vc->vc_pos;
-
-       while (++i <= vc->vc_cols - nr) {
-               scr_writew(scr_readw(p+nr), p);
-               p++;
-       }
-       scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
-       vc->vc_need_wrap = 0;
-       if (DO_UPDATE(vc)) {
-               unsigned short oldattr = vc->vc_attr;
-               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
-                                    vc->vc_cols - vc->vc_x - nr);
-               vc->vc_attr = vc->vc_video_erase_char >> 8;
-               while (nr--)
-                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
-                                    vc->vc_cols - 1 - nr);
-               vc->vc_attr = oldattr;
-       }
-}
-
-static int softcursor_original;
-
-static void add_softcursor(struct vc_data *vc)
-{
-       int i = scr_readw((u16 *) vc->vc_pos);
-       u32 type = vc->vc_cursor_type;
-
-       if (! (type & 0x10)) return;
-       if (softcursor_original != -1) return;
-       softcursor_original = i;
-       i |= ((type >> 8) & 0xff00 );
-       i ^= ((type) & 0xff00 );
-       if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
-       if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
-       scr_writew(i, (u16 *) vc->vc_pos);
-       if (DO_UPDATE(vc))
-               vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
-}
-
-static void hide_softcursor(struct vc_data *vc)
-{
-       if (softcursor_original != -1) {
-               scr_writew(softcursor_original, (u16 *)vc->vc_pos);
-               if (DO_UPDATE(vc))
-                       vc->vc_sw->con_putc(vc, softcursor_original,
-                                       vc->vc_y, vc->vc_x);
-               softcursor_original = -1;
-       }
-}
-
-static void hide_cursor(struct vc_data *vc)
-{
-       if (vc == sel_cons)
-               clear_selection();
-       vc->vc_sw->con_cursor(vc, CM_ERASE);
-       hide_softcursor(vc);
-}
-
-static void set_cursor(struct vc_data *vc)
-{
-       if (!IS_FG(vc) || console_blanked ||
-           vc->vc_mode == KD_GRAPHICS)
-               return;
-       if (vc->vc_deccm) {
-               if (vc == sel_cons)
-                       clear_selection();
-               add_softcursor(vc);
-               if ((vc->vc_cursor_type & 0x0f) != 1)
-                       vc->vc_sw->con_cursor(vc, CM_DRAW);
-       } else
-               hide_cursor(vc);
-}
-
-static void set_origin(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!CON_IS_VISIBLE(vc) ||
-           !vc->vc_sw->con_set_origin ||
-           !vc->vc_sw->con_set_origin(vc))
-               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-       vc->vc_visible_origin = vc->vc_origin;
-       vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
-       vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
-}
-
-static inline void save_screen(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc->vc_sw->con_save_screen)
-               vc->vc_sw->con_save_screen(vc);
-}
-
-/*
- *     Redrawing of screen
- */
-
-static void clear_buffer_attributes(struct vc_data *vc)
-{
-       unsigned short *p = (unsigned short *)vc->vc_origin;
-       int count = vc->vc_screenbuf_size / 2;
-       int mask = vc->vc_hi_font_mask | 0xff;
-
-       for (; count > 0; count--, p++) {
-               scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
-       }
-}
-
-void redraw_screen(struct vc_data *vc, int is_switch)
-{
-       int redraw = 0;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!vc) {
-               /* strange ... */
-               /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
-               return;
-       }
-
-       if (is_switch) {
-               struct vc_data *old_vc = vc_cons[fg_console].d;
-               if (old_vc == vc)
-                       return;
-               if (!CON_IS_VISIBLE(vc))
-                       redraw = 1;
-               *vc->vc_display_fg = vc;
-               fg_console = vc->vc_num;
-               hide_cursor(old_vc);
-               if (!CON_IS_VISIBLE(old_vc)) {
-                       save_screen(old_vc);
-                       set_origin(old_vc);
-               }
-       } else {
-               hide_cursor(vc);
-               redraw = 1;
-       }
-
-       if (redraw) {
-               int update;
-               int old_was_color = vc->vc_can_do_color;
-
-               set_origin(vc);
-               update = vc->vc_sw->con_switch(vc);
-               set_palette(vc);
-               /*
-                * If console changed from mono<->color, the best we can do
-                * is to clear the buffer attributes. As it currently stands,
-                * rebuilding new attributes from the old buffer is not doable
-                * without overly complex code.
-                */
-               if (old_was_color != vc->vc_can_do_color) {
-                       update_attr(vc);
-                       clear_buffer_attributes(vc);
-               }
-
-               /* Forcibly update if we're panicing */
-               if ((update && vc->vc_mode != KD_GRAPHICS) ||
-                   vt_force_oops_output(vc))
-                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-       }
-       set_cursor(vc);
-       if (is_switch) {
-               set_leds();
-               compute_shiftstate();
-               notify_update(vc);
-       }
-}
-
-/*
- *     Allocation, freeing and resizing of VTs.
- */
-
-int vc_cons_allocated(unsigned int i)
-{
-       return (i < MAX_NR_CONSOLES && vc_cons[i].d);
-}
-
-static void visual_init(struct vc_data *vc, int num, int init)
-{
-       /* ++Geert: vc->vc_sw->con_init determines console size */
-       if (vc->vc_sw)
-               module_put(vc->vc_sw->owner);
-       vc->vc_sw = conswitchp;
-#ifndef VT_SINGLE_DRIVER
-       if (con_driver_map[num])
-               vc->vc_sw = con_driver_map[num];
-#endif
-       __module_get(vc->vc_sw->owner);
-       vc->vc_num = num;
-       vc->vc_display_fg = &master_display_fg;
-       vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
-       vc->vc_uni_pagedir = 0;
-       vc->vc_hi_font_mask = 0;
-       vc->vc_complement_mask = 0;
-       vc->vc_can_do_color = 0;
-       vc->vc_panic_force_write = false;
-       vc->vc_sw->con_init(vc, init);
-       if (!vc->vc_complement_mask)
-               vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
-       vc->vc_s_complement_mask = vc->vc_complement_mask;
-       vc->vc_size_row = vc->vc_cols << 1;
-       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-}
-
-int vc_allocate(unsigned int currcons) /* return 0 on success */
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (currcons >= MAX_NR_CONSOLES)
-               return -ENXIO;
-       if (!vc_cons[currcons].d) {
-           struct vc_data *vc;
-           struct vt_notifier_param param;
-
-           /* prevent users from taking too much memory */
-           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
-             return -EPERM;
-
-           /* due to the granularity of kmalloc, we waste some memory here */
-           /* the alloc is done in two steps, to optimize the common situation
-              of a 25x80 console (structsize=216, screenbuf_size=4000) */
-           /* although the numbers above are not valid since long ago, the
-              point is still up-to-date and the comment still has its value
-              even if only as a historical artifact.  --mj, July 1998 */
-           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
-           if (!vc)
-               return -ENOMEM;
-           vc_cons[currcons].d = vc;
-           tty_port_init(&vc->port);
-           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-           visual_init(vc, currcons, 1);
-           if (!*vc->vc_uni_pagedir_loc)
-               con_set_default_unimap(vc);
-           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
-           if (!vc->vc_screenbuf) {
-               kfree(vc);
-               vc_cons[currcons].d = NULL;
-               return -ENOMEM;
-           }
-
-           /* If no drivers have overridden us and the user didn't pass a
-              boot option, default to displaying the cursor */
-           if (global_cursor_default == -1)
-                   global_cursor_default = 1;
-
-           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
-           vcs_make_sysfs(currcons);
-           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
-       }
-       return 0;
-}
-
-static inline int resize_screen(struct vc_data *vc, int width, int height,
-                               int user)
-{
-       /* Resizes the resolution of the display adapater */
-       int err = 0;
-
-       if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
-               err = vc->vc_sw->con_resize(vc, width, height, user);
-
-       return err;
-}
-
-/*
- * Change # of rows and columns (0 means unchanged/the size of fg_console)
- * [this is to be used together with some user program
- * like resize that changes the hardware videomode]
- */
-#define VC_RESIZE_MAXCOL (32767)
-#define VC_RESIZE_MAXROW (32767)
-
-/**
- *     vc_do_resize    -       resizing method for the tty
- *     @tty: tty being resized
- *     @real_tty: real tty (different to tty if a pty/tty pair)
- *     @vc: virtual console private data
- *     @cols: columns
- *     @lines: lines
- *
- *     Resize a virtual console, clipping according to the actual constraints.
- *     If the caller passes a tty structure then update the termios winsize
- *     information and perform any necessary signal handling.
- *
- *     Caller must hold the console semaphore. Takes the termios mutex and
- *     ctrl_lock of the tty IFF a tty is passed.
- */
-
-static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
-                               unsigned int cols, unsigned int lines)
-{
-       unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
-       unsigned long end;
-       unsigned int old_cols, old_rows, old_row_size, old_screen_size;
-       unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-       unsigned int user;
-       unsigned short *newscreen;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!vc)
-               return -ENXIO;
-
-       user = vc->vc_resize_user;
-       vc->vc_resize_user = 0;
-
-       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
-               return -EINVAL;
-
-       new_cols = (cols ? cols : vc->vc_cols);
-       new_rows = (lines ? lines : vc->vc_rows);
-       new_row_size = new_cols << 1;
-       new_screen_size = new_row_size * new_rows;
-
-       if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
-               return 0;
-
-       newscreen = kmalloc(new_screen_size, GFP_USER);
-       if (!newscreen)
-               return -ENOMEM;
-
-       old_rows = vc->vc_rows;
-       old_cols = vc->vc_cols;
-       old_row_size = vc->vc_size_row;
-       old_screen_size = vc->vc_screenbuf_size;
-
-       err = resize_screen(vc, new_cols, new_rows, user);
-       if (err) {
-               kfree(newscreen);
-               return err;
-       }
-
-       vc->vc_rows = new_rows;
-       vc->vc_cols = new_cols;
-       vc->vc_size_row = new_row_size;
-       vc->vc_screenbuf_size = new_screen_size;
-
-       rlth = min(old_row_size, new_row_size);
-       rrem = new_row_size - rlth;
-       old_origin = vc->vc_origin;
-       new_origin = (long) newscreen;
-       new_scr_end = new_origin + new_screen_size;
-
-       if (vc->vc_y > new_rows) {
-               if (old_rows - vc->vc_y < new_rows) {
-                       /*
-                        * Cursor near the bottom, copy contents from the
-                        * bottom of buffer
-                        */
-                       old_origin += (old_rows - new_rows) * old_row_size;
-               } else {
-                       /*
-                        * Cursor is in no man's land, copy 1/2 screenful
-                        * from the top and bottom of cursor position
-                        */
-                       old_origin += (vc->vc_y - new_rows/2) * old_row_size;
-               }
-       }
-
-       end = old_origin + old_row_size * min(old_rows, new_rows);
-
-       update_attr(vc);
-
-       while (old_origin < end) {
-               scr_memcpyw((unsigned short *) new_origin,
-                           (unsigned short *) old_origin, rlth);
-               if (rrem)
-                       scr_memsetw((void *)(new_origin + rlth),
-                                   vc->vc_video_erase_char, rrem);
-               old_origin += old_row_size;
-               new_origin += new_row_size;
-       }
-       if (new_scr_end > new_origin)
-               scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
-                           new_scr_end - new_origin);
-       kfree(vc->vc_screenbuf);
-       vc->vc_screenbuf = newscreen;
-       vc->vc_screenbuf_size = new_screen_size;
-       set_origin(vc);
-
-       /* do part of a reset_terminal() */
-       vc->vc_top = 0;
-       vc->vc_bottom = vc->vc_rows;
-       gotoxy(vc, vc->vc_x, vc->vc_y);
-       save_cur(vc);
-
-       if (tty) {
-               /* Rewrite the requested winsize data with the actual
-                  resulting sizes */
-               struct winsize ws;
-               memset(&ws, 0, sizeof(ws));
-               ws.ws_row = vc->vc_rows;
-               ws.ws_col = vc->vc_cols;
-               ws.ws_ypixel = vc->vc_scan_lines;
-               tty_do_resize(tty, &ws);
-       }
-
-       if (CON_IS_VISIBLE(vc))
-               update_screen(vc);
-       vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
-       return err;
-}
-
-/**
- *     vc_resize               -       resize a VT
- *     @vc: virtual console
- *     @cols: columns
- *     @rows: rows
- *
- *     Resize a virtual console as seen from the console end of things. We
- *     use the common vc_do_resize methods to update the structures. The
- *     caller must hold the console sem to protect console internals and
- *     vc->port.tty
- */
-
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
-{
-       return vc_do_resize(vc->port.tty, vc, cols, rows);
-}
-
-/**
- *     vt_resize               -       resize a VT
- *     @tty: tty to resize
- *     @ws: winsize attributes
- *
- *     Resize a virtual terminal. This is called by the tty layer as we
- *     register our own handler for resizing. The mutual helper does all
- *     the actual work.
- *
- *     Takes the console sem and the called methods then take the tty
- *     termios_mutex and the tty ctrl_lock in that order.
- */
-static int vt_resize(struct tty_struct *tty, struct winsize *ws)
-{
-       struct vc_data *vc = tty->driver_data;
-       int ret;
-
-       acquire_console_sem();
-       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
-       release_console_sem();
-       return ret;
-}
-
-void vc_deallocate(unsigned int currcons)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc_cons_allocated(currcons)) {
-               struct vc_data *vc = vc_cons[currcons].d;
-               struct vt_notifier_param param = { .vc = vc };
-
-               atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
-               vcs_remove_sysfs(currcons);
-               vc->vc_sw->con_deinit(vc);
-               put_pid(vc->vt_pid);
-               module_put(vc->vc_sw->owner);
-               kfree(vc->vc_screenbuf);
-               if (currcons >= MIN_NR_CONSOLES)
-                       kfree(vc);
-               vc_cons[currcons].d = NULL;
-       }
-}
-
-/*
- *     VT102 emulator
- */
-
-#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define is_kbd(vc, x)  vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-
-#define decarm         VC_REPEAT
-#define decckm         VC_CKMODE
-#define kbdapplic      VC_APPLIC
-#define lnm            VC_CRLF
-
-/*
- * this is what the terminal answers to a ESC-Z or csi0c query.
- */
-#define VT100ID "\033[?1;2c"
-#define VT102ID "\033[?6c"
-
-unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
-                                      8,12,10,14, 9,13,11,15 };
-
-/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
-    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
-    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
-    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
-
-module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
-
-/*
- * gotoxy() must verify all boundaries, because the arguments
- * might also be negative. If the given position is out of
- * bounds, the cursor is placed at the nearest margin.
- */
-static void gotoxy(struct vc_data *vc, int new_x, int new_y)
-{
-       int min_y, max_y;
-
-       if (new_x < 0)
-               vc->vc_x = 0;
-       else {
-               if (new_x >= vc->vc_cols)
-                       vc->vc_x = vc->vc_cols - 1;
-               else
-                       vc->vc_x = new_x;
-       }
-
-       if (vc->vc_decom) {
-               min_y = vc->vc_top;
-               max_y = vc->vc_bottom;
-       } else {
-               min_y = 0;
-               max_y = vc->vc_rows;
-       }
-       if (new_y < min_y)
-               vc->vc_y = min_y;
-       else if (new_y >= max_y)
-               vc->vc_y = max_y - 1;
-       else
-               vc->vc_y = new_y;
-       vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
-       vc->vc_need_wrap = 0;
-}
-
-/* for absolute user moves, when decom is set */
-static void gotoxay(struct vc_data *vc, int new_x, int new_y)
-{
-       gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
-}
-
-void scrollback(struct vc_data *vc, int lines)
-{
-       if (!lines)
-               lines = vc->vc_rows / 2;
-       scrolldelta(-lines);
-}
-
-void scrollfront(struct vc_data *vc, int lines)
-{
-       if (!lines)
-               lines = vc->vc_rows / 2;
-       scrolldelta(lines);
-}
-
-static void lf(struct vc_data *vc)
-{
-       /* don't scroll if above bottom of scrolling region, or
-        * if below scrolling region
-        */
-       if (vc->vc_y + 1 == vc->vc_bottom)
-               scrup(vc, vc->vc_top, vc->vc_bottom, 1);
-       else if (vc->vc_y < vc->vc_rows - 1) {
-               vc->vc_y++;
-               vc->vc_pos += vc->vc_size_row;
-       }
-       vc->vc_need_wrap = 0;
-       notify_write(vc, '\n');
-}
-
-static void ri(struct vc_data *vc)
-{
-       /* don't scroll if below top of scrolling region, or
-        * if above scrolling region
-        */
-       if (vc->vc_y == vc->vc_top)
-               scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
-       else if (vc->vc_y > 0) {
-               vc->vc_y--;
-               vc->vc_pos -= vc->vc_size_row;
-       }
-       vc->vc_need_wrap = 0;
-}
-
-static inline void cr(struct vc_data *vc)
-{
-       vc->vc_pos -= vc->vc_x << 1;
-       vc->vc_need_wrap = vc->vc_x = 0;
-       notify_write(vc, '\r');
-}
-
-static inline void bs(struct vc_data *vc)
-{
-       if (vc->vc_x) {
-               vc->vc_pos -= 2;
-               vc->vc_x--;
-               vc->vc_need_wrap = 0;
-               notify_write(vc, '\b');
-       }
-}
-
-static inline void del(struct vc_data *vc)
-{
-       /* ignored */
-}
-
-static void csi_J(struct vc_data *vc, int vpar)
-{
-       unsigned int count;
-       unsigned short * start;
-
-       switch (vpar) {
-               case 0: /* erase from cursor to end of display */
-                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
-                       start = (unsigned short *)vc->vc_pos;
-                       if (DO_UPDATE(vc)) {
-                               /* do in two stages */
-                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-                                             vc->vc_cols - vc->vc_x);
-                               vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
-                                             vc->vc_rows - vc->vc_y - 1,
-                                             vc->vc_cols);
-                       }
-                       break;
-               case 1: /* erase from start to cursor */
-                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
-                       start = (unsigned short *)vc->vc_origin;
-                       if (DO_UPDATE(vc)) {
-                               /* do in two stages */
-                               vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
-                                             vc->vc_cols);
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                             vc->vc_x + 1);
-                       }
-                       break;
-               case 2: /* erase whole display */
-                       count = vc->vc_cols * vc->vc_rows;
-                       start = (unsigned short *)vc->vc_origin;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, 0, 0,
-                                             vc->vc_rows,
-                                             vc->vc_cols);
-                       break;
-               default:
-                       return;
-       }
-       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-       vc->vc_need_wrap = 0;
-}
-
-static void csi_K(struct vc_data *vc, int vpar)
-{
-       unsigned int count;
-       unsigned short * start;
-
-       switch (vpar) {
-               case 0: /* erase from cursor to end of line */
-                       count = vc->vc_cols - vc->vc_x;
-                       start = (unsigned short *)vc->vc_pos;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-                                                    vc->vc_cols - vc->vc_x);
-                       break;
-               case 1: /* erase from start of line to cursor */
-                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-                       count = vc->vc_x + 1;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                                    vc->vc_x + 1);
-                       break;
-               case 2: /* erase whole line */
-                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-                       count = vc->vc_cols;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                             vc->vc_cols);
-                       break;
-               default:
-                       return;
-       }
-       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-       vc->vc_need_wrap = 0;
-}
-
-static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
-{                                        /* not vt100? */
-       int count;
-
-       if (!vpar)
-               vpar++;
-       count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
-
-       scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
-       if (DO_UPDATE(vc))
-               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
-       vc->vc_need_wrap = 0;
-}
-
-static void default_attr(struct vc_data *vc)
-{
-       vc->vc_intensity = 1;
-       vc->vc_italic = 0;
-       vc->vc_underline = 0;
-       vc->vc_reverse = 0;
-       vc->vc_blink = 0;
-       vc->vc_color = vc->vc_def_color;
-}
-
-/* console_sem is held */
-static void csi_m(struct vc_data *vc)
-{
-       int i;
-
-       for (i = 0; i <= vc->vc_npar; i++)
-               switch (vc->vc_par[i]) {
-                       case 0: /* all attributes off */
-                               default_attr(vc);
-                               break;
-                       case 1:
-                               vc->vc_intensity = 2;
-                               break;
-                       case 2:
-                               vc->vc_intensity = 0;
-                               break;
-                       case 3:
-                               vc->vc_italic = 1;
-                               break;
-                       case 4:
-                               vc->vc_underline = 1;
-                               break;
-                       case 5:
-                               vc->vc_blink = 1;
-                               break;
-                       case 7:
-                               vc->vc_reverse = 1;
-                               break;
-                       case 10: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select primary font, don't display
-                                 * control chars if defined, don't set
-                                 * bit 8 on output.
-                                 */
-                               vc->vc_translate = set_translate(vc->vc_charset == 0
-                                               ? vc->vc_G0_charset
-                                               : vc->vc_G1_charset, vc);
-                               vc->vc_disp_ctrl = 0;
-                               vc->vc_toggle_meta = 0;
-                               break;
-                       case 11: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select first alternate font, lets
-                                 * chars < 32 be displayed as ROM chars.
-                                 */
-                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
-                               vc->vc_disp_ctrl = 1;
-                               vc->vc_toggle_meta = 0;
-                               break;
-                       case 12: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select second alternate font, toggle
-                                 * high bit before displaying as ROM char.
-                                 */
-                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
-                               vc->vc_disp_ctrl = 1;
-                               vc->vc_toggle_meta = 1;
-                               break;
-                       case 21:
-                       case 22:
-                               vc->vc_intensity = 1;
-                               break;
-                       case 23:
-                               vc->vc_italic = 0;
-                               break;
-                       case 24:
-                               vc->vc_underline = 0;
-                               break;
-                       case 25:
-                               vc->vc_blink = 0;
-                               break;
-                       case 27:
-                               vc->vc_reverse = 0;
-                               break;
-                       case 38: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Enables underscore, white foreground
-                                 * with white underscore (Linux - use
-                                 * default foreground).
-                                 */
-                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-                               vc->vc_underline = 1;
-                               break;
-                       case 39: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Disable underline option.
-                                 * Reset colour to default? It did this
-                                 * before...
-                                 */
-                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-                               vc->vc_underline = 0;
-                               break;
-                       case 49:
-                               vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
-                               break;
-                       default:
-                               if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
-                                       vc->vc_color = color_table[vc->vc_par[i] - 30]
-                                               | (vc->vc_color & 0xf0);
-                               else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
-                                       vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
-                                               | (vc->vc_color & 0x0f);
-                               break;
-               }
-       update_attr(vc);
-}
-
-static void respond_string(const char *p, struct tty_struct *tty)
-{
-       while (*p) {
-               tty_insert_flip_char(tty, *p, 0);
-               p++;
-       }
-       con_schedule_flip(tty);
-}
-
-static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
-{
-       char buf[40];
-
-       sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
-       respond_string(buf, tty);
-}
-
-static inline void status_report(struct tty_struct *tty)
-{
-       respond_string("\033[0n", tty); /* Terminal ok */
-}
-
-static inline void respond_ID(struct tty_struct * tty)
-{
-       respond_string(VT102ID, tty);
-}
-
-void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
-{
-       char buf[8];
-
-       sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
-               (char)('!' + mry));
-       respond_string(buf, tty);
-}
-
-/* invoked via ioctl(TIOCLINUX) and through set_selection */
-int mouse_reporting(void)
-{
-       return vc_cons[fg_console].d->vc_report_mouse;
-}
-
-/* console_sem is held */
-static void set_mode(struct vc_data *vc, int on_off)
-{
-       int i;
-
-       for (i = 0; i <= vc->vc_npar; i++)
-               if (vc->vc_ques) {
-                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
-                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
-                               if (on_off)
-                                       set_kbd(vc, decckm);
-                               else
-                                       clr_kbd(vc, decckm);
-                               break;
-                       case 3: /* 80/132 mode switch unimplemented */
-                               vc->vc_deccolm = on_off;
-#if 0
-                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
-                               /* this alone does not suffice; some user mode
-                                  utility has to change the hardware regs */
-#endif
-                               break;
-                       case 5:                 /* Inverted screen on/off */
-                               if (vc->vc_decscnm != on_off) {
-                                       vc->vc_decscnm = on_off;
-                                       invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
-                                       update_attr(vc);
-                               }
-                               break;
-                       case 6:                 /* Origin relative/absolute */
-                               vc->vc_decom = on_off;
-                               gotoxay(vc, 0, 0);
-                               break;
-                       case 7:                 /* Autowrap on/off */
-                               vc->vc_decawm = on_off;
-                               break;
-                       case 8:                 /* Autorepeat on/off */
-                               if (on_off)
-                                       set_kbd(vc, decarm);
-                               else
-                                       clr_kbd(vc, decarm);
-                               break;
-                       case 9:
-                               vc->vc_report_mouse = on_off ? 1 : 0;
-                               break;
-                       case 25:                /* Cursor on/off */
-                               vc->vc_deccm = on_off;
-                               break;
-                       case 1000:
-                               vc->vc_report_mouse = on_off ? 2 : 0;
-                               break;
-                       }
-               } else {
-                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
-                       case 3:                 /* Monitor (display ctrls) */
-                               vc->vc_disp_ctrl = on_off;
-                               break;
-                       case 4:                 /* Insert Mode on/off */
-                               vc->vc_decim = on_off;
-                               break;
-                       case 20:                /* Lf, Enter == CrLf/Lf */
-                               if (on_off)
-                                       set_kbd(vc, lnm);
-                               else
-                                       clr_kbd(vc, lnm);
-                               break;
-                       }
-               }
-}
-
-/* console_sem is held */
-static void setterm_command(struct vc_data *vc)
-{
-       switch(vc->vc_par[0]) {
-               case 1: /* set color for underline mode */
-                       if (vc->vc_can_do_color &&
-                                       vc->vc_par[1] < 16) {
-                               vc->vc_ulcolor = color_table[vc->vc_par[1]];
-                               if (vc->vc_underline)
-                                       update_attr(vc);
-                       }
-                       break;
-               case 2: /* set color for half intensity mode */
-                       if (vc->vc_can_do_color &&
-                                       vc->vc_par[1] < 16) {
-                               vc->vc_halfcolor = color_table[vc->vc_par[1]];
-                               if (vc->vc_intensity == 0)
-                                       update_attr(vc);
-                       }
-                       break;
-               case 8: /* store colors as defaults */
-                       vc->vc_def_color = vc->vc_attr;
-                       if (vc->vc_hi_font_mask == 0x100)
-                               vc->vc_def_color >>= 1;
-                       default_attr(vc);
-                       update_attr(vc);
-                       break;
-               case 9: /* set blanking interval */
-                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
-                       poke_blanked_console();
-                       break;
-               case 10: /* set bell frequency in Hz */
-                       if (vc->vc_npar >= 1)
-                               vc->vc_bell_pitch = vc->vc_par[1];
-                       else
-                               vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-                       break;
-               case 11: /* set bell duration in msec */
-                       if (vc->vc_npar >= 1)
-                               vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
-                                       vc->vc_par[1] * HZ / 1000 : 0;
-                       else
-                               vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-                       break;
-               case 12: /* bring specified console to the front */
-                       if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
-                               set_console(vc->vc_par[1] - 1);
-                       break;
-               case 13: /* unblank the screen */
-                       poke_blanked_console();
-                       break;
-               case 14: /* set vesa powerdown interval */
-                       vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
-                       break;
-               case 15: /* activate the previous console */
-                       set_console(last_console);
-                       break;
-       }
-}
-
-/* console_sem is held */
-static void csi_at(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_cols - vc->vc_x)
-               nr = vc->vc_cols - vc->vc_x;
-       else if (!nr)
-               nr = 1;
-       insert_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_L(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_rows - vc->vc_y)
-               nr = vc->vc_rows - vc->vc_y;
-       else if (!nr)
-               nr = 1;
-       scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
-       vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held */
-static void csi_P(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_cols - vc->vc_x)
-               nr = vc->vc_cols - vc->vc_x;
-       else if (!nr)
-               nr = 1;
-       delete_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_M(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_rows - vc->vc_y)
-               nr = vc->vc_rows - vc->vc_y;
-       else if (!nr)
-               nr=1;
-       scrup(vc, vc->vc_y, vc->vc_bottom, nr);
-       vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held (except via vc_init->reset_terminal */
-static void save_cur(struct vc_data *vc)
-{
-       vc->vc_saved_x          = vc->vc_x;
-       vc->vc_saved_y          = vc->vc_y;
-       vc->vc_s_intensity      = vc->vc_intensity;
-       vc->vc_s_italic         = vc->vc_italic;
-       vc->vc_s_underline      = vc->vc_underline;
-       vc->vc_s_blink          = vc->vc_blink;
-       vc->vc_s_reverse        = vc->vc_reverse;
-       vc->vc_s_charset        = vc->vc_charset;
-       vc->vc_s_color          = vc->vc_color;
-       vc->vc_saved_G0         = vc->vc_G0_charset;
-       vc->vc_saved_G1         = vc->vc_G1_charset;
-}
-
-/* console_sem is held */
-static void restore_cur(struct vc_data *vc)
-{
-       gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
-       vc->vc_intensity        = vc->vc_s_intensity;
-       vc->vc_italic           = vc->vc_s_italic;
-       vc->vc_underline        = vc->vc_s_underline;
-       vc->vc_blink            = vc->vc_s_blink;
-       vc->vc_reverse          = vc->vc_s_reverse;
-       vc->vc_charset          = vc->vc_s_charset;
-       vc->vc_color            = vc->vc_s_color;
-       vc->vc_G0_charset       = vc->vc_saved_G0;
-       vc->vc_G1_charset       = vc->vc_saved_G1;
-       vc->vc_translate        = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
-       update_attr(vc);
-       vc->vc_need_wrap = 0;
-}
-
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
-       EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
-       ESpalette };
-
-/* console_sem is held (except via vc_init()) */
-static void reset_terminal(struct vc_data *vc, int do_clear)
-{
-       vc->vc_top              = 0;
-       vc->vc_bottom           = vc->vc_rows;
-       vc->vc_state            = ESnormal;
-       vc->vc_ques             = 0;
-       vc->vc_translate        = set_translate(LAT1_MAP, vc);
-       vc->vc_G0_charset       = LAT1_MAP;
-       vc->vc_G1_charset       = GRAF_MAP;
-       vc->vc_charset          = 0;
-       vc->vc_need_wrap        = 0;
-       vc->vc_report_mouse     = 0;
-       vc->vc_utf              = default_utf8;
-       vc->vc_utf_count        = 0;
-
-       vc->vc_disp_ctrl        = 0;
-       vc->vc_toggle_meta      = 0;
-
-       vc->vc_decscnm          = 0;
-       vc->vc_decom            = 0;
-       vc->vc_decawm           = 1;
-       vc->vc_deccm            = global_cursor_default;
-       vc->vc_decim            = 0;
-
-       set_kbd(vc, decarm);
-       clr_kbd(vc, decckm);
-       clr_kbd(vc, kbdapplic);
-       clr_kbd(vc, lnm);
-       kbd_table[vc->vc_num].lockstate = 0;
-       kbd_table[vc->vc_num].slockstate = 0;
-       kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
-       kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
-       /* do not do set_leds here because this causes an endless tasklet loop
-          when the keyboard hasn't been initialized yet */
-
-       vc->vc_cursor_type = cur_default;
-       vc->vc_complement_mask = vc->vc_s_complement_mask;
-
-       default_attr(vc);
-       update_attr(vc);
-
-       vc->vc_tab_stop[0]      = 0x01010100;
-       vc->vc_tab_stop[1]      =
-       vc->vc_tab_stop[2]      =
-       vc->vc_tab_stop[3]      =
-       vc->vc_tab_stop[4]      =
-       vc->vc_tab_stop[5]      =
-       vc->vc_tab_stop[6]      =
-       vc->vc_tab_stop[7]      = 0x01010101;
-
-       vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-       vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-
-       gotoxy(vc, 0, 0);
-       save_cur(vc);
-       if (do_clear)
-           csi_J(vc, 2);
-}
-
-/* console_sem is held */
-static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
-{
-       /*
-        *  Control characters can be used in the _middle_
-        *  of an escape sequence.
-        */
-       switch (c) {
-       case 0:
-               return;
-       case 7:
-               if (vc->vc_bell_duration)
-                       kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
-               return;
-       case 8:
-               bs(vc);
-               return;
-       case 9:
-               vc->vc_pos -= (vc->vc_x << 1);
-               while (vc->vc_x < vc->vc_cols - 1) {
-                       vc->vc_x++;
-                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
-                               break;
-               }
-               vc->vc_pos += (vc->vc_x << 1);
-               notify_write(vc, '\t');
-               return;
-       case 10: case 11: case 12:
-               lf(vc);
-               if (!is_kbd(vc, lnm))
-                       return;
-       case 13:
-               cr(vc);
-               return;
-       case 14:
-               vc->vc_charset = 1;
-               vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-               vc->vc_disp_ctrl = 1;
-               return;
-       case 15:
-               vc->vc_charset = 0;
-               vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-               vc->vc_disp_ctrl = 0;
-               return;
-       case 24: case 26:
-               vc->vc_state = ESnormal;
-               return;
-       case 27:
-               vc->vc_state = ESesc;
-               return;
-       case 127:
-               del(vc);
-               return;
-       case 128+27:
-               vc->vc_state = ESsquare;
-               return;
-       }
-       switch(vc->vc_state) {
-       case ESesc:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '[':
-                       vc->vc_state = ESsquare;
-                       return;
-               case ']':
-                       vc->vc_state = ESnonstd;
-                       return;
-               case '%':
-                       vc->vc_state = ESpercent;
-                       return;
-               case 'E':
-                       cr(vc);
-                       lf(vc);
-                       return;
-               case 'M':
-                       ri(vc);
-                       return;
-               case 'D':
-                       lf(vc);
-                       return;
-               case 'H':
-                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
-                       return;
-               case 'Z':
-                       respond_ID(tty);
-                       return;
-               case '7':
-                       save_cur(vc);
-                       return;
-               case '8':
-                       restore_cur(vc);
-                       return;
-               case '(':
-                       vc->vc_state = ESsetG0;
-                       return;
-               case ')':
-                       vc->vc_state = ESsetG1;
-                       return;
-               case '#':
-                       vc->vc_state = EShash;
-                       return;
-               case 'c':
-                       reset_terminal(vc, 1);
-                       return;
-               case '>':  /* Numeric keypad */
-                       clr_kbd(vc, kbdapplic);
-                       return;
-               case '=':  /* Appl. keypad */
-                       set_kbd(vc, kbdapplic);
-                       return;
-               }
-               return;
-       case ESnonstd:
-               if (c=='P') {   /* palette escape sequence */
-                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                               vc->vc_par[vc->vc_npar] = 0;
-                       vc->vc_npar = 0;
-                       vc->vc_state = ESpalette;
-                       return;
-               } else if (c=='R') {   /* reset palette */
-                       reset_palette(vc);
-                       vc->vc_state = ESnormal;
-               } else
-                       vc->vc_state = ESnormal;
-               return;
-       case ESpalette:
-               if (isxdigit(c)) {
-                       vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
-                       if (vc->vc_npar == 7) {
-                               int i = vc->vc_par[0] * 3, j = 1;
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i++] += vc->vc_par[j++];
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i++] += vc->vc_par[j++];
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i] += vc->vc_par[j];
-                               set_palette(vc);
-                               vc->vc_state = ESnormal;
-                       }
-               } else
-                       vc->vc_state = ESnormal;
-               return;
-       case ESsquare:
-               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                       vc->vc_par[vc->vc_npar] = 0;
-               vc->vc_npar = 0;
-               vc->vc_state = ESgetpars;
-               if (c == '[') { /* Function key */
-                       vc->vc_state=ESfunckey;
-                       return;
-               }
-               vc->vc_ques = (c == '?');
-               if (vc->vc_ques)
-                       return;
-       case ESgetpars:
-               if (c == ';' && vc->vc_npar < NPAR - 1) {
-                       vc->vc_npar++;
-                       return;
-               } else if (c>='0' && c<='9') {
-                       vc->vc_par[vc->vc_npar] *= 10;
-                       vc->vc_par[vc->vc_npar] += c - '0';
-                       return;
-               } else
-                       vc->vc_state = ESgotpars;
-       case ESgotpars:
-               vc->vc_state = ESnormal;
-               switch(c) {
-               case 'h':
-                       set_mode(vc, 1);
-                       return;
-               case 'l':
-                       set_mode(vc, 0);
-                       return;
-               case 'c':
-                       if (vc->vc_ques) {
-                               if (vc->vc_par[0])
-                                       vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
-                               else
-                                       vc->vc_cursor_type = cur_default;
-                               return;
-                       }
-                       break;
-               case 'm':
-                       if (vc->vc_ques) {
-                               clear_selection();
-                               if (vc->vc_par[0])
-                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
-                               else
-                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
-                               return;
-                       }
-                       break;
-               case 'n':
-                       if (!vc->vc_ques) {
-                               if (vc->vc_par[0] == 5)
-                                       status_report(tty);
-                               else if (vc->vc_par[0] == 6)
-                                       cursor_report(vc, tty);
-                       }
-                       return;
-               }
-               if (vc->vc_ques) {
-                       vc->vc_ques = 0;
-                       return;
-               }
-               switch(c) {
-               case 'G': case '`':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxy(vc, vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'A':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
-                       return;
-               case 'B': case 'e':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
-                       return;
-               case 'C': case 'a':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'D':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'E':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
-                       return;
-               case 'F':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
-                       return;
-               case 'd':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
-                       return;
-               case 'H': case 'f':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       if (vc->vc_par[1])
-                               vc->vc_par[1]--;
-                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
-                       return;
-               case 'J':
-                       csi_J(vc, vc->vc_par[0]);
-                       return;
-               case 'K':
-                       csi_K(vc, vc->vc_par[0]);
-                       return;
-               case 'L':
-                       csi_L(vc, vc->vc_par[0]);
-                       return;
-               case 'M':
-                       csi_M(vc, vc->vc_par[0]);
-                       return;
-               case 'P':
-                       csi_P(vc, vc->vc_par[0]);
-                       return;
-               case 'c':
-                       if (!vc->vc_par[0])
-                               respond_ID(tty);
-                       return;
-               case 'g':
-                       if (!vc->vc_par[0])
-                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
-                       else if (vc->vc_par[0] == 3) {
-                               vc->vc_tab_stop[0] =
-                                       vc->vc_tab_stop[1] =
-                                       vc->vc_tab_stop[2] =
-                                       vc->vc_tab_stop[3] =
-                                       vc->vc_tab_stop[4] =
-                                       vc->vc_tab_stop[5] =
-                                       vc->vc_tab_stop[6] =
-                                       vc->vc_tab_stop[7] = 0;
-                       }
-                       return;
-               case 'm':
-                       csi_m(vc);
-                       return;
-               case 'q': /* DECLL - but only 3 leds */
-                       /* map 0,1,2,3 to 0,1,2,4 */
-                       if (vc->vc_par[0] < 4)
-                               setledstate(kbd_table + vc->vc_num,
-                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
-                       return;
-               case 'r':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       if (!vc->vc_par[1])
-                               vc->vc_par[1] = vc->vc_rows;
-                       /* Minimum allowed region is 2 lines */
-                       if (vc->vc_par[0] < vc->vc_par[1] &&
-                           vc->vc_par[1] <= vc->vc_rows) {
-                               vc->vc_top = vc->vc_par[0] - 1;
-                               vc->vc_bottom = vc->vc_par[1];
-                               gotoxay(vc, 0, 0);
-                       }
-                       return;
-               case 's':
-                       save_cur(vc);
-                       return;
-               case 'u':
-                       restore_cur(vc);
-                       return;
-               case 'X':
-                       csi_X(vc, vc->vc_par[0]);
-                       return;
-               case '@':
-                       csi_at(vc, vc->vc_par[0]);
-                       return;
-               case ']': /* setterm functions */
-                       setterm_command(vc);
-                       return;
-               }
-               return;
-       case ESpercent:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '@':  /* defined in ISO 2022 */
-                       vc->vc_utf = 0;
-                       return;
-               case 'G':  /* prelim official escape code */
-               case '8':  /* retained for compatibility */
-                       vc->vc_utf = 1;
-                       return;
-               }
-               return;
-       case ESfunckey:
-               vc->vc_state = ESnormal;
-               return;
-       case EShash:
-               vc->vc_state = ESnormal;
-               if (c == '8') {
-                       /* DEC screen alignment test. kludge :-) */
-                       vc->vc_video_erase_char =
-                               (vc->vc_video_erase_char & 0xff00) | 'E';
-                       csi_J(vc, 2);
-                       vc->vc_video_erase_char =
-                               (vc->vc_video_erase_char & 0xff00) | ' ';
-                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-               }
-               return;
-       case ESsetG0:
-               if (c == '0')
-                       vc->vc_G0_charset = GRAF_MAP;
-               else if (c == 'B')
-                       vc->vc_G0_charset = LAT1_MAP;
-               else if (c == 'U')
-                       vc->vc_G0_charset = IBMPC_MAP;
-               else if (c == 'K')
-                       vc->vc_G0_charset = USER_MAP;
-               if (vc->vc_charset == 0)
-                       vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-               vc->vc_state = ESnormal;
-               return;
-       case ESsetG1:
-               if (c == '0')
-                       vc->vc_G1_charset = GRAF_MAP;
-               else if (c == 'B')
-                       vc->vc_G1_charset = LAT1_MAP;
-               else if (c == 'U')
-                       vc->vc_G1_charset = IBMPC_MAP;
-               else if (c == 'K')
-                       vc->vc_G1_charset = USER_MAP;
-               if (vc->vc_charset == 1)
-                       vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-               vc->vc_state = ESnormal;
-               return;
-       default:
-               vc->vc_state = ESnormal;
-       }
-}
-
-/* This is a temporary buffer used to prepare a tty console write
- * so that we can easily avoid touching user space while holding the
- * console spinlock.  It is allocated in con_init and is shared by
- * this code and the vc_screen read/write tty calls.
- *
- * We have to allocate this statically in the kernel data section
- * since console_init (and thus con_init) are called before any
- * kernel memory allocation is available.
- */
-char con_buf[CON_BUF_SIZE];
-DEFINE_MUTEX(con_buf_mtx);
-
-/* is_double_width() is based on the wcwidth() implementation by
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
- */
-struct interval {
-       uint32_t first;
-       uint32_t last;
-};
-
-static int bisearch(uint32_t ucs, const struct interval *table, int max)
-{
-       int min = 0;
-       int mid;
-
-       if (ucs < table[0].first || ucs > table[max].last)
-               return 0;
-       while (max >= min) {
-               mid = (min + max) / 2;
-               if (ucs > table[mid].last)
-                       min = mid + 1;
-               else if (ucs < table[mid].first)
-                       max = mid - 1;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-static int is_double_width(uint32_t ucs)
-{
-       static const struct interval double_width[] = {
-               { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
-               { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
-               { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
-               { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
-       };
-       return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
-}
-
-/* acquires console_sem */
-static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-#ifdef VT_BUF_VRAM_ONLY
-#define FLUSH do { } while(0);
-#else
-#define FLUSH if (draw_x >= 0) { \
-       vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
-       draw_x = -1; \
-       }
-#endif
-
-       int c, tc, ok, n = 0, draw_x = -1;
-       unsigned int currcons;
-       unsigned long draw_from = 0, draw_to = 0;
-       struct vc_data *vc;
-       unsigned char vc_attr;
-       struct vt_notifier_param param;
-       uint8_t rescan;
-       uint8_t inverse;
-       uint8_t width;
-       u16 himask, charmask;
-
-       if (in_interrupt())
-               return count;
-
-       might_sleep();
-
-       acquire_console_sem();
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
-               release_console_sem();
-               return 0;
-       }
-
-       currcons = vc->vc_num;
-       if (!vc_cons_allocated(currcons)) {
-           /* could this happen? */
-               printk_once("con_write: tty %d not allocated\n", currcons+1);
-           release_console_sem();
-           return 0;
-       }
-
-       himask = vc->vc_hi_font_mask;
-       charmask = himask ? 0x1ff : 0xff;
-
-       /* undraw cursor first */
-       if (IS_FG(vc))
-               hide_cursor(vc);
-
-       param.vc = vc;
-
-       while (!tty->stopped && count) {
-               int orig = *buf;
-               c = orig;
-               buf++;
-               n++;
-               count--;
-               rescan = 0;
-               inverse = 0;
-               width = 1;
-
-               /* Do no translation at all in control states */
-               if (vc->vc_state != ESnormal) {
-                       tc = c;
-               } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
-                   /* Combine UTF-8 into Unicode in vc_utf_char.
-                    * vc_utf_count is the number of continuation bytes still
-                    * expected to arrive.
-                    * vc_npar is the number of continuation bytes arrived so
-                    * far
-                    */
-rescan_last_byte:
-                   if ((c & 0xc0) == 0x80) {
-                       /* Continuation byte received */
-                       static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
-                       if (vc->vc_utf_count) {
-                           vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
-                           vc->vc_npar++;
-                           if (--vc->vc_utf_count) {
-                               /* Still need some bytes */
-                               continue;
-                           }
-                           /* Got a whole character */
-                           c = vc->vc_utf_char;
-                           /* Reject overlong sequences */
-                           if (c <= utf8_length_changes[vc->vc_npar - 1] ||
-                                       c > utf8_length_changes[vc->vc_npar])
-                               c = 0xfffd;
-                       } else {
-                           /* Unexpected continuation byte */
-                           vc->vc_utf_count = 0;
-                           c = 0xfffd;
-                       }
-                   } else {
-                       /* Single ASCII byte or first byte of a sequence received */
-                       if (vc->vc_utf_count) {
-                           /* Continuation byte expected */
-                           rescan = 1;
-                           vc->vc_utf_count = 0;
-                           c = 0xfffd;
-                       } else if (c > 0x7f) {
-                           /* First byte of a multibyte sequence received */
-                           vc->vc_npar = 0;
-                           if ((c & 0xe0) == 0xc0) {
-                               vc->vc_utf_count = 1;
-                               vc->vc_utf_char = (c & 0x1f);
-                           } else if ((c & 0xf0) == 0xe0) {
-                               vc->vc_utf_count = 2;
-                               vc->vc_utf_char = (c & 0x0f);
-                           } else if ((c & 0xf8) == 0xf0) {
-                               vc->vc_utf_count = 3;
-                               vc->vc_utf_char = (c & 0x07);
-                           } else if ((c & 0xfc) == 0xf8) {
-                               vc->vc_utf_count = 4;
-                               vc->vc_utf_char = (c & 0x03);
-                           } else if ((c & 0xfe) == 0xfc) {
-                               vc->vc_utf_count = 5;
-                               vc->vc_utf_char = (c & 0x01);
-                           } else {
-                               /* 254 and 255 are invalid */
-                               c = 0xfffd;
-                           }
-                           if (vc->vc_utf_count) {
-                               /* Still need some bytes */
-                               continue;
-                           }
-                       }
-                       /* Nothing to do if an ASCII byte was received */
-                   }
-                   /* End of UTF-8 decoding. */
-                   /* c is the received character, or U+FFFD for invalid sequences. */
-                   /* Replace invalid Unicode code points with U+FFFD too */
-                   if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
-                       c = 0xfffd;
-                   tc = c;
-               } else {        /* no utf or alternate charset mode */
-                   tc = vc_translate(vc, c);
-               }
-
-               param.c = tc;
-               if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
-                                       &param) == NOTIFY_STOP)
-                       continue;
-
-                /* If the original code was a control character we
-                 * only allow a glyph to be displayed if the code is
-                 * not normally used (such as for cursor movement) or
-                 * if the disp_ctrl mode has been explicitly enabled.
-                 * Certain characters (as given by the CTRL_ALWAYS
-                 * bitmap) are always displayed as control characters,
-                 * as the console would be pretty useless without
-                 * them; to display an arbitrary font position use the
-                 * direct-to-font zone in UTF-8 mode.
-                 */
-                ok = tc && (c >= 32 ||
-                           !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
-                                 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
-                       && (c != 127 || vc->vc_disp_ctrl)
-                       && (c != 128+27);
-
-               if (vc->vc_state == ESnormal && ok) {
-                       if (vc->vc_utf && !vc->vc_disp_ctrl) {
-                               if (is_double_width(c))
-                                       width = 2;
-                       }
-                       /* Now try to find out how to display it */
-                       tc = conv_uni_to_pc(vc, tc);
-                       if (tc & ~charmask) {
-                               if (tc == -1 || tc == -2) {
-                                   continue; /* nothing to display */
-                               }
-                               /* Glyph not found */
-                               if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
-                                   /* In legacy mode use the glyph we get by a 1:1 mapping.
-                                      This would make absolutely no sense with Unicode in mind,
-                                      but do this for ASCII characters since a font may lack
-                                      Unicode mapping info and we don't want to end up with
-                                      having question marks only. */
-                                   tc = c;
-                               } else {
-                                   /* Display U+FFFD. If it's not found, display an inverse question mark. */
-                                   tc = conv_uni_to_pc(vc, 0xfffd);
-                                   if (tc < 0) {
-                                       inverse = 1;
-                                       tc = conv_uni_to_pc(vc, '?');
-                                       if (tc < 0) tc = '?';
-                                   }
-                               }
-                       }
-
-                       if (!inverse) {
-                               vc_attr = vc->vc_attr;
-                       } else {
-                               /* invert vc_attr */
-                               if (!vc->vc_can_do_color) {
-                                       vc_attr = (vc->vc_attr) ^ 0x08;
-                               } else if (vc->vc_hi_font_mask == 0x100) {
-                                       vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
-                               } else {
-                                       vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
-                               }
-                               FLUSH
-                       }
-
-                       while (1) {
-                               if (vc->vc_need_wrap || vc->vc_decim)
-                                       FLUSH
-                               if (vc->vc_need_wrap) {
-                                       cr(vc);
-                                       lf(vc);
-                               }
-                               if (vc->vc_decim)
-                                       insert_char(vc, 1);
-                               scr_writew(himask ?
-                                            ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
-                                            (vc_attr << 8) + tc,
-                                          (u16 *) vc->vc_pos);
-                               if (DO_UPDATE(vc) && draw_x < 0) {
-                                       draw_x = vc->vc_x;
-                                       draw_from = vc->vc_pos;
-                               }
-                               if (vc->vc_x == vc->vc_cols - 1) {
-                                       vc->vc_need_wrap = vc->vc_decawm;
-                                       draw_to = vc->vc_pos + 2;
-                               } else {
-                                       vc->vc_x++;
-                                       draw_to = (vc->vc_pos += 2);
-                               }
-
-                               if (!--width) break;
-
-                               tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
-                               if (tc < 0) tc = ' ';
-                       }
-                       notify_write(vc, c);
-
-                       if (inverse) {
-                               FLUSH
-                       }
-
-                       if (rescan) {
-                               rescan = 0;
-                               inverse = 0;
-                               width = 1;
-                               c = orig;
-                               goto rescan_last_byte;
-                       }
-                       continue;
-               }
-               FLUSH
-               do_con_trol(tty, vc, orig);
-       }
-       FLUSH
-       console_conditional_schedule();
-       release_console_sem();
-       notify_update(vc);
-       return n;
-#undef FLUSH
-}
-
-/*
- * This is the console switching callback.
- *
- * Doing console switching in a process context allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt).  Synchronization
- * with other console code and prevention of re-entrancy is
- * ensured with console_sem.
- */
-static void console_callback(struct work_struct *ignored)
-{
-       acquire_console_sem();
-
-       if (want_console >= 0) {
-               if (want_console != fg_console &&
-                   vc_cons_allocated(want_console)) {
-                       hide_cursor(vc_cons[fg_console].d);
-                       change_console(vc_cons[want_console].d);
-                       /* we only changed when the console had already
-                          been allocated - a new console is not created
-                          in an interrupt routine */
-               }
-               want_console = -1;
-       }
-       if (do_poke_blanked_console) { /* do not unblank for a LED change */
-               do_poke_blanked_console = 0;
-               poke_blanked_console();
-       }
-       if (scrollback_delta) {
-               struct vc_data *vc = vc_cons[fg_console].d;
-               clear_selection();
-               if (vc->vc_mode == KD_TEXT)
-                       vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
-               scrollback_delta = 0;
-       }
-       if (blank_timer_expired) {
-               do_blank_screen(0);
-               blank_timer_expired = 0;
-       }
-       notify_update(vc_cons[fg_console].d);
-
-       release_console_sem();
-}
-
-int set_console(int nr)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-
-       if (!vc_cons_allocated(nr) || vt_dont_switch ||
-               (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
-
-               /*
-                * Console switch will fail in console_callback() or
-                * change_console() so there is no point scheduling
-                * the callback
-                *
-                * Existing set_console() users don't check the return
-                * value so this shouldn't break anything
-                */
-               return -EINVAL;
-       }
-
-       want_console = nr;
-       schedule_console_callback();
-
-       return 0;
-}
-
-struct tty_driver *console_driver;
-
-#ifdef CONFIG_VT_CONSOLE
-
-/**
- * vt_kmsg_redirect() - Sets/gets the kernel message console
- * @new:       The new virtual terminal number or -1 if the console should stay
- *             unchanged
- *
- * By default, the kernel messages are always printed on the current virtual
- * console. However, the user may modify that default with the
- * TIOCL_SETKMSGREDIRECT ioctl call.
- *
- * This function sets the kernel message console to be @new. It returns the old
- * virtual console number. The virtual terminal number 0 (both as parameter and
- * return value) means no redirection (i.e. always printed on the currently
- * active console).
- *
- * The parameter -1 means that only the current console is returned, but the
- * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
- * case to make the code more understandable.
- *
- * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
- * the parameter and always returns 0.
- */
-int vt_kmsg_redirect(int new)
-{
-       static int kmsg_con;
-
-       if (new != -1)
-               return xchg(&kmsg_con, new);
-       else
-               return kmsg_con;
-}
-
-/*
- *     Console on virtual terminal
- *
- * The console must be locked when we get here.
- */
-
-static void vt_console_print(struct console *co, const char *b, unsigned count)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       unsigned char c;
-       static DEFINE_SPINLOCK(printing_lock);
-       const ushort *start;
-       ushort cnt = 0;
-       ushort myx;
-       int kmsg_console;
-
-       /* console busy or not yet initialized */
-       if (!printable)
-               return;
-       if (!spin_trylock(&printing_lock))
-               return;
-
-       kmsg_console = vt_get_kmsg_redirect();
-       if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
-               vc = vc_cons[kmsg_console - 1].d;
-
-       /* read `x' only after setting currcons properly (otherwise
-          the `x' macro will read the x of the foreground console). */
-       myx = vc->vc_x;
-
-       if (!vc_cons_allocated(fg_console)) {
-               /* impossible */
-               /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
-               goto quit;
-       }
-
-       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-               goto quit;
-
-       /* undraw cursor first */
-       if (IS_FG(vc))
-               hide_cursor(vc);
-
-       start = (ushort *)vc->vc_pos;
-
-       /* Contrived structure to try to emulate original need_wrap behaviour
-        * Problems caused when we have need_wrap set on '\n' character */
-       while (count--) {
-               c = *b++;
-               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
-                       if (cnt > 0) {
-                               if (CON_IS_VISIBLE(vc))
-                                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-                               vc->vc_x += cnt;
-                               if (vc->vc_need_wrap)
-                                       vc->vc_x--;
-                               cnt = 0;
-                       }
-                       if (c == 8) {           /* backspace */
-                               bs(vc);
-                               start = (ushort *)vc->vc_pos;
-                               myx = vc->vc_x;
-                               continue;
-                       }
-                       if (c != 13)
-                               lf(vc);
-                       cr(vc);
-                       start = (ushort *)vc->vc_pos;
-                       myx = vc->vc_x;
-                       if (c == 10 || c == 13)
-                               continue;
-               }
-               scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
-               notify_write(vc, c);
-               cnt++;
-               if (myx == vc->vc_cols - 1) {
-                       vc->vc_need_wrap = 1;
-                       continue;
-               }
-               vc->vc_pos += 2;
-               myx++;
-       }
-       if (cnt > 0) {
-               if (CON_IS_VISIBLE(vc))
-                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-               vc->vc_x += cnt;
-               if (vc->vc_x == vc->vc_cols) {
-                       vc->vc_x--;
-                       vc->vc_need_wrap = 1;
-               }
-       }
-       set_cursor(vc);
-       notify_update(vc);
-
-quit:
-       spin_unlock(&printing_lock);
-}
-
-static struct tty_driver *vt_console_device(struct console *c, int *index)
-{
-       *index = c->index ? c->index-1 : fg_console;
-       return console_driver;
-}
-
-static struct console vt_console_driver = {
-       .name           = "tty",
-       .write          = vt_console_print,
-       .device         = vt_console_device,
-       .unblank        = unblank_screen,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-#endif
-
-/*
- *     Handling of Linux-specific VC ioctls
- */
-
-/*
- * Generally a bit racy with respect to console_sem().
- *
- * There are some functions which don't need it.
- *
- * There are some functions which can sleep for arbitrary periods
- * (paste_selection) but we don't need the lock there anyway.
- *
- * set_selection has locking, and definitely needs it
- */
-
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
-       char type, data;
-       char __user *p = (char __user *)arg;
-       int lines;
-       int ret;
-
-       if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (get_user(type, p))
-               return -EFAULT;
-       ret = 0;
-
-       switch (type)
-       {
-               case TIOCL_SETSEL:
-                       acquire_console_sem();
-                       ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-                       release_console_sem();
-                       break;
-               case TIOCL_PASTESEL:
-                       ret = paste_selection(tty);
-                       break;
-               case TIOCL_UNBLANKSCREEN:
-                       acquire_console_sem();
-                       unblank_screen();
-                       release_console_sem();
-                       break;
-               case TIOCL_SELLOADLUT:
-                       ret = sel_loadlut(p);
-                       break;
-               case TIOCL_GETSHIFTSTATE:
-
-       /*
-        * Make it possible to react to Shift+Mousebutton.
-        * Note that 'shift_state' is an undocumented
-        * kernel-internal variable; programs not closely
-        * related to the kernel should not use this.
-        */
-                       data = shift_state;
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_GETMOUSEREPORTING:
-                       data = mouse_reporting();
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_SETVESABLANK:
-                       ret = set_vesa_blanking(p);
-                       break;
-               case TIOCL_GETKMSGREDIRECT:
-                       data = vt_get_kmsg_redirect();
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_SETKMSGREDIRECT:
-                       if (!capable(CAP_SYS_ADMIN)) {
-                               ret = -EPERM;
-                       } else {
-                               if (get_user(data, p+1))
-                                       ret = -EFAULT;
-                               else
-                                       vt_kmsg_redirect(data);
-                       }
-                       break;
-               case TIOCL_GETFGCONSOLE:
-                       ret = fg_console;
-                       break;
-               case TIOCL_SCROLLCONSOLE:
-                       if (get_user(lines, (s32 __user *)(p+4))) {
-                               ret = -EFAULT;
-                       } else {
-                               scrollfront(vc_cons[fg_console].d, lines);
-                               ret = 0;
-                       }
-                       break;
-               case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
-                       acquire_console_sem();
-                       ignore_poke = 1;
-                       do_blank_screen(0);
-                       release_console_sem();
-                       break;
-               case TIOCL_BLANKEDSCREEN:
-                       ret = console_blanked;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-       }
-       return ret;
-}
-
-/*
- * /dev/ttyN handling
- */
-
-static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-       int     retval;
-
-       retval = do_con_write(tty, buf, count);
-       con_flush_chars(tty);
-
-       return retval;
-}
-
-static int con_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       if (in_interrupt())
-               return 0;       /* n_r3964 calls put_char() from interrupt context */
-       return do_con_write(tty, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
-       if (tty->stopped)
-               return 0;
-       return 32768;           /* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;               /* we're not buffering */
-}
-
-/*
- * con_throttle and con_unthrottle are only used for
- * paste_selection(), which has to stuff in a large number of
- * characters...
- */
-static void con_throttle(struct tty_struct *tty)
-{
-}
-
-static void con_unthrottle(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-
-       wake_up_interruptible(&vc->paste_wait);
-}
-
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
-{
-       int console_num;
-       if (!tty)
-               return;
-       console_num = tty->index;
-       if (!vc_cons_allocated(console_num))
-               return;
-       set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-       set_leds();
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
-       int console_num;
-       if (!tty)
-               return;
-       console_num = tty->index;
-       if (!vc_cons_allocated(console_num))
-               return;
-       clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-       set_leds();
-}
-
-static void con_flush_chars(struct tty_struct *tty)
-{
-       struct vc_data *vc;
-
-       if (in_interrupt())     /* from flush_to_ldisc */
-               return;
-
-       /* if we race with con_close(), vt may be null */
-       acquire_console_sem();
-       vc = tty->driver_data;
-       if (vc)
-               set_cursor(vc);
-       release_console_sem();
-}
-
-/*
- * Allocate the console screen memory.
- */
-static int con_open(struct tty_struct *tty, struct file *filp)
-{
-       unsigned int currcons = tty->index;
-       int ret = 0;
-
-       acquire_console_sem();
-       if (tty->driver_data == NULL) {
-               ret = vc_allocate(currcons);
-               if (ret == 0) {
-                       struct vc_data *vc = vc_cons[currcons].d;
-
-                       /* Still being freed */
-                       if (vc->port.tty) {
-                               release_console_sem();
-                               return -ERESTARTSYS;
-                       }
-                       tty->driver_data = vc;
-                       vc->port.tty = tty;
-
-                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
-                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
-                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
-                       }
-                       if (vc->vc_utf)
-                               tty->termios->c_iflag |= IUTF8;
-                       else
-                               tty->termios->c_iflag &= ~IUTF8;
-                       release_console_sem();
-                       return ret;
-               }
-       }
-       release_console_sem();
-       return ret;
-}
-
-static void con_close(struct tty_struct *tty, struct file *filp)
-{
-       /* Nothing to do - we defer to shutdown */
-}
-
-static void con_shutdown(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-       BUG_ON(vc == NULL);
-       acquire_console_sem();
-       vc->port.tty = NULL;
-       release_console_sem();
-       tty_shutdown(tty);
-}
-
-static int default_italic_color    = 2; // green (ASCII)
-static int default_underline_color = 3; // cyan (ASCII)
-module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
-module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
-
-static void vc_init(struct vc_data *vc, unsigned int rows,
-                   unsigned int cols, int do_clear)
-{
-       int j, k ;
-
-       vc->vc_cols = cols;
-       vc->vc_rows = rows;
-       vc->vc_size_row = cols << 1;
-       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-
-       set_origin(vc);
-       vc->vc_pos = vc->vc_origin;
-       reset_vc(vc);
-       for (j=k=0; j<16; j++) {
-               vc->vc_palette[k++] = default_red[j] ;
-               vc->vc_palette[k++] = default_grn[j] ;
-               vc->vc_palette[k++] = default_blu[j] ;
-       }
-       vc->vc_def_color       = 0x07;   /* white */
-       vc->vc_ulcolor         = default_underline_color;
-       vc->vc_itcolor         = default_italic_color;
-       vc->vc_halfcolor       = 0x08;   /* grey */
-       init_waitqueue_head(&vc->paste_wait);
-       reset_terminal(vc, do_clear);
-}
-
-/*
- * This routine initializes console interrupts, and does nothing
- * else. If you want the screen to clear, call tty_write with
- * the appropriate escape-sequence.
- */
-
-static int __init con_init(void)
-{
-       const char *display_desc = NULL;
-       struct vc_data *vc;
-       unsigned int currcons = 0, i;
-
-       acquire_console_sem();
-
-       if (conswitchp)
-               display_desc = conswitchp->con_startup();
-       if (!display_desc) {
-               fg_console = 0;
-               release_console_sem();
-               return 0;
-       }
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = conswitchp;
-                       con_driver->desc = display_desc;
-                       con_driver->flag = CON_DRIVER_FLAG_INIT;
-                       con_driver->first = 0;
-                       con_driver->last = MAX_NR_CONSOLES - 1;
-                       break;
-               }
-       }
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               con_driver_map[i] = conswitchp;
-
-       if (blankinterval) {
-               blank_state = blank_normal_wait;
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-       }
-
-       for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
-               vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
-               INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-               tty_port_init(&vc->port);
-               visual_init(vc, currcons, 1);
-               vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
-               vc_init(vc, vc->vc_rows, vc->vc_cols,
-                       currcons || !vc->vc_sw->con_save_screen);
-       }
-       currcons = fg_console = 0;
-       master_display_fg = vc = vc_cons[currcons].d;
-       set_origin(vc);
-       save_screen(vc);
-       gotoxy(vc, vc->vc_x, vc->vc_y);
-       csi_J(vc, 0);
-       update_screen(vc);
-       printk("Console: %s %s %dx%d",
-               vc->vc_can_do_color ? "colour" : "mono",
-               display_desc, vc->vc_cols, vc->vc_rows);
-       printable = 1;
-       printk("\n");
-
-       release_console_sem();
-
-#ifdef CONFIG_VT_CONSOLE
-       register_console(&vt_console_driver);
-#endif
-       return 0;
-}
-console_initcall(con_init);
-
-static const struct tty_operations con_ops = {
-       .open = con_open,
-       .close = con_close,
-       .write = con_write,
-       .write_room = con_write_room,
-       .put_char = con_put_char,
-       .flush_chars = con_flush_chars,
-       .chars_in_buffer = con_chars_in_buffer,
-       .ioctl = vt_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = vt_compat_ioctl,
-#endif
-       .stop = con_stop,
-       .start = con_start,
-       .throttle = con_throttle,
-       .unthrottle = con_unthrottle,
-       .resize = vt_resize,
-       .shutdown = con_shutdown
-};
-
-static struct cdev vc0_cdev;
-
-int __init vty_init(const struct file_operations *console_fops)
-{
-       cdev_init(&vc0_cdev, console_fops);
-       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
-               panic("Couldn't register /dev/tty0 driver\n");
-       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-       vcs_init();
-
-       console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
-       if (!console_driver)
-               panic("Couldn't allocate console driver\n");
-       console_driver->owner = THIS_MODULE;
-       console_driver->name = "tty";
-       console_driver->name_base = 1;
-       console_driver->major = TTY_MAJOR;
-       console_driver->minor_start = 1;
-       console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
-       console_driver->init_termios = tty_std_termios;
-       if (default_utf8)
-               console_driver->init_termios.c_iflag |= IUTF8;
-       console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-       tty_set_operations(console_driver, &con_ops);
-       if (tty_register_driver(console_driver))
-               panic("Couldn't register console driver\n");
-       kbd_init();
-       console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
-       mda_console_init();
-#endif
-       return 0;
-}
-
-#ifndef VT_SINGLE_DRIVER
-
-static struct class *vtconsole_class;
-
-static int bind_con_driver(const struct consw *csw, int first, int last,
-                          int deflt)
-{
-       struct module *owner = csw->owner;
-       const char *desc = NULL;
-       struct con_driver *con_driver;
-       int i, j = -1, k = -1, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw) {
-                       desc = con_driver->desc;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
-               csw->con_startup();
-               con_driver->flag |= CON_DRIVER_FLAG_INIT;
-       }
-
-       if (deflt) {
-               if (conswitchp)
-                       module_put(conswitchp->owner);
-
-               __module_get(owner);
-               conswitchp = csw;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               int old_was_color;
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (con_driver_map[i])
-                       module_put(con_driver_map[i]->owner);
-               __module_get(owner);
-               con_driver_map[i] = csw;
-
-               if (!vc || !vc->vc_sw)
-                       continue;
-
-               j = i;
-
-               if (CON_IS_VISIBLE(vc)) {
-                       k = i;
-                       save_screen(vc);
-               }
-
-               old_was_color = vc->vc_can_do_color;
-               vc->vc_sw->con_deinit(vc);
-               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-               visual_init(vc, i, 0);
-               set_origin(vc);
-               update_attr(vc);
-
-               /* If the console changed between mono <-> color, then
-                * the attributes in the screenbuf will be wrong.  The
-                * following resets all attributes to something sane.
-                */
-               if (old_was_color != vc->vc_can_do_color)
-                       clear_buffer_attributes(vc);
-       }
-
-       printk("Console: switching ");
-       if (!deflt)
-               printk("consoles %d-%d ", first+1, last+1);
-       if (j >= 0) {
-               struct vc_data *vc = vc_cons[j].d;
-
-               printk("to %s %s %dx%d\n",
-                      vc->vc_can_do_color ? "colour" : "mono",
-                      desc, vc->vc_cols, vc->vc_rows);
-
-               if (k >= 0) {
-                       vc = vc_cons[k].d;
-                       update_screen(vc);
-               }
-       } else
-               printk("to %s\n", desc);
-
-       retval = 0;
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-};
-
-#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
-       int i, retval = 0;
-
-       for (i = first; i <= last; i++) {
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (vc && vc->vc_mode == KD_GRAPHICS) {
-                       retval = 1;
-                       break;
-               }
-       }
-
-       return retval;
-}
-
-/**
- * unbind_con_driver - unbind a console driver
- * @csw: pointer to console driver to unregister
- * @first: first in range of consoles that @csw should be unbound from
- * @last: last in range of consoles that @csw should be unbound from
- * @deflt: should next bound console driver be default after @csw is unbound?
- *
- * To unbind a driver from all possible consoles, pass 0 as @first and
- * %MAX_NR_CONSOLES as @last.
- *
- * @deflt controls whether the console that ends up replacing @csw should be
- * the default console.
- *
- * RETURNS:
- * -ENODEV if @csw isn't a registered console driver or can't be unregistered
- * or 0 on success.
- */
-int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
-{
-       struct module *owner = csw->owner;
-       const struct consw *defcsw = NULL;
-       struct con_driver *con_driver = NULL, *con_back = NULL;
-       int i, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered and if it is unbindable */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       retval = -ENODEV;
-
-       /* check if backup driver exists */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_back = &registered_con_driver[i];
-
-               if (con_back->con &&
-                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con_back->con;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       if (!con_is_bound(csw)) {
-               release_console_sem();
-               goto err;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               if (con_driver_map[i] == csw) {
-                       module_put(csw->owner);
-                       con_driver_map[i] = NULL;
-               }
-       }
-
-       if (!con_is_bound(defcsw)) {
-               const struct consw *defconsw = conswitchp;
-
-               defcsw->con_startup();
-               con_back->flag |= CON_DRIVER_FLAG_INIT;
-               /*
-                * vgacon may change the default driver to point
-                * to dummycon, we restore it here...
-                */
-               conswitchp = defconsw;
-       }
-
-       if (!con_is_bound(csw))
-               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
-
-       release_console_sem();
-       /* ignore return value, binding should not fail */
-       bind_con_driver(defcsw, first, last, deflt);
-err:
-       module_put(owner);
-       return retval;
-
-}
-EXPORT_SYMBOL(unbind_con_driver);
-
-static int vt_bind(struct con_driver *con)
-{
-       const struct consw *defcsw = NULL, *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con->con;
-                       break;
-               }
-       }
-
-       if (!defcsw)
-               goto err;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == defcsw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       bind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-
-static int vt_unbind(struct con_driver *con)
-{
-       const struct consw *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == csw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       unbind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-#else
-static inline int vt_bind(struct con_driver *con)
-{
-       return 0;
-}
-static inline int vt_unbind(struct con_driver *con)
-{
-       return 0;
-}
-#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
-
-static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t count)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-       int bind = simple_strtoul(buf, NULL, 0);
-
-       if (bind)
-               vt_bind(con);
-       else
-               vt_unbind(con);
-
-       return count;
-}
-
-static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-       int bind = con_is_bound(con->con);
-
-       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
-}
-
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%s %s\n",
-                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
-                        con->desc);
-
-}
-
-static struct device_attribute device_attrs[] = {
-       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
-       __ATTR(name, S_IRUGO, show_name, NULL),
-};
-
-static int vtconsole_init_device(struct con_driver *con)
-{
-       int i;
-       int error = 0;
-
-       con->flag |= CON_DRIVER_FLAG_ATTR;
-       dev_set_drvdata(con->dev, con);
-       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-               error = device_create_file(con->dev, &device_attrs[i]);
-               if (error)
-                       break;
-       }
-
-       if (error) {
-               while (--i >= 0)
-                       device_remove_file(con->dev, &device_attrs[i]);
-               con->flag &= ~CON_DRIVER_FLAG_ATTR;
-       }
-
-       return error;
-}
-
-static void vtconsole_deinit_device(struct con_driver *con)
-{
-       int i;
-
-       if (con->flag & CON_DRIVER_FLAG_ATTR) {
-               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-                       device_remove_file(con->dev, &device_attrs[i]);
-               con->flag &= ~CON_DRIVER_FLAG_ATTR;
-       }
-}
-
-/**
- * con_is_bound - checks if driver is bound to the console
- * @csw: console driver
- *
- * RETURNS: zero if unbound, nonzero if bound
- *
- * Drivers can call this and if zero, they should release
- * all resources allocated on con_startup()
- */
-int con_is_bound(const struct consw *csw)
-{
-       int i, bound = 0;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (con_driver_map[i] == csw) {
-                       bound = 1;
-                       break;
-               }
-       }
-
-       return bound;
-}
-EXPORT_SYMBOL(con_is_bound);
-
-/**
- * con_debug_enter - prepare the console for the kernel debugger
- * @sw: console driver
- *
- * Called when the console is taken over by the kernel debugger, this
- * function needs to save the current console state, then put the console
- * into a state suitable for the kernel debugger.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to prepare
- * the console for the debugger.
- */
-int con_debug_enter(struct vc_data *vc)
-{
-       int ret = 0;
-
-       saved_fg_console = fg_console;
-       saved_last_console = last_console;
-       saved_want_console = want_console;
-       saved_vc_mode = vc->vc_mode;
-       saved_console_blanked = console_blanked;
-       vc->vc_mode = KD_TEXT;
-       console_blanked = 0;
-       if (vc->vc_sw->con_debug_enter)
-               ret = vc->vc_sw->con_debug_enter(vc);
-#ifdef CONFIG_KGDB_KDB
-       /* Set the initial LINES variable if it is not already set */
-       if (vc->vc_rows < 999) {
-               int linecount;
-               char lns[4];
-               const char *setargs[3] = {
-                       "set",
-                       "LINES",
-                       lns,
-               };
-               if (kdbgetintenv(setargs[0], &linecount)) {
-                       snprintf(lns, 4, "%i", vc->vc_rows);
-                       kdb_set(2, setargs);
-               }
-       }
-#endif /* CONFIG_KGDB_KDB */
-       return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_enter);
-
-/**
- * con_debug_leave - restore console state
- * @sw: console driver
- *
- * Restore the console state to what it was before the kernel debugger
- * was invoked.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to restore
- * the console.
- */
-int con_debug_leave(void)
-{
-       struct vc_data *vc;
-       int ret = 0;
-
-       fg_console = saved_fg_console;
-       last_console = saved_last_console;
-       want_console = saved_want_console;
-       console_blanked = saved_console_blanked;
-       vc_cons[fg_console].d->vc_mode = saved_vc_mode;
-
-       vc = vc_cons[fg_console].d;
-       if (vc->vc_sw->con_debug_leave)
-               ret = vc->vc_sw->con_debug_leave(vc);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_leave);
-
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
-{
-       struct module *owner = csw->owner;
-       struct con_driver *con_driver;
-       const char *desc;
-       int i, retval = 0;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               /* already registered */
-               if (con_driver->con == csw)
-                       retval = -EINVAL;
-       }
-
-       if (retval)
-               goto err;
-
-       desc = csw->con_startup();
-
-       if (!desc)
-               goto err;
-
-       retval = -EINVAL;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = csw;
-                       con_driver->desc = desc;
-                       con_driver->node = i;
-                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
-                                          CON_DRIVER_FLAG_INIT;
-                       con_driver->first = first;
-                       con_driver->last = last;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       con_driver->dev = device_create(vtconsole_class, NULL,
-                                               MKDEV(0, con_driver->node),
-                                               NULL, "vtcon%i",
-                                               con_driver->node);
-
-       if (IS_ERR(con_driver->dev)) {
-               printk(KERN_WARNING "Unable to create device for %s; "
-                      "errno = %ld\n", con_driver->desc,
-                      PTR_ERR(con_driver->dev));
-               con_driver->dev = NULL;
-       } else {
-               vtconsole_init_device(con_driver);
-       }
-
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-}
-EXPORT_SYMBOL(register_con_driver);
-
-/**
- * unregister_con_driver - unregister console driver from console layer
- * @csw: console driver
- *
- * DESCRIPTION: All drivers that registers to the console layer must
- * call this function upon exit, or if the console driver is in a state
- * where it won't be able to handle console services, such as the
- * framebuffer console without loaded framebuffer drivers.
- *
- * The driver must unbind first prior to unregistration.
- */
-int unregister_con_driver(const struct consw *csw)
-{
-       int i, retval = -ENODEV;
-
-       acquire_console_sem();
-
-       /* cannot unregister a bound driver */
-       if (con_is_bound(csw))
-               goto err;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       vtconsole_deinit_device(con_driver);
-                       device_destroy(vtconsole_class,
-                                      MKDEV(0, con_driver->node));
-                       con_driver->con = NULL;
-                       con_driver->desc = NULL;
-                       con_driver->dev = NULL;
-                       con_driver->node = 0;
-                       con_driver->flag = 0;
-                       con_driver->first = 0;
-                       con_driver->last = 0;
-                       retval = 0;
-                       break;
-               }
-       }
-err:
-       release_console_sem();
-       return retval;
-}
-EXPORT_SYMBOL(unregister_con_driver);
-
-/*
- *     If we support more console drivers, this function is used
- *     when a driver wants to take over some existing consoles
- *     and become default driver for newly opened ones.
- *
- *      take_over_console is basically a register followed by unbind
- */
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
-{
-       int err;
-
-       err = register_con_driver(csw, first, last);
-
-       if (!err)
-               bind_con_driver(csw, first, last, deflt);
-
-       return err;
-}
-
-/*
- * give_up_console is a wrapper to unregister_con_driver. It will only
- * work if driver is fully unbound.
- */
-void give_up_console(const struct consw *csw)
-{
-       unregister_con_driver(csw);
-}
-
-static int __init vtconsole_class_init(void)
-{
-       int i;
-
-       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
-       if (IS_ERR(vtconsole_class)) {
-               printk(KERN_WARNING "Unable to create vt console class; "
-                      "errno = %ld\n", PTR_ERR(vtconsole_class));
-               vtconsole_class = NULL;
-       }
-
-       /* Add system drivers to sysfs */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !con->dev) {
-                       con->dev = device_create(vtconsole_class, NULL,
-                                                        MKDEV(0, con->node),
-                                                        NULL, "vtcon%i",
-                                                        con->node);
-
-                       if (IS_ERR(con->dev)) {
-                               printk(KERN_WARNING "Unable to create "
-                                      "device for %s; errno = %ld\n",
-                                      con->desc, PTR_ERR(con->dev));
-                               con->dev = NULL;
-                       } else {
-                               vtconsole_init_device(con);
-                       }
-               }
-       }
-
-       return 0;
-}
-postcore_initcall(vtconsole_class_init);
-
-#endif
-
-/*
- *     Screen blanking
- */
-
-static int set_vesa_blanking(char __user *p)
-{
-       unsigned int mode;
-
-       if (get_user(mode, p + 1))
-               return -EFAULT;
-
-       vesa_blank_mode = (mode < 4) ? mode : 0;
-       return 0;
-}
-
-void do_blank_screen(int entering_gfx)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       int i;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (console_blanked) {
-               if (blank_state == blank_vesa_wait) {
-                       blank_state = blank_off;
-                       vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
-               }
-               return;
-       }
-
-       /* entering graphics mode? */
-       if (entering_gfx) {
-               hide_cursor(vc);
-               save_screen(vc);
-               vc->vc_sw->con_blank(vc, -1, 1);
-               console_blanked = fg_console + 1;
-               blank_state = blank_off;
-               set_origin(vc);
-               return;
-       }
-
-       if (blank_state != blank_normal_wait)
-               return;
-       blank_state = blank_off;
-
-       /* don't blank graphics */
-       if (vc->vc_mode != KD_TEXT) {
-               console_blanked = fg_console + 1;
-               return;
-       }
-
-       hide_cursor(vc);
-       del_timer_sync(&console_timer);
-       blank_timer_expired = 0;
-
-       save_screen(vc);
-       /* In case we need to reset origin, blanking hook returns 1 */
-       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
-       console_blanked = fg_console + 1;
-       if (i)
-               set_origin(vc);
-
-       if (console_blank_hook && console_blank_hook(1))
-               return;
-
-       if (vesa_off_interval && vesa_blank_mode) {
-               blank_state = blank_vesa_wait;
-               mod_timer(&console_timer, jiffies + vesa_off_interval);
-       }
-       vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
-}
-EXPORT_SYMBOL(do_blank_screen);
-
-/*
- * Called by timer as well as from vt_console_driver
- */
-void do_unblank_screen(int leaving_gfx)
-{
-       struct vc_data *vc;
-
-       /* This should now always be called from a "sane" (read: can schedule)
-        * context for the sake of the low level drivers, except in the special
-        * case of oops_in_progress
-        */
-       if (!oops_in_progress)
-               might_sleep();
-
-       WARN_CONSOLE_UNLOCKED();
-
-       ignore_poke = 0;
-       if (!console_blanked)
-               return;
-       if (!vc_cons_allocated(fg_console)) {
-               /* impossible */
-               printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
-               return;
-       }
-       vc = vc_cons[fg_console].d;
-       /* Try to unblank in oops case too */
-       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-               return; /* but leave console_blanked != 0 */
-
-       if (blankinterval) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               blank_state = blank_normal_wait;
-       }
-
-       console_blanked = 0;
-       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
-               /* Low-level driver cannot restore -> do it ourselves */
-               update_screen(vc);
-       if (console_blank_hook)
-               console_blank_hook(0);
-       set_palette(vc);
-       set_cursor(vc);
-       vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
-}
-EXPORT_SYMBOL(do_unblank_screen);
-
-/*
- * This is called by the outside world to cause a forced unblank, mostly for
- * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
- * call it with 1 as an argument and so force a mode restore... that may kill
- * X or at least garbage the screen but would also make the Oops visible...
- */
-void unblank_screen(void)
-{
-       do_unblank_screen(0);
-}
-
-/*
- * We defer the timer blanking to work queue so it can take the console mutex
- * (console operations can still happen at irq time, but only from printk which
- * has the console mutex. Not perfect yet, but better than no locking
- */
-static void blank_screen_t(unsigned long dummy)
-{
-       if (unlikely(!keventd_up())) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               return;
-       }
-       blank_timer_expired = 1;
-       schedule_work(&console_work);
-}
-
-void poke_blanked_console(void)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       /* Add this so we quickly catch whoever might call us in a non
-        * safe context. Nowadays, unblank_screen() isn't to be called in
-        * atomic contexts and is allowed to schedule (with the special case
-        * of oops_in_progress, but that isn't of any concern for this
-        * function. --BenH.
-        */
-       might_sleep();
-
-       /* This isn't perfectly race free, but a race here would be mostly harmless,
-        * at worse, we'll do a spurrious blank and it's unlikely
-        */
-       del_timer(&console_timer);
-       blank_timer_expired = 0;
-
-       if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
-               return;
-       if (console_blanked)
-               unblank_screen();
-       else if (blankinterval) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               blank_state = blank_normal_wait;
-       }
-}
-
-/*
- *     Palettes
- */
-
-static void set_palette(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc->vc_mode != KD_GRAPHICS)
-               vc->vc_sw->con_set_palette(vc, color_table);
-}
-
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
-    int i, j, k;
-
-    WARN_CONSOLE_UNLOCKED();
-
-    for (i = 0; i < 16; i++)
-       if (set) {
-           get_user(default_red[i], arg++);
-           get_user(default_grn[i], arg++);
-           get_user(default_blu[i], arg++);
-       } else {
-           put_user(default_red[i], arg++);
-           put_user(default_grn[i], arg++);
-           put_user(default_blu[i], arg++);
-       }
-    if (set) {
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-           if (vc_cons_allocated(i)) {
-               for (j = k = 0; j < 16; j++) {
-                   vc_cons[i].d->vc_palette[k++] = default_red[j];
-                   vc_cons[i].d->vc_palette[k++] = default_grn[j];
-                   vc_cons[i].d->vc_palette[k++] = default_blu[j];
-               }
-               set_palette(vc_cons[i].d);
-           }
-    }
-    return 0;
-}
-
-/*
- * Load palette into the DAC registers. arg points to a colour
- * map, 3 bytes per colour, 16 colours, range from 0 to 255.
- */
-
-int con_set_cmap(unsigned char __user *arg)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = set_get_cmap (arg,1);
-       release_console_sem();
-
-       return rc;
-}
-
-int con_get_cmap(unsigned char __user *arg)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = set_get_cmap (arg,0);
-       release_console_sem();
-
-       return rc;
-}
-
-void reset_palette(struct vc_data *vc)
-{
-       int j, k;
-       for (j=k=0; j<16; j++) {
-               vc->vc_palette[k++] = default_red[j];
-               vc->vc_palette[k++] = default_grn[j];
-               vc->vc_palette[k++] = default_blu[j];
-       }
-       set_palette(vc);
-}
-
-/*
- *  Font switching
- *
- *  Currently we only support fonts up to 32 pixels wide, at a maximum height
- *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
- *  depending on width) reserved for each character which is kinda wasty, but 
- *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
- *  is upto the actual low-level console-driver convert data into its favorite
- *  format (maybe we should add a `fontoffset' field to the `display'
- *  structure so we won't have to convert the fontdata all the time.
- *  /Jes
- */
-
-#define max_font_size 65536
-
-static int con_font_get(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font;
-       int rc = -EINVAL;
-       int c;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       if (op->data) {
-               font.data = kmalloc(max_font_size, GFP_KERNEL);
-               if (!font.data)
-                       return -ENOMEM;
-       } else
-               font.data = NULL;
-
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_get)
-               rc = vc->vc_sw->con_font_get(vc, &font);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-
-       if (rc)
-               goto out;
-
-       c = (font.width+7)/8 * 32 * font.charcount;
-
-       if (op->data && font.charcount > op->charcount)
-               rc = -ENOSPC;
-       if (!(op->flags & KD_FONT_FLAG_OLD)) {
-               if (font.width > op->width || font.height > op->height) 
-                       rc = -ENOSPC;
-       } else {
-               if (font.width != 8)
-                       rc = -EIO;
-               else if ((op->height && font.height > op->height) ||
-                        font.height > 32)
-                       rc = -ENOSPC;
-       }
-       if (rc)
-               goto out;
-
-       op->height = font.height;
-       op->width = font.width;
-       op->charcount = font.charcount;
-
-       if (op->data && copy_to_user(op->data, font.data, c))
-               rc = -EFAULT;
-
-out:
-       kfree(font.data);
-       return rc;
-}
-
-static int con_font_set(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font;
-       int rc = -EINVAL;
-       int size;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-       if (!op->data)
-               return -EINVAL;
-       if (op->charcount > 512)
-               return -EINVAL;
-       if (!op->height) {              /* Need to guess font height [compat] */
-               int h, i;
-               u8 __user *charmap = op->data;
-               u8 tmp;
-               
-               /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
-                  so that we can get rid of this soon */
-               if (!(op->flags & KD_FONT_FLAG_OLD))
-                       return -EINVAL;
-               for (h = 32; h > 0; h--)
-                       for (i = 0; i < op->charcount; i++) {
-                               if (get_user(tmp, &charmap[32*i+h-1]))
-                                       return -EFAULT;
-                               if (tmp)
-                                       goto nonzero;
-                       }
-               return -EINVAL;
-       nonzero:
-               op->height = h;
-       }
-       if (op->width <= 0 || op->width > 32 || op->height > 32)
-               return -EINVAL;
-       size = (op->width+7)/8 * 32 * op->charcount;
-       if (size > max_font_size)
-               return -ENOSPC;
-       font.charcount = op->charcount;
-       font.height = op->height;
-       font.width = op->width;
-       font.data = memdup_user(op->data, size);
-       if (IS_ERR(font.data))
-               return PTR_ERR(font.data);
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_set)
-               rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-       kfree(font.data);
-       return rc;
-}
-
-static int con_font_default(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font = {.width = op->width, .height = op->height};
-       char name[MAX_FONT_NAME];
-       char *s = name;
-       int rc;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       if (!op->data)
-               s = NULL;
-       else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
-               return -EFAULT;
-       else
-               name[MAX_FONT_NAME - 1] = 0;
-
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_default)
-               rc = vc->vc_sw->con_font_default(vc, &font, s);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-       if (!rc) {
-               op->width = font.width;
-               op->height = font.height;
-       }
-       return rc;
-}
-
-static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
-{
-       int con = op->height;
-       int rc;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       acquire_console_sem();
-       if (!vc->vc_sw->con_font_copy)
-               rc = -ENOSYS;
-       else if (con < 0 || !vc_cons_allocated(con))
-               rc = -ENOTTY;
-       else if (con == vc->vc_num)     /* nothing to do */
-               rc = 0;
-       else
-               rc = vc->vc_sw->con_font_copy(vc, con);
-       release_console_sem();
-       return rc;
-}
-
-int con_font_op(struct vc_data *vc, struct console_font_op *op)
-{
-       switch (op->op) {
-       case KD_FONT_OP_SET:
-               return con_font_set(vc, op);
-       case KD_FONT_OP_GET:
-               return con_font_get(vc, op);
-       case KD_FONT_OP_SET_DEFAULT:
-               return con_font_default(vc, op);
-       case KD_FONT_OP_COPY:
-               return con_font_copy(vc, op);
-       }
-       return -ENOSYS;
-}
-
-/*
- *     Interface exported to selection and vcs.
- */
-
-/* used by selection */
-u16 screen_glyph(struct vc_data *vc, int offset)
-{
-       u16 w = scr_readw(screenpos(vc, offset, 1));
-       u16 c = w & 0xff;
-
-       if (w & vc->vc_hi_font_mask)
-               c |= 0x100;
-       return c;
-}
-EXPORT_SYMBOL_GPL(screen_glyph);
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
-{
-       return screenpos(vc, 2 * w_offset, viewed);
-}
-
-void getconsxy(struct vc_data *vc, unsigned char *p)
-{
-       p[0] = vc->vc_x;
-       p[1] = vc->vc_y;
-}
-
-void putconsxy(struct vc_data *vc, unsigned char *p)
-{
-       hide_cursor(vc);
-       gotoxy(vc, p[0], p[1]);
-       set_cursor(vc);
-}
-
-u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
-{
-       if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
-               return softcursor_original;
-       return scr_readw(org);
-}
-
-void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
-{
-       scr_writew(val, org);
-       if ((unsigned long)org == vc->vc_pos) {
-               softcursor_original = -1;
-               add_softcursor(vc);
-       }
-}
-
-void vcs_scr_updated(struct vc_data *vc)
-{
-       notify_update(vc);
-}
-
-/*
- *     Visible symbols for modules
- */
-
-EXPORT_SYMBOL(color_table);
-EXPORT_SYMBOL(default_red);
-EXPORT_SYMBOL(default_grn);
-EXPORT_SYMBOL(default_blu);
-EXPORT_SYMBOL(update_region);
-EXPORT_SYMBOL(redraw_screen);
-EXPORT_SYMBOL(vc_resize);
-EXPORT_SYMBOL(fg_console);
-EXPORT_SYMBOL(console_blank_hook);
-EXPORT_SYMBOL(console_blanked);
-EXPORT_SYMBOL(vc_cons);
-EXPORT_SYMBOL(global_cursor_default);
-#ifndef VT_SINGLE_DRIVER
-EXPORT_SYMBOL(take_over_console);
-EXPORT_SYMBOL(give_up_console);
-#endif
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
deleted file mode 100644 (file)
index 6b68a0f..0000000
+++ /dev/null
@@ -1,1788 +0,0 @@
-/*
- *  linux/drivers/char/vt_ioctl.c
- *
- *  Copyright (C) 1992 obz under the linux copyright
- *
- *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
- *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
- *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
- *  Some code moved for less code duplication - Andi Kleen - Mar 1997
- *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/console.h>
-#include <linux/consolemap.h>
-#include <linux/signal.h>
-#include <linux/smp_lock.h>
-#include <linux/timex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/selection.h>
-
-char vt_dont_switch;
-extern struct tty_driver *console_driver;
-
-#define VT_IS_IN_USE(i)        (console_driver->ttys[i] && console_driver->ttys[i]->count)
-#define VT_BUSY(i)     (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
-
-/*
- * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
- * experimentation and study of X386 SYSV handling.
- *
- * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
- * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
- * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
- * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
- * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
- * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
- * to the current console is done by the main ioctl code.
- */
-
-#ifdef CONFIG_X86
-#include <linux/syscalls.h>
-#endif
-
-static void complete_change_console(struct vc_data *vc);
-
-/*
- *     User space VT_EVENT handlers
- */
-
-struct vt_event_wait {
-       struct list_head list;
-       struct vt_event event;
-       int done;
-};
-
-static LIST_HEAD(vt_events);
-static DEFINE_SPINLOCK(vt_event_lock);
-static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
-
-/**
- *     vt_event_post
- *     @event: the event that occurred
- *     @old: old console
- *     @new: new console
- *
- *     Post an VT event to interested VT handlers
- */
-
-void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
-{
-       struct list_head *pos, *head;
-       unsigned long flags;
-       int wake = 0;
-
-       spin_lock_irqsave(&vt_event_lock, flags);
-       head = &vt_events;
-
-       list_for_each(pos, head) {
-               struct vt_event_wait *ve = list_entry(pos,
-                                               struct vt_event_wait, list);
-               if (!(ve->event.event & event))
-                       continue;
-               ve->event.event = event;
-               /* kernel view is consoles 0..n-1, user space view is
-                  console 1..n with 0 meaning current, so we must bias */
-               ve->event.oldev = old + 1;
-               ve->event.newev = new + 1;
-               wake = 1;
-               ve->done = 1;
-       }
-       spin_unlock_irqrestore(&vt_event_lock, flags);
-       if (wake)
-               wake_up_interruptible(&vt_event_waitqueue);
-}
-
-/**
- *     vt_event_wait           -       wait for an event
- *     @vw: our event
- *
- *     Waits for an event to occur which completes our vt_event_wait
- *     structure. On return the structure has wv->done set to 1 for success
- *     or 0 if some event such as a signal ended the wait.
- */
-
-static void vt_event_wait(struct vt_event_wait *vw)
-{
-       unsigned long flags;
-       /* Prepare the event */
-       INIT_LIST_HEAD(&vw->list);
-       vw->done = 0;
-       /* Queue our event */
-       spin_lock_irqsave(&vt_event_lock, flags);
-       list_add(&vw->list, &vt_events);
-       spin_unlock_irqrestore(&vt_event_lock, flags);
-       /* Wait for it to pass */
-       wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
-       /* Dequeue it */
-       spin_lock_irqsave(&vt_event_lock, flags);
-       list_del(&vw->list);
-       spin_unlock_irqrestore(&vt_event_lock, flags);
-}
-
-/**
- *     vt_event_wait_ioctl     -       event ioctl handler
- *     @arg: argument to ioctl
- *
- *     Implement the VT_WAITEVENT ioctl using the VT event interface
- */
-
-static int vt_event_wait_ioctl(struct vt_event __user *event)
-{
-       struct vt_event_wait vw;
-
-       if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
-               return -EFAULT;
-       /* Highest supported event for now */
-       if (vw.event.event & ~VT_MAX_EVENT)
-               return -EINVAL;
-
-       vt_event_wait(&vw);
-       /* If it occurred report it */
-       if (vw.done) {
-               if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
-                       return -EFAULT;
-               return 0;
-       }
-       return -EINTR;
-}
-
-/**
- *     vt_waitactive   -       active console wait
- *     @event: event code
- *     @n: new console
- *
- *     Helper for event waits. Used to implement the legacy
- *     event waiting ioctls in terms of events
- */
-
-int vt_waitactive(int n)
-{
-       struct vt_event_wait vw;
-       do {
-               if (n == fg_console + 1)
-                       break;
-               vw.event.event = VT_EVENT_SWITCH;
-               vt_event_wait(&vw);
-               if (vw.done == 0)
-                       return -EINTR;
-       } while (vw.event.newev != n);
-       return 0;
-}
-
-/*
- * these are the valid i/o ports we're allowed to change. they map all the
- * video ports
- */
-#define GPFIRST 0x3b4
-#define GPLAST 0x3df
-#define GPNUM (GPLAST - GPFIRST + 1)
-
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-static inline int
-do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
-{
-       struct kbentry tmp;
-       ushort *key_map, val, ov;
-
-       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-               return -EFAULT;
-
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
-
-       switch (cmd) {
-       case KDGKBENT:
-               key_map = key_maps[s];
-               if (key_map) {
-                   val = U(key_map[i]);
-                   if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-                       val = K_HOLE;
-               } else
-                   val = (i ? K_HOLE : K_NOSUCHMAP);
-               return put_user(val, &user_kbe->kb_value);
-       case KDSKBENT:
-               if (!perm)
-                       return -EPERM;
-               if (!i && v == K_NOSUCHMAP) {
-                       /* deallocate map */
-                       key_map = key_maps[s];
-                       if (s && key_map) {
-                           key_maps[s] = NULL;
-                           if (key_map[0] == U(K_ALLOCATED)) {
-                                       kfree(key_map);
-                                       keymap_count--;
-                           }
-                       }
-                       break;
-               }
-
-               if (KTYP(v) < NR_TYPES) {
-                   if (KVAL(v) > max_vals[KTYP(v)])
-                               return -EINVAL;
-               } else
-                   if (kbd->kbdmode != VC_UNICODE)
-                               return -EINVAL;
-
-               /* ++Geert: non-PC keyboards may generate keycode zero */
-#if !defined(__mc68000__) && !defined(__powerpc__)
-               /* assignment to entry 0 only tests validity of args */
-               if (!i)
-                       break;
-#endif
-
-               if (!(key_map = key_maps[s])) {
-                       int j;
-
-                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-                           !capable(CAP_SYS_RESOURCE))
-                               return -EPERM;
-
-                       key_map = kmalloc(sizeof(plain_map),
-                                                    GFP_KERNEL);
-                       if (!key_map)
-                               return -ENOMEM;
-                       key_maps[s] = key_map;
-                       key_map[0] = U(K_ALLOCATED);
-                       for (j = 1; j < NR_KEYS; j++)
-                               key_map[j] = U(K_HOLE);
-                       keymap_count++;
-               }
-               ov = U(key_map[i]);
-               if (v == ov)
-                       break;  /* nothing to do */
-               /*
-                * Attention Key.
-                */
-               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               key_map[i] = U(v);
-               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-                       compute_shiftstate();
-               break;
-       }
-       return 0;
-}
-#undef i
-#undef s
-#undef v
-
-static inline int 
-do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
-{
-       struct kbkeycode tmp;
-       int kc = 0;
-
-       if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
-               return -EFAULT;
-       switch (cmd) {
-       case KDGETKEYCODE:
-               kc = getkeycode(tmp.scancode);
-               if (kc >= 0)
-                       kc = put_user(kc, &user_kbkc->keycode);
-               break;
-       case KDSETKEYCODE:
-               if (!perm)
-                       return -EPERM;
-               kc = setkeycode(tmp.scancode, tmp.keycode);
-               break;
-       }
-       return kc;
-}
-
-static inline int
-do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
-{
-       struct kbsentry *kbs;
-       char *p;
-       u_char *q;
-       u_char __user *up;
-       int sz;
-       int delta;
-       char *first_free, *fj, *fnw;
-       int i, j, k;
-       int ret;
-
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
-
-       kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-       if (!kbs) {
-               ret = -ENOMEM;
-               goto reterr;
-       }
-
-       /* we mostly copy too much here (512bytes), but who cares ;) */
-       if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-               ret = -EFAULT;
-               goto reterr;
-       }
-       kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-       i = kbs->kb_func;
-
-       switch (cmd) {
-       case KDGKBSENT:
-               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-                                                 a struct member */
-               up = user_kdgkb->kb_string;
-               p = func_table[i];
-               if(p)
-                       for ( ; *p && sz; p++, sz--)
-                               if (put_user(*p, up++)) {
-                                       ret = -EFAULT;
-                                       goto reterr;
-                               }
-               if (put_user('\0', up)) {
-                       ret = -EFAULT;
-                       goto reterr;
-               }
-               kfree(kbs);
-               return ((p && *p) ? -EOVERFLOW : 0);
-       case KDSKBSENT:
-               if (!perm) {
-                       ret = -EPERM;
-                       goto reterr;
-               }
-
-               q = func_table[i];
-               first_free = funcbufptr + (funcbufsize - funcbufleft);
-               for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
-                       ;
-               if (j < MAX_NR_FUNC)
-                       fj = func_table[j];
-               else
-                       fj = first_free;
-
-               delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-               if (delta <= funcbufleft) {     /* it fits in current buf */
-                   if (j < MAX_NR_FUNC) {
-                       memmove(fj + delta, fj, first_free - fj);
-                       for (k = j; k < MAX_NR_FUNC; k++)
-                           if (func_table[k])
-                               func_table[k] += delta;
-                   }
-                   if (!q)
-                     func_table[i] = fj;
-                   funcbufleft -= delta;
-               } else {                        /* allocate a larger buffer */
-                   sz = 256;
-                   while (sz < funcbufsize - funcbufleft + delta)
-                     sz <<= 1;
-                   fnw = kmalloc(sz, GFP_KERNEL);
-                   if(!fnw) {
-                     ret = -ENOMEM;
-                     goto reterr;
-                   }
-
-                   if (!q)
-                     func_table[i] = fj;
-                   if (fj > funcbufptr)
-                       memmove(fnw, funcbufptr, fj - funcbufptr);
-                   for (k = 0; k < j; k++)
-                     if (func_table[k])
-                       func_table[k] = fnw + (func_table[k] - funcbufptr);
-
-                   if (first_free > fj) {
-                       memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
-                       for (k = j; k < MAX_NR_FUNC; k++)
-                         if (func_table[k])
-                           func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
-                   }
-                   if (funcbufptr != func_buf)
-                     kfree(funcbufptr);
-                   funcbufptr = fnw;
-                   funcbufleft = funcbufleft - delta + sz - funcbufsize;
-                   funcbufsize = sz;
-               }
-               strcpy(func_table[i], kbs->kb_string);
-               break;
-       }
-       ret = 0;
-reterr:
-       kfree(kbs);
-       return ret;
-}
-
-static inline int 
-do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
-{
-       struct consolefontdesc cfdarg;
-       int i;
-
-       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
-               return -EFAULT;
-       
-       switch (cmd) {
-       case PIO_FONTX:
-               if (!perm)
-                       return -EPERM;
-               op->op = KD_FONT_OP_SET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = cfdarg.chardata;
-               return con_font_op(vc_cons[fg_console].d, op);
-       case GIO_FONTX: {
-               op->op = KD_FONT_OP_GET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = cfdarg.chardata;
-               i = con_font_op(vc_cons[fg_console].d, op);
-               if (i)
-                       return i;
-               cfdarg.charheight = op->height;
-               cfdarg.charcount = op->charcount;
-               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
-                       return -EFAULT;
-               return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static inline int 
-do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
-{
-       struct unimapdesc tmp;
-
-       if (copy_from_user(&tmp, user_ud, sizeof tmp))
-               return -EFAULT;
-       if (tmp.entries)
-               if (!access_ok(VERIFY_WRITE, tmp.entries,
-                               tmp.entry_ct*sizeof(struct unipair)))
-                       return -EFAULT;
-       switch (cmd) {
-       case PIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-               return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
-       case GIO_UNIMAP:
-               if (!perm && fg_console != vc->vc_num)
-                       return -EPERM;
-               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
-       }
-       return 0;
-}
-
-
-
-/*
- * We handle the console-specific ioctl's here.  We allow the
- * capability to modify any console, not just the fg_console. 
- */
-int vt_ioctl(struct tty_struct *tty, struct file * file,
-            unsigned int cmd, unsigned long arg)
-{
-       struct vc_data *vc = tty->driver_data;
-       struct console_font_op op;      /* used in multiple places here */
-       struct kbd_struct * kbd;
-       unsigned int console;
-       unsigned char ucval;
-       unsigned int uival;
-       void __user *up = (void __user *)arg;
-       int i, perm;
-       int ret = 0;
-
-       console = vc->vc_num;
-
-       tty_lock();
-
-       if (!vc_cons_allocated(console)) {      /* impossible? */
-               ret = -ENOIOCTLCMD;
-               goto out;
-       }
-
-
-       /*
-        * To have permissions to do most of the vt ioctls, we either have
-        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-        */
-       perm = 0;
-       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-               perm = 1;
-       kbd = kbd_table + console;
-       switch (cmd) {
-       case TIOCLINUX:
-               ret = tioclinux(tty, arg);
-               break;
-       case KIOCSOUND:
-               if (!perm)
-                       goto eperm;
-               /*
-                * The use of PIT_TICK_RATE is historic, it used to be
-                * the platform-dependent CLOCK_TICK_RATE between 2.6.12
-                * and 2.6.36, which was a minor but unfortunate ABI
-                * change.
-                */
-               if (arg)
-                       arg = PIT_TICK_RATE / arg;
-               kd_mksound(arg, 0);
-               break;
-
-       case KDMKTONE:
-               if (!perm)
-                       goto eperm;
-       {
-               unsigned int ticks, count;
-               
-               /*
-                * Generate the tone for the appropriate number of ticks.
-                * If the time is zero, turn off sound ourselves.
-                */
-               ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
-               count = ticks ? (arg & 0xffff) : 0;
-               if (count)
-                       count = PIT_TICK_RATE / count;
-               kd_mksound(count, ticks);
-               break;
-       }
-
-       case KDGKBTYPE:
-               /*
-                * this is naive.
-                */
-               ucval = KB_101;
-               goto setchar;
-
-               /*
-                * These cannot be implemented on any machine that implements
-                * ioperm() in user level (such as Alpha PCs) or not at all.
-                *
-                * XXX: you should never use these, just call ioperm directly..
-                */
-#ifdef CONFIG_X86
-       case KDADDIO:
-       case KDDELIO:
-               /*
-                * KDADDIO and KDDELIO may be able to add ports beyond what
-                * we reject here, but to be safe...
-                */
-               if (arg < GPFIRST || arg > GPLAST) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
-               break;
-
-       case KDENABIO:
-       case KDDISABIO:
-               ret = sys_ioperm(GPFIRST, GPNUM,
-                                 (cmd == KDENABIO)) ? -ENXIO : 0;
-               break;
-#endif
-
-       /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
-               
-       case KDKBDREP:
-       {
-               struct kbd_repeat kbrep;
-               
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-
-               if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
-                       ret =  -EFAULT;
-                       break;
-               }
-               ret = kbd_rate(&kbrep);
-               if (ret)
-                       break;
-               if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case KDSETMODE:
-               /*
-                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
-                * doesn't do a whole lot. i'm not sure if it should do any
-                * restoration of modes or what...
-                *
-                * XXX It should at least call into the driver, fbdev's definitely
-                * need to restore their engine state. --BenH
-                */
-               if (!perm)
-                       goto eperm;
-               switch (arg) {
-               case KD_GRAPHICS:
-                       break;
-               case KD_TEXT0:
-               case KD_TEXT1:
-                       arg = KD_TEXT;
-               case KD_TEXT:
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-               if (vc->vc_mode == (unsigned char) arg)
-                       break;
-               vc->vc_mode = (unsigned char) arg;
-               if (console != fg_console)
-                       break;
-               /*
-                * explicitly blank/unblank the screen if switching modes
-                */
-               acquire_console_sem();
-               if (arg == KD_TEXT)
-                       do_unblank_screen(1);
-               else
-                       do_blank_screen(1);
-               release_console_sem();
-               break;
-
-       case KDGETMODE:
-               uival = vc->vc_mode;
-               goto setint;
-
-       case KDMAPDISP:
-       case KDUNMAPDISP:
-               /*
-                * these work like a combination of mmap and KDENABIO.
-                * this could be easily finished.
-                */
-               ret = -EINVAL;
-               break;
-
-       case KDSKBMODE:
-               if (!perm)
-                       goto eperm;
-               switch(arg) {
-                 case K_RAW:
-                       kbd->kbdmode = VC_RAW;
-                       break;
-                 case K_MEDIUMRAW:
-                       kbd->kbdmode = VC_MEDIUMRAW;
-                       break;
-                 case K_XLATE:
-                       kbd->kbdmode = VC_XLATE;
-                       compute_shiftstate();
-                       break;
-                 case K_UNICODE:
-                       kbd->kbdmode = VC_UNICODE;
-                       compute_shiftstate();
-                       break;
-                 default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-               tty_ldisc_flush(tty);
-               break;
-
-       case KDGKBMODE:
-               uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
-                                (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
-                                (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
-                                K_XLATE);
-               goto setint;
-
-       /* this could be folded into KDSKBMODE, but for compatibility
-          reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
-       case KDSKBMETA:
-               switch(arg) {
-                 case K_METABIT:
-                       clr_vc_kbd_mode(kbd, VC_META);
-                       break;
-                 case K_ESCPREFIX:
-                       set_vc_kbd_mode(kbd, VC_META);
-                       break;
-                 default:
-                       ret = -EINVAL;
-               }
-               break;
-
-       case KDGKBMETA:
-               uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
-       setint:
-               ret = put_user(uival, (int __user *)arg);
-               break;
-
-       case KDGETKEYCODE:
-       case KDSETKEYCODE:
-               if(!capable(CAP_SYS_TTY_CONFIG))
-                       perm = 0;
-               ret = do_kbkeycode_ioctl(cmd, up, perm);
-               break;
-
-       case KDGKBENT:
-       case KDSKBENT:
-               ret = do_kdsk_ioctl(cmd, up, perm, kbd);
-               break;
-
-       case KDGKBSENT:
-       case KDSKBSENT:
-               ret = do_kdgkb_ioctl(cmd, up, perm);
-               break;
-
-       case KDGKBDIACR:
-       {
-               struct kbdiacrs __user *a = up;
-               struct kbdiacr diacr;
-               int i;
-
-               if (put_user(accent_table_size, &a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               for (i = 0; i < accent_table_size; i++) {
-                       diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
-                       diacr.base = conv_uni_to_8bit(accent_table[i].base);
-                       diacr.result = conv_uni_to_8bit(accent_table[i].result);
-                       if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-               }
-               break;
-       }
-       case KDGKBDIACRUC:
-       {
-               struct kbdiacrsuc __user *a = up;
-
-               if (put_user(accent_table_size, &a->kb_cnt))
-                       ret = -EFAULT;
-               else if (copy_to_user(a->kbdiacruc, accent_table,
-                               accent_table_size*sizeof(struct kbdiacruc)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case KDSKBDIACR:
-       {
-               struct kbdiacrs __user *a = up;
-               struct kbdiacr diacr;
-               unsigned int ct;
-               int i;
-
-               if (!perm)
-                       goto eperm;
-               if (get_user(ct,&a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (ct >= MAX_DIACR) {
-                       ret = -EINVAL;
-                       break;
-               }
-               accent_table_size = ct;
-               for (i = 0; i < ct; i++) {
-                       if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
-                       accent_table[i].base = conv_8bit_to_uni(diacr.base);
-                       accent_table[i].result = conv_8bit_to_uni(diacr.result);
-               }
-               break;
-       }
-
-       case KDSKBDIACRUC:
-       {
-               struct kbdiacrsuc __user *a = up;
-               unsigned int ct;
-
-               if (!perm)
-                       goto eperm;
-               if (get_user(ct,&a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (ct >= MAX_DIACR) {
-                       ret = -EINVAL;
-                       break;
-               }
-               accent_table_size = ct;
-               if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       /* the ioctls below read/set the flags usually shown in the leds */
-       /* don't use them - they will go away without warning */
-       case KDGKBLED:
-               ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
-               goto setchar;
-
-       case KDSKBLED:
-               if (!perm)
-                       goto eperm;
-               if (arg & ~0x77) {
-                       ret = -EINVAL;
-                       break;
-               }
-               kbd->ledflagstate = (arg & 7);
-               kbd->default_ledflagstate = ((arg >> 4) & 7);
-               set_leds();
-               break;
-
-       /* the ioctls below only set the lights, not the functions */
-       /* for those, see KDGKBLED and KDSKBLED above */
-       case KDGETLED:
-               ucval = getledstate();
-       setchar:
-               ret = put_user(ucval, (char __user *)arg);
-               break;
-
-       case KDSETLED:
-               if (!perm)
-                       goto eperm;
-               setledstate(kbd, arg);
-               break;
-
-       /*
-        * A process can indicate its willingness to accept signals
-        * generated by pressing an appropriate key combination.
-        * Thus, one can have a daemon that e.g. spawns a new console
-        * upon a keypress and then changes to it.
-        * See also the kbrequest field of inittab(5).
-        */
-       case KDSIGACCEPT:
-       {
-               if (!perm || !capable(CAP_KILL))
-                       goto eperm;
-               if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
-                       ret = -EINVAL;
-               else {
-                       spin_lock_irq(&vt_spawn_con.lock);
-                       put_pid(vt_spawn_con.pid);
-                       vt_spawn_con.pid = get_pid(task_pid(current));
-                       vt_spawn_con.sig = arg;
-                       spin_unlock_irq(&vt_spawn_con.lock);
-               }
-               break;
-       }
-
-       case VT_SETMODE:
-       {
-               struct vt_mode tmp;
-
-               if (!perm)
-                       goto eperm;
-               if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-               acquire_console_sem();
-               vc->vt_mode = tmp;
-               /* the frsig is ignored, so we set it to 0 */
-               vc->vt_mode.frsig = 0;
-               put_pid(vc->vt_pid);
-               vc->vt_pid = get_pid(task_pid(current));
-               /* no switch is required -- saw@shade.msu.ru */
-               vc->vt_newvt = -1;
-               release_console_sem();
-               break;
-       }
-
-       case VT_GETMODE:
-       {
-               struct vt_mode tmp;
-               int rc;
-
-               acquire_console_sem();
-               memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
-               release_console_sem();
-
-               rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
-               if (rc)
-                       ret = -EFAULT;
-               break;
-       }
-
-       /*
-        * Returns global vt state. Note that VT 0 is always open, since
-        * it's an alias for the current VT, and people can't use it here.
-        * We cannot return state for more than 16 VTs, since v_state is short.
-        */
-       case VT_GETSTATE:
-       {
-               struct vt_stat __user *vtstat = up;
-               unsigned short state, mask;
-
-               if (put_user(fg_console + 1, &vtstat->v_active))
-                       ret = -EFAULT;
-               else {
-                       state = 1;      /* /dev/tty0 is always open */
-                       for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
-                                                       ++i, mask <<= 1)
-                               if (VT_IS_IN_USE(i))
-                                       state |= mask;
-                       ret = put_user(state, &vtstat->v_state);
-               }
-               break;
-       }
-
-       /*
-        * Returns the first available (non-opened) console.
-        */
-       case VT_OPENQRY:
-               for (i = 0; i < MAX_NR_CONSOLES; ++i)
-                       if (! VT_IS_IN_USE(i))
-                               break;
-               uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
-               goto setint;             
-
-       /*
-        * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
-        * with num >= 1 (switches to vt 0, our console, are not allowed, just
-        * to preserve sanity).
-        */
-       case VT_ACTIVATE:
-               if (!perm)
-                       goto eperm;
-               if (arg == 0 || arg > MAX_NR_CONSOLES)
-                       ret =  -ENXIO;
-               else {
-                       arg--;
-                       acquire_console_sem();
-                       ret = vc_allocate(arg);
-                       release_console_sem();
-                       if (ret)
-                               break;
-                       set_console(arg);
-               }
-               break;
-
-       case VT_SETACTIVATE:
-       {
-               struct vt_setactivate vsa;
-
-               if (!perm)
-                       goto eperm;
-
-               if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
-                                       sizeof(struct vt_setactivate))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
-                       ret = -ENXIO;
-               else {
-                       vsa.console--;
-                       acquire_console_sem();
-                       ret = vc_allocate(vsa.console);
-                       if (ret == 0) {
-                               struct vc_data *nvc;
-                               /* This is safe providing we don't drop the
-                                  console sem between vc_allocate and
-                                  finishing referencing nvc */
-                               nvc = vc_cons[vsa.console].d;
-                               nvc->vt_mode = vsa.mode;
-                               nvc->vt_mode.frsig = 0;
-                               put_pid(nvc->vt_pid);
-                               nvc->vt_pid = get_pid(task_pid(current));
-                       }
-                       release_console_sem();
-                       if (ret)
-                               break;
-                       /* Commence switch and lock */
-                       set_console(arg);
-               }
-       }
-
-       /*
-        * wait until the specified VT has been activated
-        */
-       case VT_WAITACTIVE:
-               if (!perm)
-                       goto eperm;
-               if (arg == 0 || arg > MAX_NR_CONSOLES)
-                       ret = -ENXIO;
-               else
-                       ret = vt_waitactive(arg);
-               break;
-
-       /*
-        * If a vt is under process control, the kernel will not switch to it
-        * immediately, but postpone the operation until the process calls this
-        * ioctl, allowing the switch to complete.
-        *
-        * According to the X sources this is the behavior:
-        *      0:      pending switch-from not OK
-        *      1:      pending switch-from OK
-        *      2:      completed switch-to OK
-        */
-       case VT_RELDISP:
-               if (!perm)
-                       goto eperm;
-
-               if (vc->vt_mode.mode != VT_PROCESS) {
-                       ret = -EINVAL;
-                       break;
-               }
-               /*
-                * Switching-from response
-                */
-               acquire_console_sem();
-               if (vc->vt_newvt >= 0) {
-                       if (arg == 0)
-                               /*
-                                * Switch disallowed, so forget we were trying
-                                * to do it.
-                                */
-                               vc->vt_newvt = -1;
-
-                       else {
-                               /*
-                                * The current vt has been released, so
-                                * complete the switch.
-                                */
-                               int newvt;
-                               newvt = vc->vt_newvt;
-                               vc->vt_newvt = -1;
-                               ret = vc_allocate(newvt);
-                               if (ret) {
-                                       release_console_sem();
-                                       break;
-                               }
-                               /*
-                                * When we actually do the console switch,
-                                * make sure we are atomic with respect to
-                                * other console switches..
-                                */
-                               complete_change_console(vc_cons[newvt].d);
-                       }
-               } else {
-                       /*
-                        * Switched-to response
-                        */
-                       /*
-                        * If it's just an ACK, ignore it
-                        */
-                       if (arg != VT_ACKACQ)
-                               ret = -EINVAL;
-               }
-               release_console_sem();
-               break;
-
-        /*
-         * Disallocate memory associated to VT (but leave VT1)
-         */
-        case VT_DISALLOCATE:
-               if (arg > MAX_NR_CONSOLES) {
-                       ret = -ENXIO;
-                       break;
-               }
-               if (arg == 0) {
-                   /* deallocate all unused consoles, but leave 0 */
-                       acquire_console_sem();
-                       for (i=1; i<MAX_NR_CONSOLES; i++)
-                               if (! VT_BUSY(i))
-                                       vc_deallocate(i);
-                       release_console_sem();
-               } else {
-                       /* deallocate a single console, if possible */
-                       arg--;
-                       if (VT_BUSY(arg))
-                               ret = -EBUSY;
-                       else if (arg) {                       /* leave 0 */
-                               acquire_console_sem();
-                               vc_deallocate(arg);
-                               release_console_sem();
-                       }
-               }
-               break;
-
-       case VT_RESIZE:
-       {
-               struct vt_sizes __user *vtsizes = up;
-               struct vc_data *vc;
-
-               ushort ll,cc;
-               if (!perm)
-                       goto eperm;
-               if (get_user(ll, &vtsizes->v_rows) ||
-                   get_user(cc, &vtsizes->v_cols))
-                       ret = -EFAULT;
-               else {
-                       acquire_console_sem();
-                       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-                               vc = vc_cons[i].d;
-
-                               if (vc) {
-                                       vc->vc_resize_user = 1;
-                                       vc_resize(vc_cons[i].d, cc, ll);
-                               }
-                       }
-                       release_console_sem();
-               }
-               break;
-       }
-
-       case VT_RESIZEX:
-       {
-               struct vt_consize __user *vtconsize = up;
-               ushort ll,cc,vlin,clin,vcol,ccol;
-               if (!perm)
-                       goto eperm;
-               if (!access_ok(VERIFY_READ, vtconsize,
-                               sizeof(struct vt_consize))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               /* FIXME: Should check the copies properly */
-               __get_user(ll, &vtconsize->v_rows);
-               __get_user(cc, &vtconsize->v_cols);
-               __get_user(vlin, &vtconsize->v_vlin);
-               __get_user(clin, &vtconsize->v_clin);
-               __get_user(vcol, &vtconsize->v_vcol);
-               __get_user(ccol, &vtconsize->v_ccol);
-               vlin = vlin ? vlin : vc->vc_scan_lines;
-               if (clin) {
-                       if (ll) {
-                               if (ll != vlin/clin) {
-                                       /* Parameters don't add up */
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       } else 
-                               ll = vlin/clin;
-               }
-               if (vcol && ccol) {
-                       if (cc) {
-                               if (cc != vcol/ccol) {
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       } else
-                               cc = vcol/ccol;
-               }
-
-               if (clin > 32) {
-                       ret =  -EINVAL;
-                       break;
-               }
-                   
-               for (i = 0; i < MAX_NR_CONSOLES; i++) {
-                       if (!vc_cons[i].d)
-                               continue;
-                       acquire_console_sem();
-                       if (vlin)
-                               vc_cons[i].d->vc_scan_lines = vlin;
-                       if (clin)
-                               vc_cons[i].d->vc_font.height = clin;
-                       vc_cons[i].d->vc_resize_user = 1;
-                       vc_resize(vc_cons[i].d, cc, ll);
-                       release_console_sem();
-               }
-               break;
-       }
-
-       case PIO_FONT: {
-               if (!perm)
-                       goto eperm;
-               op.op = KD_FONT_OP_SET;
-               op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
-               op.width = 8;
-               op.height = 0;
-               op.charcount = 256;
-               op.data = up;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               break;
-       }
-
-       case GIO_FONT: {
-               op.op = KD_FONT_OP_GET;
-               op.flags = KD_FONT_FLAG_OLD;
-               op.width = 8;
-               op.height = 32;
-               op.charcount = 256;
-               op.data = up;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               break;
-       }
-
-       case PIO_CMAP:
-                if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_cmap(up);
-               break;
-
-       case GIO_CMAP:
-                ret = con_get_cmap(up);
-               break;
-
-       case PIO_FONTX:
-       case GIO_FONTX:
-               ret = do_fontx_ioctl(cmd, up, perm, &op);
-               break;
-
-       case PIO_FONTRESET:
-       {
-               if (!perm)
-                       goto eperm;
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
-               /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
-                  font is not saved. */
-               ret = -ENOSYS;
-               break;
-#else
-               {
-               op.op = KD_FONT_OP_SET_DEFAULT;
-               op.data = NULL;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               if (ret)
-                       break;
-               con_set_default_unimap(vc_cons[fg_console].d);
-               break;
-               }
-#endif
-       }
-
-       case KDFONTOP: {
-               if (copy_from_user(&op, up, sizeof(op))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (!perm && op.op != KD_FONT_OP_GET)
-                       goto eperm;
-               ret = con_font_op(vc, &op);
-               if (ret)
-                       break;
-               if (copy_to_user(up, &op, sizeof(op)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case PIO_SCRNMAP:
-               if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_trans_old(up);
-               break;
-
-       case GIO_SCRNMAP:
-               ret = con_get_trans_old(up);
-               break;
-
-       case PIO_UNISCRNMAP:
-               if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_trans_new(up);
-               break;
-
-       case GIO_UNISCRNMAP:
-               ret = con_get_trans_new(up);
-               break;
-
-       case PIO_UNIMAPCLR:
-             { struct unimapinit ui;
-               if (!perm)
-                       goto eperm;
-               ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
-               if (ret)
-                       ret = -EFAULT;
-               else
-                       con_clear_unimap(vc, &ui);
-               break;
-             }
-
-       case PIO_UNIMAP:
-       case GIO_UNIMAP:
-               ret = do_unimap_ioctl(cmd, up, perm, vc);
-               break;
-
-       case VT_LOCKSWITCH:
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-               vt_dont_switch = 1;
-               break;
-       case VT_UNLOCKSWITCH:
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-               vt_dont_switch = 0;
-               break;
-       case VT_GETHIFONTMASK:
-               ret = put_user(vc->vc_hi_font_mask,
-                                       (unsigned short __user *)arg);
-               break;
-       case VT_WAITEVENT:
-               ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-       }
-out:
-       tty_unlock();
-       return ret;
-eperm:
-       ret = -EPERM;
-       goto out;
-}
-
-void reset_vc(struct vc_data *vc)
-{
-       vc->vc_mode = KD_TEXT;
-       kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-       vc->vt_mode.mode = VT_AUTO;
-       vc->vt_mode.waitv = 0;
-       vc->vt_mode.relsig = 0;
-       vc->vt_mode.acqsig = 0;
-       vc->vt_mode.frsig = 0;
-       put_pid(vc->vt_pid);
-       vc->vt_pid = NULL;
-       vc->vt_newvt = -1;
-       if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
-               reset_palette(vc);
-}
-
-void vc_SAK(struct work_struct *work)
-{
-       struct vc *vc_con =
-               container_of(work, struct vc, SAK_work);
-       struct vc_data *vc;
-       struct tty_struct *tty;
-
-       acquire_console_sem();
-       vc = vc_con->d;
-       if (vc) {
-               tty = vc->port.tty;
-               /*
-                * SAK should also work in all raw modes and reset
-                * them properly.
-                */
-               if (tty)
-                       __do_SAK(tty);
-               reset_vc(vc);
-       }
-       release_console_sem();
-}
-
-#ifdef CONFIG_COMPAT
-
-struct compat_consolefontdesc {
-       unsigned short charcount;       /* characters in font (256 or 512) */
-       unsigned short charheight;      /* scan lines per character (1-32) */
-       compat_caddr_t chardata;        /* font data in expanded form */
-};
-
-static inline int
-compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
-                        int perm, struct console_font_op *op)
-{
-       struct compat_consolefontdesc cfdarg;
-       int i;
-
-       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
-               return -EFAULT;
-
-       switch (cmd) {
-       case PIO_FONTX:
-               if (!perm)
-                       return -EPERM;
-               op->op = KD_FONT_OP_SET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = compat_ptr(cfdarg.chardata);
-               return con_font_op(vc_cons[fg_console].d, op);
-       case GIO_FONTX:
-               op->op = KD_FONT_OP_GET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = compat_ptr(cfdarg.chardata);
-               i = con_font_op(vc_cons[fg_console].d, op);
-               if (i)
-                       return i;
-               cfdarg.charheight = op->height;
-               cfdarg.charcount = op->charcount;
-               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
-                       return -EFAULT;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-struct compat_console_font_op {
-       compat_uint_t op;        /* operation code KD_FONT_OP_* */
-       compat_uint_t flags;     /* KD_FONT_FLAG_* */
-       compat_uint_t width, height;     /* font size */
-       compat_uint_t charcount;
-       compat_caddr_t data;    /* font data with height fixed to 32 */
-};
-
-static inline int
-compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
-                        int perm, struct console_font_op *op, struct vc_data *vc)
-{
-       int i;
-
-       if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
-               return -EFAULT;
-       if (!perm && op->op != KD_FONT_OP_GET)
-               return -EPERM;
-       op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
-       op->flags |= KD_FONT_FLAG_OLD;
-       i = con_font_op(vc, op);
-       if (i)
-               return i;
-       ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
-       if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
-               return -EFAULT;
-       return 0;
-}
-
-struct compat_unimapdesc {
-       unsigned short entry_ct;
-       compat_caddr_t entries;
-};
-
-static inline int
-compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
-                        int perm, struct vc_data *vc)
-{
-       struct compat_unimapdesc tmp;
-       struct unipair __user *tmp_entries;
-
-       if (copy_from_user(&tmp, user_ud, sizeof tmp))
-               return -EFAULT;
-       tmp_entries = compat_ptr(tmp.entries);
-       if (tmp_entries)
-               if (!access_ok(VERIFY_WRITE, tmp_entries,
-                               tmp.entry_ct*sizeof(struct unipair)))
-                       return -EFAULT;
-       switch (cmd) {
-       case PIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-               return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
-       case GIO_UNIMAP:
-               if (!perm && fg_console != vc->vc_num)
-                       return -EPERM;
-               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
-       }
-       return 0;
-}
-
-long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
-            unsigned int cmd, unsigned long arg)
-{
-       struct vc_data *vc = tty->driver_data;
-       struct console_font_op op;      /* used in multiple places here */
-       struct kbd_struct *kbd;
-       unsigned int console;
-       void __user *up = (void __user *)arg;
-       int perm;
-       int ret = 0;
-
-       console = vc->vc_num;
-
-       tty_lock();
-
-       if (!vc_cons_allocated(console)) {      /* impossible? */
-               ret = -ENOIOCTLCMD;
-               goto out;
-       }
-
-       /*
-        * To have permissions to do most of the vt ioctls, we either have
-        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-        */
-       perm = 0;
-       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-               perm = 1;
-
-       kbd = kbd_table + console;
-       switch (cmd) {
-       /*
-        * these need special handlers for incompatible data structures
-        */
-       case PIO_FONTX:
-       case GIO_FONTX:
-               ret = compat_fontx_ioctl(cmd, up, perm, &op);
-               break;
-
-       case KDFONTOP:
-               ret = compat_kdfontop_ioctl(up, perm, &op, vc);
-               break;
-
-       case PIO_UNIMAP:
-       case GIO_UNIMAP:
-               ret = compat_unimap_ioctl(cmd, up, perm, vc);
-               break;
-
-       /*
-        * all these treat 'arg' as an integer
-        */
-       case KIOCSOUND:
-       case KDMKTONE:
-#ifdef CONFIG_X86
-       case KDADDIO:
-       case KDDELIO:
-#endif
-       case KDSETMODE:
-       case KDMAPDISP:
-       case KDUNMAPDISP:
-       case KDSKBMODE:
-       case KDSKBMETA:
-       case KDSKBLED:
-       case KDSETLED:
-       case KDSIGACCEPT:
-       case VT_ACTIVATE:
-       case VT_WAITACTIVE:
-       case VT_RELDISP:
-       case VT_DISALLOCATE:
-       case VT_RESIZE:
-       case VT_RESIZEX:
-               goto fallback;
-
-       /*
-        * the rest has a compatible data structure behind arg,
-        * but we have to convert it to a proper 64 bit pointer.
-        */
-       default:
-               arg = (unsigned long)compat_ptr(arg);
-               goto fallback;
-       }
-out:
-       tty_unlock();
-       return ret;
-
-fallback:
-       tty_unlock();
-       return vt_ioctl(tty, file, cmd, arg);
-}
-
-
-#endif /* CONFIG_COMPAT */
-
-
-/*
- * Performs the back end of a vt switch. Called under the console
- * semaphore.
- */
-static void complete_change_console(struct vc_data *vc)
-{
-       unsigned char old_vc_mode;
-       int old = fg_console;
-
-       last_console = fg_console;
-
-       /*
-        * If we're switching, we could be going from KD_GRAPHICS to
-        * KD_TEXT mode or vice versa, which means we need to blank or
-        * unblank the screen later.
-        */
-       old_vc_mode = vc_cons[fg_console].d->vc_mode;
-       switch_screen(vc);
-
-       /*
-        * This can't appear below a successful kill_pid().  If it did,
-        * then the *blank_screen operation could occur while X, having
-        * received acqsig, is waking up on another processor.  This
-        * condition can lead to overlapping accesses to the VGA range
-        * and the framebuffer (causing system lockups).
-        *
-        * To account for this we duplicate this code below only if the
-        * controlling process is gone and we've called reset_vc.
-        */
-       if (old_vc_mode != vc->vc_mode) {
-               if (vc->vc_mode == KD_TEXT)
-                       do_unblank_screen(1);
-               else
-                       do_blank_screen(1);
-       }
-
-       /*
-        * If this new console is under process control, send it a signal
-        * telling it that it has acquired. Also check if it has died and
-        * clean up (similar to logic employed in change_console())
-        */
-       if (vc->vt_mode.mode == VT_PROCESS) {
-               /*
-                * Send the signal as privileged - kill_pid() will
-                * tell us if the process has gone or something else
-                * is awry
-                */
-               if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
-               /*
-                * The controlling process has died, so we revert back to
-                * normal operation. In this case, we'll also change back
-                * to KD_TEXT mode. I'm not sure if this is strictly correct
-                * but it saves the agony when the X server dies and the screen
-                * remains blanked due to KD_GRAPHICS! It would be nice to do
-                * this outside of VT_PROCESS but there is no single process
-                * to account for and tracking tty count may be undesirable.
-                */
-                       reset_vc(vc);
-
-                       if (old_vc_mode != vc->vc_mode) {
-                               if (vc->vc_mode == KD_TEXT)
-                                       do_unblank_screen(1);
-                               else
-                                       do_blank_screen(1);
-                       }
-               }
-       }
-
-       /*
-        * Wake anyone waiting for their VT to activate
-        */
-       vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
-       return;
-}
-
-/*
- * Performs the front-end of a vt switch
- */
-void change_console(struct vc_data *new_vc)
-{
-       struct vc_data *vc;
-
-       if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
-               return;
-
-       /*
-        * If this vt is in process mode, then we need to handshake with
-        * that process before switching. Essentially, we store where that
-        * vt wants to switch to and wait for it to tell us when it's done
-        * (via VT_RELDISP ioctl).
-        *
-        * We also check to see if the controlling process still exists.
-        * If it doesn't, we reset this vt to auto mode and continue.
-        * This is a cheap way to track process control. The worst thing
-        * that can happen is: we send a signal to a process, it dies, and
-        * the switch gets "lost" waiting for a response; hopefully, the
-        * user will try again, we'll detect the process is gone (unless
-        * the user waits just the right amount of time :-) and revert the
-        * vt to auto control.
-        */
-       vc = vc_cons[fg_console].d;
-       if (vc->vt_mode.mode == VT_PROCESS) {
-               /*
-                * Send the signal as privileged - kill_pid() will
-                * tell us if the process has gone or something else
-                * is awry.
-                *
-                * We need to set vt_newvt *before* sending the signal or we
-                * have a race.
-                */
-               vc->vt_newvt = new_vc->vc_num;
-               if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
-                       /*
-                        * It worked. Mark the vt to switch to and
-                        * return. The process needs to send us a
-                        * VT_RELDISP ioctl to complete the switch.
-                        */
-                       return;
-               }
-
-               /*
-                * The controlling process has died, so we revert back to
-                * normal operation. In this case, we'll also change back
-                * to KD_TEXT mode. I'm not sure if this is strictly correct
-                * but it saves the agony when the X server dies and the screen
-                * remains blanked due to KD_GRAPHICS! It would be nice to do
-                * this outside of VT_PROCESS but there is no single process
-                * to account for and tracking tty count may be undesirable.
-                */
-               reset_vc(vc);
-
-               /*
-                * Fall through to normal (VT_AUTO) handling of the switch...
-                */
-       }
-
-       /*
-        * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
-        */
-       if (vc->vc_mode == KD_GRAPHICS)
-               return;
-
-       complete_change_console(new_vc);
-}
-
-/* Perform a kernel triggered VT switch for suspend/resume */
-
-static int disable_vt_switch;
-
-int vt_move_to_console(unsigned int vt, int alloc)
-{
-       int prev;
-
-       acquire_console_sem();
-       /* Graphics mode - up to X */
-       if (disable_vt_switch) {
-               release_console_sem();
-               return 0;
-       }
-       prev = fg_console;
-
-       if (alloc && vc_allocate(vt)) {
-               /* we can't have a free VC for now. Too bad,
-                * we don't want to mess the screen for now. */
-               release_console_sem();
-               return -ENOSPC;
-       }
-
-       if (set_console(vt)) {
-               /*
-                * We're unable to switch to the SUSPEND_CONSOLE.
-                * Let the calling function know so it can decide
-                * what to do.
-                */
-               release_console_sem();
-               return -EIO;
-       }
-       release_console_sem();
-       tty_lock();
-       if (vt_waitactive(vt + 1)) {
-               pr_debug("Suspend: Can't switch VCs.");
-               tty_unlock();
-               return -EINTR;
-       }
-       tty_unlock();
-       return prev;
-}
-
-/*
- * Normally during a suspend, we allocate a new console and switch to it.
- * When we resume, we switch back to the original console.  This switch
- * can be slow, so on systems where the framebuffer can handle restoration
- * of video registers anyways, there's little point in doing the console
- * switch.  This function allows you to disable it by passing it '0'.
- */
-void pm_set_vt_switch(int do_switch)
-{
-       acquire_console_sem();
-       disable_vt_switch = !do_switch;
-       release_console_sem();
-}
-EXPORT_SYMBOL(pm_set_vt_switch);
index a44611652282c6c173e70b861910d4bee1610db4..d68d3aa1814b4ac635017e98cebd9625b0e7b40a 100644 (file)
@@ -616,13 +616,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "cmt_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        if (resource_size(res) == 6) {
index ef7a5be8a09f5a36bb1ed545fccf64e2fa7e7f89..40630cb9823707423c84e2459b812165786c5a15 100644 (file)
@@ -287,13 +287,9 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
index de715901b82a28a09f8160dd1b62f17a25247a51..36aba9923060f5dfbd02d250a1de675e274e7695 100644 (file)
@@ -393,13 +393,9 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "tmu_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
index 88ee01510ec0132d894763dc9ac967b101ea0439..76141262ea1d41b256ad4e70b4af5e5b1bc34f28 100644 (file)
@@ -1832,7 +1832,7 @@ static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
                return -ENODEV;
 
        ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
-       if (!intr)
+       if (!ino)
                return -ENODEV;
 
        if (intr_len != ino_len)
index 2e992bc8015b7bd63bf0c5b4b878b8da1bfa69c4..8a515baa38f7c2d554e786bb33ab6979d770bc00 100644 (file)
@@ -286,7 +286,7 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
        if (initial)
                asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"       /* rep xcryptcbc */
                              : "+S" (input), "+D" (output), "+a" (iv)
-                             : "d" (control_word), "b" (key), "c" (count));
+                             : "d" (control_word), "b" (key), "c" (initial));
 
        asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"       /* rep xcryptcbc */
                      : "+S" (input), "+D" (output), "+a" (iv)
index 9dcb17d51aee737bcbb4ac478807c04311588d6c..84eb607d6c031b4275e834604d4c0c0729fa8502 100644 (file)
@@ -577,17 +577,11 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
        return ret;
 }
 
-static int ar_context_add_page(struct ar_context *ctx)
+static void ar_context_link_page(struct ar_context *ctx,
+                                struct ar_buffer *ab, dma_addr_t ab_bus)
 {
-       struct device *dev = ctx->ohci->card.device;
-       struct ar_buffer *ab;
-       dma_addr_t uninitialized_var(ab_bus);
        size_t offset;
 
-       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
-       if (ab == NULL)
-               return -ENOMEM;
-
        ab->next = NULL;
        memset(&ab->descriptor, 0, sizeof(ab->descriptor));
        ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
@@ -606,6 +600,19 @@ static int ar_context_add_page(struct ar_context *ctx)
 
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
        flush_writes(ctx->ohci);
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+       struct device *dev = ctx->ohci->card.device;
+       struct ar_buffer *ab;
+       dma_addr_t uninitialized_var(ab_bus);
+
+       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
+       if (ab == NULL)
+               return -ENOMEM;
+
+       ar_context_link_page(ctx, ab, ab_bus);
 
        return 0;
 }
@@ -730,16 +737,17 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
 static void ar_context_tasklet(unsigned long data)
 {
        struct ar_context *ctx = (struct ar_context *)data;
-       struct fw_ohci *ohci = ctx->ohci;
        struct ar_buffer *ab;
        struct descriptor *d;
        void *buffer, *end;
+       __le16 res_count;
 
        ab = ctx->current_buffer;
        d = &ab->descriptor;
 
-       if (d->res_count == 0) {
-               size_t size, rest, offset;
+       res_count = ACCESS_ONCE(d->res_count);
+       if (res_count == 0) {
+               size_t size, size2, rest, pktsize, size3, offset;
                dma_addr_t start_bus;
                void *start;
 
@@ -750,29 +758,63 @@ static void ar_context_tasklet(unsigned long data)
                 */
 
                offset = offsetof(struct ar_buffer, data);
-               start = buffer = ab;
+               start = ab;
                start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+               buffer = ab->data;
 
                ab = ab->next;
                d = &ab->descriptor;
-               size = buffer + PAGE_SIZE - ctx->pointer;
+               size = start + PAGE_SIZE - ctx->pointer;
+               /* valid buffer data in the next page */
                rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+               /* what actually fits in this page */
+               size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
                memmove(buffer, ctx->pointer, size);
-               memcpy(buffer + size, ab->data, rest);
-               ctx->current_buffer = ab;
-               ctx->pointer = (void *) ab->data + rest;
-               end = buffer + size + rest;
+               memcpy(buffer + size, ab->data, size2);
+
+               while (size > 0) {
+                       void *next = handle_ar_packet(ctx, buffer);
+                       pktsize = next - buffer;
+                       if (pktsize >= size) {
+                               /*
+                                * We have handled all the data that was
+                                * originally in this page, so we can now
+                                * continue in the next page.
+                                */
+                               buffer = next;
+                               break;
+                       }
+                       /* move the next packet to the start of the buffer */
+                       memmove(buffer, next, size + size2 - pktsize);
+                       size -= pktsize;
+                       /* fill up this page again */
+                       size3 = min(rest - size2,
+                                   (size_t)PAGE_SIZE - offset - size - size2);
+                       memcpy(buffer + size + size2,
+                              (void *) ab->data + size2, size3);
+                       size2 += size3;
+               }
 
-               while (buffer < end)
-                       buffer = handle_ar_packet(ctx, buffer);
+               if (rest > 0) {
+                       /* handle the packets that are fully in the next page */
+                       buffer = (void *) ab->data +
+                                       (buffer - (start + offset + size));
+                       end = (void *) ab->data + rest;
+
+                       while (buffer < end)
+                               buffer = handle_ar_packet(ctx, buffer);
 
-               dma_free_coherent(ohci->card.device, PAGE_SIZE,
-                                 start, start_bus);
-               ar_context_add_page(ctx);
+                       ctx->current_buffer = ab;
+                       ctx->pointer = end;
+
+                       ar_context_link_page(ctx, start, start_bus);
+               } else {
+                       ctx->pointer = start + PAGE_SIZE;
+               }
        } else {
                buffer = ctx->pointer;
                ctx->pointer = end =
-                       (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+                       (void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
 
                while (buffer < end)
                        buffer = handle_ar_packet(ctx, buffer);
index bfae4b309791103e48b2bb704300d1cd84da9750..afa576a75a8ed443273d4722c03edc2bb8c31720 100644 (file)
@@ -1468,7 +1468,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
 
 /* SCSI stack integration */
 
-static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done)
 {
        struct sbp2_logical_unit *lu = cmd->device->hostdata;
        struct fw_device *device = target_device(lu->tgt);
@@ -1534,6 +1534,8 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
        return retval;
 }
 
+static DEF_SCSI_QCMD(sbp2_scsi_queuecommand)
+
 static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
 {
        struct sbp2_logical_unit *lu = sdev->hostdata;
index dcbeb98f195a7addf665e0134af9ee799280a279..f7af91cb273d58232d41c68b712b2d6d4404671c 100644 (file)
@@ -276,7 +276,7 @@ static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
        struct drm_crtc *tmp;
        int crtc_mask = 1;
 
-       WARN(!crtc, "checking null crtc?");
+       WARN(!crtc, "checking null crtc?\n");
 
        dev = crtc->dev;
 
index c1a26217a5305ee65a07b85fa77e4c15db77436b..a245d17165ae28b4eab835d612c92e008e3ab5d4 100644 (file)
@@ -240,7 +240,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
                        .addr   = DDC_ADDR,
                        .flags  = I2C_M_RD,
                        .len    = len,
-                       .buf    = buf + start,
+                       .buf    = buf,
                }
        };
 
@@ -253,7 +253,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
 static u8 *
 drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
-       int i, j = 0;
+       int i, j = 0, valid_extensions = 0;
        u8 *block, *new;
 
        if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
@@ -280,14 +280,28 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 
        for (j = 1; j <= block[0x7e]; j++) {
                for (i = 0; i < 4; i++) {
-                       if (drm_do_probe_ddc_edid(adapter, block, j,
-                                                 EDID_LENGTH))
+                       if (drm_do_probe_ddc_edid(adapter,
+                                 block + (valid_extensions + 1) * EDID_LENGTH,
+                                 j, EDID_LENGTH))
                                goto out;
-                       if (drm_edid_block_valid(block + j * EDID_LENGTH))
+                       if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) {
+                               valid_extensions++;
                                break;
+                       }
                }
                if (i == 4)
-                       goto carp;
+                       dev_warn(connector->dev->dev,
+                        "%s: Ignoring invalid EDID block %d.\n",
+                        drm_get_connector_name(connector), j);
+       }
+
+       if (valid_extensions != block[0x7e]) {
+               block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
+               block[0x7e] = valid_extensions;
+               new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
+               if (!new)
+                       goto out;
+               block = new;
        }
 
        return block;
index b744dad5c237f5371d571d13dc35d46a2fc95e2c..a39794bac04b4a57a8531c5ed38cccf081aa8ef9 100644 (file)
@@ -37,7 +37,6 @@
 #include "drmP.h"
 #include <linux/poll.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 /* from BKL pushdown: note that nothing else serializes idr_find() */
 DEFINE_MUTEX(drm_global_mutex);
index 3467dd420760fa51084a2ba00d097b90d6c214a2..f737960712e607c448eabc83d57e6d0557269f16 100644 (file)
@@ -44,7 +44,7 @@ unsigned int i915_fbpercrtc = 0;
 module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 
 unsigned int i915_powersave = 1;
-module_param_named(powersave, i915_powersave, int, 0400);
+module_param_named(powersave, i915_powersave, int, 0600);
 
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
@@ -150,7 +150,8 @@ static const struct intel_device_info intel_ironlake_d_info = {
 
 static const struct intel_device_info intel_ironlake_m_info = {
        .gen = 5, .is_mobile = 1,
-       .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+       .need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1,
+       .has_fbc = 0, /* disabled due to buggy hardware */
        .has_bsd_ring = 1,
 };
 
index 2c2c19b6285ecf331edbac9c53e0bdd44b2093ad..409826da3099dcb594473685bdf4b5f2e78183c9 100644 (file)
@@ -1045,6 +1045,8 @@ void i915_gem_clflush_object(struct drm_gem_object *obj);
 int i915_gem_object_set_domain(struct drm_gem_object *obj,
                               uint32_t read_domains,
                               uint32_t write_domain);
+int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+                             bool interruptible);
 int i915_gem_init_ringbuffer(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 int i915_gem_do_init(struct drm_device *dev, unsigned long start,
@@ -1321,6 +1323,7 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
 
 #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
 #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
+#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
index 8eb8453208b5ce491e77c1c06c77c1c0a2da41bc..17b1cba3b5f11c281eedc13c5adaa5a98ac4eef8 100644 (file)
@@ -547,6 +547,19 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_object *obj_priv;
        int ret = 0;
 
+       if (args->size == 0)
+               return 0;
+
+       if (!access_ok(VERIFY_WRITE,
+                      (char __user *)(uintptr_t)args->data_ptr,
+                      args->size))
+               return -EFAULT;
+
+       ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
+                                      args->size);
+       if (ret)
+               return -EFAULT;
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
@@ -564,23 +577,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
                goto out;
        }
 
-       if (args->size == 0)
-               goto out;
-
-       if (!access_ok(VERIFY_WRITE,
-                      (char __user *)(uintptr_t)args->data_ptr,
-                      args->size)) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
-                                      args->size);
-       if (ret) {
-               ret = -EFAULT;
-               goto out;
-       }
-
        ret = i915_gem_object_get_pages_or_evict(obj);
        if (ret)
                goto out;
@@ -981,7 +977,20 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_pwrite *args = data;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
-       int ret = 0;
+       int ret;
+
+       if (args->size == 0)
+               return 0;
+
+       if (!access_ok(VERIFY_READ,
+                      (char __user *)(uintptr_t)args->data_ptr,
+                      args->size))
+               return -EFAULT;
+
+       ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
+                                     args->size);
+       if (ret)
+               return -EFAULT;
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
@@ -994,30 +1003,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
        }
        obj_priv = to_intel_bo(obj);
 
-
        /* Bounds check destination. */
        if (args->offset > obj->size || args->size > obj->size - args->offset) {
                ret = -EINVAL;
                goto out;
        }
 
-       if (args->size == 0)
-               goto out;
-
-       if (!access_ok(VERIFY_READ,
-                      (char __user *)(uintptr_t)args->data_ptr,
-                      args->size)) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
-                                     args->size);
-       if (ret) {
-               ret = -EFAULT;
-               goto out;
-       }
-
        /* We can only do the GTT pwrite on untiled buffers, as otherwise
         * it would end up going through the fenced access, and we'll get
         * different detiling behavior between reading and writing.
@@ -2172,7 +2163,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
 static int i915_ring_idle(struct drm_device *dev,
                          struct intel_ring_buffer *ring)
 {
-       if (list_empty(&ring->gpu_write_list))
+       if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list))
                return 0;
 
        i915_gem_flush_ring(dev, NULL, ring,
@@ -2190,9 +2181,7 @@ i915_gpu_idle(struct drm_device *dev)
        int ret;
 
        lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
-                      list_empty(&dev_priv->render_ring.active_list) &&
-                      list_empty(&dev_priv->bsd_ring.active_list) &&
-                      list_empty(&dev_priv->blt_ring.active_list));
+                      list_empty(&dev_priv->mm.active_list));
        if (lists_empty)
                return 0;
 
@@ -2909,6 +2898,20 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
        return 0;
 }
 
+int
+i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+                         bool interruptible)
+{
+       if (!obj->active)
+               return 0;
+
+       if (obj->base.write_domain & I915_GEM_GPU_DOMAINS)
+               i915_gem_flush_ring(obj->base.dev, NULL, obj->ring,
+                                   0, obj->base.write_domain);
+
+       return i915_gem_object_wait_rendering(&obj->base, interruptible);
+}
+
 /**
  * Moves a single object to the CPU read, and possibly write domain.
  *
@@ -3108,7 +3111,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
         * write domain
         */
        if (obj->write_domain &&
-           obj->write_domain != obj->pending_read_domains) {
+           (obj->write_domain != obj->pending_read_domains ||
+            obj_priv->ring != ring)) {
                flush_domains |= obj->write_domain;
                invalidate_domains |=
                        obj->pending_read_domains & ~obj->write_domain;
@@ -3497,6 +3501,52 @@ i915_gem_execbuffer_pin(struct drm_device *dev,
        return 0;
 }
 
+static int
+i915_gem_execbuffer_move_to_gpu(struct drm_device *dev,
+                               struct drm_file *file,
+                               struct intel_ring_buffer *ring,
+                               struct drm_gem_object **objects,
+                               int count)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret, i;
+
+       /* Zero the global flush/invalidate flags. These
+        * will be modified as new domains are computed
+        * for each object
+        */
+       dev->invalidate_domains = 0;
+       dev->flush_domains = 0;
+       dev_priv->mm.flush_rings = 0;
+       for (i = 0; i < count; i++)
+               i915_gem_object_set_to_gpu_domain(objects[i], ring);
+
+       if (dev->invalidate_domains | dev->flush_domains) {
+#if WATCH_EXEC
+               DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
+                         __func__,
+                        dev->invalidate_domains,
+                        dev->flush_domains);
+#endif
+               i915_gem_flush(dev, file,
+                              dev->invalidate_domains,
+                              dev->flush_domains,
+                              dev_priv->mm.flush_rings);
+       }
+
+       for (i = 0; i < count; i++) {
+               struct drm_i915_gem_object *obj = to_intel_bo(objects[i]);
+               /* XXX replace with semaphores */
+               if (obj->ring && ring != obj->ring) {
+                       ret = i915_gem_object_wait_rendering(&obj->base, true);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
 /* Throttle our rendering by waiting until the ring has completed our requests
  * emitted over 20 msec ago.
  *
@@ -3757,33 +3807,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto err;
        }
 
-       /* Zero the global flush/invalidate flags. These
-        * will be modified as new domains are computed
-        * for each object
-        */
-       dev->invalidate_domains = 0;
-       dev->flush_domains = 0;
-       dev_priv->mm.flush_rings = 0;
-
-       for (i = 0; i < args->buffer_count; i++) {
-               struct drm_gem_object *obj = object_list[i];
-
-               /* Compute new gpu domains and update invalidate/flush */
-               i915_gem_object_set_to_gpu_domain(obj, ring);
-       }
-
-       if (dev->invalidate_domains | dev->flush_domains) {
-#if WATCH_EXEC
-               DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
-                         __func__,
-                        dev->invalidate_domains,
-                        dev->flush_domains);
-#endif
-               i915_gem_flush(dev, file,
-                              dev->invalidate_domains,
-                              dev->flush_domains,
-                              dev_priv->mm.flush_rings);
-       }
+       ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring,
+                                             object_list, args->buffer_count);
+       if (ret)
+               goto err;
 
        for (i = 0; i < args->buffer_count; i++) {
                struct drm_gem_object *obj = object_list[i];
@@ -4043,8 +4070,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
                        alignment = i915_gem_get_gtt_alignment(obj);
                if (obj_priv->gtt_offset & (alignment - 1)) {
                        WARN(obj_priv->pin_count,
-                            "bo is already pinned with incorrect alignment:"
-                            " offset=%x, req.alignment=%x\n",
+                            "bo is already pinned with incorrect alignment: offset=%x, req.alignment=%x\n",
                             obj_priv->gtt_offset, alignment);
                        ret = i915_gem_object_unbind(obj);
                        if (ret)
@@ -4856,17 +4882,24 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
                     struct drm_file *file_priv)
 {
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-       void *obj_addr;
-       int ret;
-       char __user *user_data;
+       void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset;
+       char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
 
-       user_data = (char __user *) (uintptr_t) args->data_ptr;
-       obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
+       DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size);
 
-       DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size);
-       ret = copy_from_user(obj_addr, user_data, args->size);
-       if (ret)
-               return -EFAULT;
+       if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
+               unsigned long unwritten;
+
+               /* The physical object once assigned is fixed for the lifetime
+                * of the obj, so we can safely drop the lock and continue
+                * to access vaddr.
+                */
+               mutex_unlock(&dev->struct_mutex);
+               unwritten = copy_from_user(vaddr, user_data, args->size);
+               mutex_lock(&dev->struct_mutex);
+               if (unwritten)
+                       return -EFAULT;
+       }
 
        drm_agp_chipset_flush(dev);
        return 0;
@@ -4900,9 +4933,7 @@ i915_gpu_is_active(struct drm_device *dev)
        int lists_empty;
 
        lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
-                     list_empty(&dev_priv->render_ring.active_list) &&
-                     list_empty(&dev_priv->bsd_ring.active_list) &&
-                     list_empty(&dev_priv->blt_ring.active_list);
+                     list_empty(&dev_priv->mm.active_list);
 
        return !lists_empty;
 }
index 43a4013f53fa24e212849af68940384b777d30a1..d8ae7d1d0cc671d9d59393fd2d11ddff317b322f 100644 (file)
@@ -165,9 +165,7 @@ i915_gem_evict_everything(struct drm_device *dev)
 
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
-                      list_empty(&dev_priv->render_ring.active_list) &&
-                      list_empty(&dev_priv->bsd_ring.active_list) &&
-                      list_empty(&dev_priv->blt_ring.active_list));
+                      list_empty(&dev_priv->mm.active_list));
        if (lists_empty)
                return -ENOSPC;
 
@@ -184,9 +182,7 @@ i915_gem_evict_everything(struct drm_device *dev)
 
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
-                      list_empty(&dev_priv->render_ring.active_list) &&
-                      list_empty(&dev_priv->bsd_ring.active_list) &&
-                      list_empty(&dev_priv->blt_ring.active_list));
+                      list_empty(&dev_priv->mm.active_list));
        BUG_ON(!lists_empty);
 
        return 0;
index 989c19d2d959b6bc6c54a0e4bf31d9aee093efe6..454c064f8ef7f8d0daffe0ed40394354b152ee55 100644 (file)
@@ -862,8 +862,10 @@ int i915_restore_state(struct drm_device *dev)
        /* Clock gating state */
        intel_init_clock_gating(dev);
 
-       if (HAS_PCH_SPLIT(dev))
+       if (HAS_PCH_SPLIT(dev)) {
                ironlake_enable_drps(dev);
+               intel_init_emon(dev);
+       }
 
        /* Cache mode state */
        I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
index c55c77043357cb0243a4b368a1e6d63b7a4af398..8df574316063fb751d683b4b9d5c0d59b82f42f1 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+/* Here's the desired hotplug mode */
+#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |               \
+                          ADPA_CRT_HOTPLUG_WARMUP_10MS |               \
+                          ADPA_CRT_HOTPLUG_SAMPLE_4S |                 \
+                          ADPA_CRT_HOTPLUG_VOLTAGE_50 |                \
+                          ADPA_CRT_HOTPLUG_VOLREF_325MV |              \
+                          ADPA_CRT_HOTPLUG_ENABLE)
+
+struct intel_crt {
+       struct intel_encoder base;
+       bool force_hotplug_required;
+};
+
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
+{
+       return container_of(intel_attached_encoder(connector),
+                           struct intel_crt, base);
+}
+
 static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
@@ -129,7 +148,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
                           dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
        }
 
-       adpa = 0;
+       adpa = ADPA_HOTPLUG_BITS;
        if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
                adpa |= ADPA_HSYNC_ACTIVE_HIGH;
        if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -157,53 +176,44 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
 static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
+       struct intel_crt *crt = intel_attached_crt(connector);
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 adpa, temp;
+       u32 adpa;
        bool ret;
-       bool turn_off_dac = false;
 
-       temp = adpa = I915_READ(PCH_ADPA);
+       /* The first time through, trigger an explicit detection cycle */
+       if (crt->force_hotplug_required) {
+               bool turn_off_dac = HAS_PCH_SPLIT(dev);
+               u32 save_adpa;
 
-       if (HAS_PCH_SPLIT(dev))
-               turn_off_dac = true;
-
-       adpa &= ~ADPA_CRT_HOTPLUG_MASK;
-       if (turn_off_dac)
-               adpa &= ~ADPA_DAC_ENABLE;
-
-       /* disable HPD first */
-       I915_WRITE(PCH_ADPA, adpa);
-       (void)I915_READ(PCH_ADPA);
-
-       adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
-                       ADPA_CRT_HOTPLUG_WARMUP_10MS |
-                       ADPA_CRT_HOTPLUG_SAMPLE_4S |
-                       ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
-                       ADPA_CRT_HOTPLUG_VOLREF_325MV |
-                       ADPA_CRT_HOTPLUG_ENABLE |
-                       ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
-
-       DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
-       I915_WRITE(PCH_ADPA, adpa);
-
-       if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
-                    1000))
-               DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
-
-       if (turn_off_dac) {
-               /* Make sure hotplug is enabled */
-               I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
-               (void)I915_READ(PCH_ADPA);
+               crt->force_hotplug_required = 0;
+
+               save_adpa = adpa = I915_READ(PCH_ADPA);
+               DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
+
+               adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+               if (turn_off_dac)
+                       adpa &= ~ADPA_DAC_ENABLE;
+
+               I915_WRITE(PCH_ADPA, adpa);
+
+               if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
+                            1000))
+                       DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
+
+               if (turn_off_dac) {
+                       I915_WRITE(PCH_ADPA, save_adpa);
+                       POSTING_READ(PCH_ADPA);
+               }
        }
 
        /* Check the status to see if both blue and green are on now */
        adpa = I915_READ(PCH_ADPA);
-       adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
-       if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
-               (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
+       if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
                ret = true;
        else
                ret = false;
+       DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
 
        return ret;
 }
@@ -277,13 +287,12 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
        return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
 }
 
-static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
+static bool intel_crt_detect_ddc(struct intel_crt *crt)
 {
-       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
-       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
 
        /* CRT should always be at 0, but check anyway */
-       if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
+       if (crt->base.type != INTEL_OUTPUT_ANALOG)
                return false;
 
        if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
@@ -291,7 +300,7 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
                return true;
        }
 
-       if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
+       if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
                DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
                return true;
        }
@@ -300,9 +309,9 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
 }
 
 static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
+intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
 {
-       struct drm_encoder *encoder = &intel_encoder->base;
+       struct drm_encoder *encoder = &crt->base.base;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -434,7 +443,7 @@ static enum drm_connector_status
 intel_crt_detect(struct drm_connector *connector, bool force)
 {
        struct drm_device *dev = connector->dev;
-       struct intel_encoder *encoder = intel_attached_encoder(connector);
+       struct intel_crt *crt = intel_attached_crt(connector);
        struct drm_crtc *crtc;
        int dpms_mode;
        enum drm_connector_status status;
@@ -443,28 +452,31 @@ intel_crt_detect(struct drm_connector *connector, bool force)
                if (intel_crt_detect_hotplug(connector)) {
                        DRM_DEBUG_KMS("CRT detected via hotplug\n");
                        return connector_status_connected;
-               } else
+               } else {
+                       DRM_DEBUG_KMS("CRT not detected via hotplug\n");
                        return connector_status_disconnected;
+               }
        }
 
-       if (intel_crt_detect_ddc(&encoder->base))
+       if (intel_crt_detect_ddc(crt))
                return connector_status_connected;
 
        if (!force)
                return connector->status;
 
        /* for pre-945g platforms use load detect */
-       if (encoder->base.crtc && encoder->base.crtc->enabled) {
-               status = intel_crt_load_detect(encoder->base.crtc, encoder);
+       crtc = crt->base.base.crtc;
+       if (crtc && crtc->enabled) {
+               status = intel_crt_load_detect(crtc, crt);
        } else {
-               crtc = intel_get_load_detect_pipe(encoder, connector,
+               crtc = intel_get_load_detect_pipe(&crt->base, connector,
                                                  NULL, &dpms_mode);
                if (crtc) {
-                       if (intel_crt_detect_ddc(&encoder->base))
+                       if (intel_crt_detect_ddc(crt))
                                status = connector_status_connected;
                        else
-                               status = intel_crt_load_detect(crtc, encoder);
-                       intel_release_load_detect_pipe(encoder,
+                               status = intel_crt_load_detect(crtc, crt);
+                       intel_release_load_detect_pipe(&crt->base,
                                                       connector, dpms_mode);
                } else
                        status = connector_status_unknown;
@@ -536,17 +548,17 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
 void intel_crt_init(struct drm_device *dev)
 {
        struct drm_connector *connector;
-       struct intel_encoder *intel_encoder;
+       struct intel_crt *crt;
        struct intel_connector *intel_connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
-       if (!intel_encoder)
+       crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
+       if (!crt)
                return;
 
        intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
        if (!intel_connector) {
-               kfree(intel_encoder);
+               kfree(crt);
                return;
        }
 
@@ -554,20 +566,20 @@ void intel_crt_init(struct drm_device *dev)
        drm_connector_init(dev, &intel_connector->base,
                           &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
-       drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
+       drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
                         DRM_MODE_ENCODER_DAC);
 
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
+       intel_connector_attach_encoder(intel_connector, &crt->base);
 
-       intel_encoder->type = INTEL_OUTPUT_ANALOG;
-       intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-                                  (1 << INTEL_ANALOG_CLONE_BIT) |
-                                  (1 << INTEL_SDVO_LVDS_CLONE_BIT);
-       intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+       crt->base.type = INTEL_OUTPUT_ANALOG;
+       crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
+                               1 << INTEL_ANALOG_CLONE_BIT |
+                               1 << INTEL_SDVO_LVDS_CLONE_BIT);
+       crt->base.crtc_mask = (1 << 0) | (1 << 1);
        connector->interlace_allowed = 1;
        connector->doublescan_allowed = 0;
 
-       drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
+       drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
        drm_sysfs_connector_add(connector);
@@ -577,5 +589,22 @@ void intel_crt_init(struct drm_device *dev)
        else
                connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 
+       /*
+        * Configure the automatic hotplug detection stuff
+        */
+       crt->force_hotplug_required = 0;
+       if (HAS_PCH_SPLIT(dev)) {
+               u32 adpa;
+
+               adpa = I915_READ(PCH_ADPA);
+               adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+               adpa |= ADPA_HOTPLUG_BITS;
+               I915_WRITE(PCH_ADPA, adpa);
+               POSTING_READ(PCH_ADPA);
+
+               DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
+               crt->force_hotplug_required = 1;
+       }
+
        dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
 }
index 990f065374b22eacfc2fcddd68c873a5081ee773..bee24b1a58e86b5dc1d1c038f8f1a653848bec97 100644 (file)
@@ -1611,6 +1611,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 
                wait_event(dev_priv->pending_flip_queue,
                           atomic_read(&obj_priv->pending_flip) == 0);
+
+               /* Big Hammer, we also need to ensure that any pending
+                * MI_WAIT_FOR_EVENT inside a user batch buffer on the
+                * current scanout is retired before unpinning the old
+                * framebuffer.
+                */
+               ret = i915_gem_object_flush_gpu(obj_priv, false);
+               if (ret) {
+                       i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
+               }
        }
 
        ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
@@ -1681,6 +1693,37 @@ static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
        udelay(500);
 }
 
+static void intel_fdi_normal_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp;
+
+       /* enable normal train */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE;
+       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       if (HAS_PCH_CPT(dev)) {
+               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE;
+       }
+       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+       /* wait one idle pattern time */
+       POSTING_READ(reg);
+       udelay(1000);
+}
+
 /* The FDI link training functions for ILK/Ibexpeak. */
 static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 {
@@ -1767,27 +1810,6 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 
        DRM_DEBUG_KMS("FDI train done\n");
 
-       /* enable normal train */
-       reg = FDI_TX_CTL(pipe);
-       temp = I915_READ(reg);
-       temp &= ~FDI_LINK_TRAIN_NONE;
-       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
-       I915_WRITE(reg, temp);
-
-       reg = FDI_RX_CTL(pipe);
-       temp = I915_READ(reg);
-       if (HAS_PCH_CPT(dev)) {
-               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-       } else {
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_NONE;
-       }
-       I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-
-       /* wait one idle pattern time */
-       POSTING_READ(reg);
-       udelay(1000);
 }
 
 static const int const snb_b_fdi_train_param [] = {
@@ -2090,6 +2112,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
        I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
 
+       intel_fdi_normal_train(crtc);
+
        /* For PCH DP, enable TRANS_DP_CTL */
        if (HAS_PCH_CPT(dev) &&
            intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
@@ -2200,9 +2224,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        udelay(100);
 
        /* Ironlake workaround, disable clock pointer after downing FDI */
-       I915_WRITE(FDI_RX_CHICKEN(pipe),
-                  I915_READ(FDI_RX_CHICKEN(pipe) &
-                            ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+       if (HAS_PCH_IBX(dev))
+               I915_WRITE(FDI_RX_CHICKEN(pipe),
+                          I915_READ(FDI_RX_CHICKEN(pipe) &
+                                    ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
 
        /* still set train pattern 1 */
        reg = FDI_TX_CTL(pipe);
@@ -5581,20 +5606,19 @@ void ironlake_enable_drps(struct drm_device *dev)
        fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
        fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
                MEMMODE_FSTART_SHIFT;
-       fstart = fmax;
 
        vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
                PXVFREQ_PX_SHIFT;
 
-       dev_priv->fmax = fstart; /* IPS callback will increase this */
+       dev_priv->fmax = fmax; /* IPS callback will increase this */
        dev_priv->fstart = fstart;
 
-       dev_priv->max_delay = fmax;
+       dev_priv->max_delay = fstart;
        dev_priv->min_delay = fmin;
        dev_priv->cur_delay = fstart;
 
-       DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin,
-                        fstart);
+       DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
+                        fmax, fmin, fstart);
 
        I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
 
index 891f4f1d63b11570b7ede1c4e5e49814f2dcb5d0..c8e005553310a5eaeae98e4cb8ed349b4b204164 100644 (file)
@@ -1517,7 +1517,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
                        status = connector_status_connected;
        }
 
-       return bit;
+       return status;
 }
 
 /**
index 9af9f86a8765c82833706aa1320ca9baed3fa416..21551fe745416abb4597341b18d647f2529e85ce 100644 (file)
@@ -296,6 +296,7 @@ extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
 extern void intel_init_clock_gating(struct drm_device *dev);
 extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
+extern void intel_init_emon(struct drm_device *dev);
 
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
                                      struct drm_gem_object *obj,
index 2be4f728ed0c7b250550613cc93259462db9735a..3dba086e7eea012947c410738e208a9ef39bfa9e 100644 (file)
@@ -160,7 +160,7 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
        };
        struct intel_gpio *gpio;
 
-       if (pin < 1 || pin > 7)
+       if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
                return NULL;
 
        gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
@@ -172,7 +172,8 @@ intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
                gpio->reg += PCH_GPIOA - GPIOA;
        gpio->dev_priv = dev_priv;
 
-       snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+       snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
+                "i915 GPIO%c", "?BACDE?F"[pin]);
        gpio->adapter.owner = THIS_MODULE;
        gpio->adapter.algo_data = &gpio->algo;
        gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
@@ -349,7 +350,7 @@ int intel_setup_gmbus(struct drm_device *dev)
                "panel",
                "dpc",
                "dpb",
-               "reserved"
+               "reserved",
                "dpd",
        };
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -366,8 +367,8 @@ int intel_setup_gmbus(struct drm_device *dev)
                bus->adapter.owner = THIS_MODULE;
                bus->adapter.class = I2C_CLASS_DDC;
                snprintf(bus->adapter.name,
-                        I2C_NAME_SIZE,
-                        "gmbus %s",
+                        sizeof(bus->adapter.name),
+                        "i915 gmbus %s",
                         names[i]);
 
                bus->adapter.dev.parent = &dev->pdev->dev;
index f1a649990ea9e61d5f7ff6f8b15e127d6fcc2f17..4324a326f98ee28f4d67936b7a4789556344c4fb 100644 (file)
@@ -481,11 +481,8 @@ static int intel_lvds_get_modes(struct drm_connector *connector)
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode;
 
-       if (intel_lvds->edid) {
-               drm_mode_connector_update_edid_property(connector,
-                                                       intel_lvds->edid);
+       if (intel_lvds->edid)
                return drm_add_edid_modes(connector, intel_lvds->edid);
-       }
 
        mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
        if (mode == 0)
@@ -939,7 +936,16 @@ void intel_lvds_init(struct drm_device *dev)
         */
        intel_lvds->edid = drm_get_edid(connector,
                                        &dev_priv->gmbus[pin].adapter);
-
+       if (intel_lvds->edid) {
+               if (drm_add_edid_modes(connector,
+                                      intel_lvds->edid)) {
+                       drm_mode_connector_update_edid_property(connector,
+                                                               intel_lvds->edid);
+               } else {
+                       kfree(intel_lvds->edid);
+                       intel_lvds->edid = NULL;
+               }
+       }
        if (!intel_lvds->edid) {
                /* Didn't get an EDID, so
                 * Set wide sync ranges so we get all modes
index 917c7dc3cd6b33ee151ad2e960743fe35016cec0..9b0d9a867aeada1f1c9d601e21f76e2d9e4e7351 100644 (file)
@@ -512,6 +512,6 @@ int intel_opregion_setup(struct drm_device *dev)
        return 0;
 
 err_out:
-       iounmap(opregion->header);
+       iounmap(base);
        return err;
 }
index afb96d25219afe473b116802f30616c0edb1cf86..02ff0a481f470cea6e3f4f109805e07fbd84725e 100644 (file)
@@ -946,7 +946,9 @@ static int check_overlay_src(struct drm_device *dev,
 {
        int uv_hscale = uv_hsubsampling(rec->flags);
        int uv_vscale = uv_vsubsampling(rec->flags);
-       u32 stride_mask, depth, tmp;
+       u32 stride_mask;
+       int depth;
+       u32 tmp;
 
        /* check src dimensions */
        if (IS_845G(dev) || IS_I830(dev)) {
index 09f2dc353ae239f0d2a6f86a5940c1d7b27656e4..b83306f9244b6c887d84976b4f1801449445941a 100644 (file)
@@ -177,7 +177,7 @@ static int init_ring_common(struct drm_device *dev,
 
        I915_WRITE_CTL(ring,
                        ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
-                       | RING_NO_REPORT | RING_VALID);
+                       | RING_REPORT_64K | RING_VALID);
 
        head = I915_READ_HEAD(ring) & HEAD_ADDR;
        /* If the head is still not zero, the ring is dead */
@@ -654,6 +654,10 @@ void intel_cleanup_ring_buffer(struct drm_device *dev,
        i915_gem_object_unpin(ring->gem_object);
        drm_gem_object_unreference(ring->gem_object);
        ring->gem_object = NULL;
+
+       if (ring->cleanup)
+               ring->cleanup(ring);
+
        cleanup_status_page(dev, ring);
 }
 
@@ -688,6 +692,17 @@ int intel_wait_ring_buffer(struct drm_device *dev,
 {
        unsigned long end;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 head;
+
+       head = intel_read_status_page(ring, 4);
+       if (head) {
+               ring->head = head & HEAD_ADDR;
+               ring->space = ring->head - (ring->tail + 8);
+               if (ring->space < 0)
+                       ring->space += ring->size;
+               if (ring->space >= n)
+                       return 0;
+       }
 
        trace_i915_ring_wait_begin (dev);
        end = jiffies + 3 * HZ;
@@ -854,19 +869,125 @@ blt_ring_put_user_irq(struct drm_device *dev,
        /* do nothing */
 }
 
+
+/* Workaround for some stepping of SNB,
+ * each time when BLT engine ring tail moved,
+ * the first command in the ring to be parsed
+ * should be MI_BATCH_BUFFER_START
+ */
+#define NEED_BLT_WORKAROUND(dev) \
+       (IS_GEN6(dev) && (dev->pdev->revision < 8))
+
+static inline struct drm_i915_gem_object *
+to_blt_workaround(struct intel_ring_buffer *ring)
+{
+       return ring->private;
+}
+
+static int blt_ring_init(struct drm_device *dev,
+                        struct intel_ring_buffer *ring)
+{
+       if (NEED_BLT_WORKAROUND(dev)) {
+               struct drm_i915_gem_object *obj;
+               u32 __iomem *ptr;
+               int ret;
+
+               obj = to_intel_bo(i915_gem_alloc_object(dev, 4096));
+               if (obj == NULL)
+                       return -ENOMEM;
+
+               ret = i915_gem_object_pin(&obj->base, 4096);
+               if (ret) {
+                       drm_gem_object_unreference(&obj->base);
+                       return ret;
+               }
+
+               ptr = kmap(obj->pages[0]);
+               iowrite32(MI_BATCH_BUFFER_END, ptr);
+               iowrite32(MI_NOOP, ptr+1);
+               kunmap(obj->pages[0]);
+
+               ret = i915_gem_object_set_to_gtt_domain(&obj->base, false);
+               if (ret) {
+                       i915_gem_object_unpin(&obj->base);
+                       drm_gem_object_unreference(&obj->base);
+                       return ret;
+               }
+
+               ring->private = obj;
+       }
+
+       return init_ring_common(dev, ring);
+}
+
+static void blt_ring_begin(struct drm_device *dev,
+                          struct intel_ring_buffer *ring,
+                         int num_dwords)
+{
+       if (ring->private) {
+               intel_ring_begin(dev, ring, num_dwords+2);
+               intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START);
+               intel_ring_emit(dev, ring, to_blt_workaround(ring)->gtt_offset);
+       } else
+               intel_ring_begin(dev, ring, 4);
+}
+
+static void blt_ring_flush(struct drm_device *dev,
+                          struct intel_ring_buffer *ring,
+                          u32 invalidate_domains,
+                          u32 flush_domains)
+{
+       blt_ring_begin(dev, ring, 4);
+       intel_ring_emit(dev, ring, MI_FLUSH_DW);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_advance(dev, ring);
+}
+
+static u32
+blt_ring_add_request(struct drm_device *dev,
+                    struct intel_ring_buffer *ring,
+                    u32 flush_domains)
+{
+       u32 seqno = i915_gem_get_seqno(dev);
+
+       blt_ring_begin(dev, ring, 4);
+       intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX);
+       intel_ring_emit(dev, ring,
+                       I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+       intel_ring_emit(dev, ring, seqno);
+       intel_ring_emit(dev, ring, MI_USER_INTERRUPT);
+       intel_ring_advance(dev, ring);
+
+       DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
+       return seqno;
+}
+
+static void blt_ring_cleanup(struct intel_ring_buffer *ring)
+{
+       if (!ring->private)
+               return;
+
+       i915_gem_object_unpin(ring->private);
+       drm_gem_object_unreference(ring->private);
+       ring->private = NULL;
+}
+
 static const struct intel_ring_buffer gen6_blt_ring = {
        .name                   = "blt ring",
        .id                     = RING_BLT,
        .mmio_base              = BLT_RING_BASE,
        .size                   = 32 * PAGE_SIZE,
-       .init                   = init_ring_common,
+       .init                   = blt_ring_init,
        .write_tail             = ring_write_tail,
-       .flush                  = gen6_ring_flush,
-       .add_request            = ring_add_request,
+       .flush                  = blt_ring_flush,
+       .add_request            = blt_ring_add_request,
        .get_seqno              = ring_status_page_get_seqno,
        .user_irq_get           = blt_ring_get_user_irq,
        .user_irq_put           = blt_ring_put_user_irq,
        .dispatch_gem_execbuffer        = gen6_ring_dispatch_gem_execbuffer,
+       .cleanup                        = blt_ring_cleanup,
 };
 
 int intel_init_render_ring_buffer(struct drm_device *dev)
index a05aff0e5764d67e421a5a4995f2b0b92dfcd925..3126c2681983e21ba729d9ca599d104f4f1323de 100644 (file)
@@ -63,6 +63,7 @@ struct  intel_ring_buffer {
                        struct drm_i915_gem_execbuffer2 *exec,
                        struct drm_clip_rect *cliprects,
                        uint64_t exec_offset);
+       void            (*cleanup)(struct intel_ring_buffer *ring);
 
        /**
         * List of objects currently involved in rendering from the
@@ -98,6 +99,8 @@ struct  intel_ring_buffer {
 
        wait_queue_head_t irq_queue;
        drm_local_map_t map;
+
+       void *private;
 };
 
 static inline u32
index 406228f4a2a05e549090f8a4e4fca09253546833..b14c811105756706103fe770bc140f24e0a604a7 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <linux/backlight.h>
+#include <linux/acpi.h>
 
 #include "drmP.h"
 #include "nouveau_drv.h"
@@ -136,6 +137,14 @@ int nouveau_backlight_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
+#ifdef CONFIG_ACPI
+       if (acpi_video_backlight_support()) {
+               NV_INFO(dev, "ACPI backlight interface available, "
+                            "not registering our own\n");
+               return 0;
+       }
+#endif
+
        switch (dev_priv->card_type) {
        case NV_40:
                return nouveau_nv40_backlight_init(dev);
index 5f21030a293bbc3f373a76631a5e092a0075ea3f..b2293576f27895f3b67e41e563675ab52519b3ad 100644 (file)
@@ -6829,7 +6829,7 @@ nouveau_bios_posted(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        unsigned htotal;
 
-       if (dev_priv->chipset >= NV_50) {
+       if (dev_priv->card_type >= NV_50) {
                if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
                    NVReadVgaCrtc(dev, 0, 0x1a) == 0)
                        return false;
index 80353e2b8409fdfe34b620b54ce8fdc119af5acd..c41e1c200ef5f2143ea670b45eb3f1d0633864e2 100644 (file)
@@ -143,8 +143,10 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
        nvbo->no_vm = no_vm;
        nvbo->tile_mode = tile_mode;
        nvbo->tile_flags = tile_flags;
+       nvbo->bo.bdev = &dev_priv->ttm.bdev;
 
-       nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
+       nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo),
+                              &align, &size);
        align >>= PAGE_SHIFT;
 
        nouveau_bo_placement_set(nvbo, flags, 0);
@@ -176,6 +178,31 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
                pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
 }
 
+static void
+set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
+{
+       struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+
+       if (dev_priv->card_type == NV_10 &&
+           nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
+               /*
+                * Make sure that the color and depth buffers are handled
+                * by independent memory controller units. Up to a 9x
+                * speed up when alpha-blending and depth-test are enabled
+                * at the same time.
+                */
+               int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
+
+               if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
+                       nvbo->placement.fpfn = vram_pages / 2;
+                       nvbo->placement.lpfn = ~0;
+               } else {
+                       nvbo->placement.fpfn = 0;
+                       nvbo->placement.lpfn = vram_pages / 2;
+               }
+       }
+}
+
 void
 nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 {
@@ -190,6 +217,8 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
        pl->busy_placement = nvbo->busy_placements;
        set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
                           type | busy, flags);
+
+       set_placement_range(nvbo, type);
 }
 
 int
@@ -525,7 +554,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
                stride  = 16 * 4;
                height  = amount / stride;
 
-               if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+               if (new_mem->mem_type == TTM_PL_VRAM &&
+                   nouveau_bo_tile_layout(nvbo)) {
                        ret = RING_SPACE(chan, 8);
                        if (ret)
                                return ret;
@@ -546,7 +576,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
                        BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
                        OUT_RING  (chan, 1);
                }
-               if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
+               if (old_mem->mem_type == TTM_PL_VRAM &&
+                   nouveau_bo_tile_layout(nvbo)) {
                        ret = RING_SPACE(chan, 8);
                        if (ret)
                                return ret;
@@ -753,7 +784,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
        if (dev_priv->card_type == NV_50) {
                ret = nv50_mem_vm_bind_linear(dev,
                                              offset + dev_priv->vm_vram_base,
-                                             new_mem->size, nvbo->tile_flags,
+                                             new_mem->size,
+                                             nouveau_bo_tile_layout(nvbo),
                                              offset);
                if (ret)
                        return ret;
@@ -894,7 +926,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
         * nothing to do here.
         */
        if (bo->mem.mem_type != TTM_PL_VRAM) {
-               if (dev_priv->card_type < NV_50 || !nvbo->tile_flags)
+               if (dev_priv->card_type < NV_50 ||
+                   !nouveau_bo_tile_layout(nvbo))
                        return 0;
        }
 
index 0871495096fa86f1278f825c8420f8e14f1e6b38..52c356e9a3d177b92ed5013e8f55247a56468f5d 100644 (file)
@@ -281,7 +281,7 @@ detect_analog:
        nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
        if (!nv_encoder && !nouveau_tv_disable)
                nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
-       if (nv_encoder) {
+       if (nv_encoder && force) {
                struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
                struct drm_encoder_helper_funcs *helper =
                                                encoder->helper_private;
@@ -641,11 +641,28 @@ nouveau_connector_get_modes(struct drm_connector *connector)
        return ret;
 }
 
+static unsigned
+get_tmds_link_bandwidth(struct drm_connector *connector)
+{
+       struct nouveau_connector *nv_connector = nouveau_connector(connector);
+       struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
+       struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;
+
+       if (dcb->location != DCB_LOC_ON_CHIP ||
+           dev_priv->chipset >= 0x46)
+               return 165000;
+       else if (dev_priv->chipset >= 0x40)
+               return 155000;
+       else if (dev_priv->chipset >= 0x18)
+               return 135000;
+       else
+               return 112000;
+}
+
 static int
 nouveau_connector_mode_valid(struct drm_connector *connector,
                             struct drm_display_mode *mode)
 {
-       struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
        struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
@@ -663,11 +680,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
                max_clock = 400000;
                break;
        case OUTPUT_TMDS:
-               if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) ||
-                   !nv_encoder->dcb->duallink_possible)
-                       max_clock = 165000;
-               else
-                       max_clock = 330000;
+               max_clock = get_tmds_link_bandwidth(connector);
+               if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
+                       max_clock *= 2;
                break;
        case OUTPUT_ANALOG:
                max_clock = nv_encoder->dcb->crtconf.maxfreq;
@@ -709,44 +724,6 @@ nouveau_connector_best_encoder(struct drm_connector *connector)
        return NULL;
 }
 
-void
-nouveau_connector_set_polling(struct drm_connector *connector)
-{
-       struct drm_device *dev = connector->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc;
-       bool spare_crtc = false;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-               spare_crtc |= !crtc->enabled;
-
-       connector->polled = 0;
-
-       switch (connector->connector_type) {
-       case DRM_MODE_CONNECTOR_VGA:
-       case DRM_MODE_CONNECTOR_TV:
-               if (dev_priv->card_type >= NV_50 ||
-                   (nv_gf4_disp_arch(dev) && spare_crtc))
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-               break;
-
-       case DRM_MODE_CONNECTOR_DVII:
-       case DRM_MODE_CONNECTOR_DVID:
-       case DRM_MODE_CONNECTOR_HDMIA:
-       case DRM_MODE_CONNECTOR_DisplayPort:
-       case DRM_MODE_CONNECTOR_eDP:
-               if (dev_priv->card_type >= NV_50)
-                       connector->polled = DRM_CONNECTOR_POLL_HPD;
-               else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
-                        spare_crtc)
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-               break;
-
-       default:
-               break;
-       }
-}
-
 static const struct drm_connector_helper_funcs
 nouveau_connector_helper_funcs = {
        .get_modes = nouveau_connector_get_modes,
@@ -872,6 +849,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                                        dev->mode_config.scaling_mode_property,
                                        nv_connector->scaling_mode);
                }
+               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
                /* fall-through */
        case DCB_CONNECTOR_TV_0:
        case DCB_CONNECTOR_TV_1:
@@ -888,11 +866,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
                                dev->mode_config.dithering_mode_property,
                                nv_connector->use_dithering ?
                                DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
+
+               if (dcb->type != DCB_CONNECTOR_LVDS) {
+                       if (dev_priv->card_type >= NV_50)
+                               connector->polled = DRM_CONNECTOR_POLL_HPD;
+                       else
+                               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+               }
                break;
        }
 
-       nouveau_connector_set_polling(connector);
-
        drm_sysfs_connector_add(connector);
        dcb->drm = connector;
        return dcb->drm;
index c21ed6b16f88d41aebdee888997c12a7249fdd03..711b1e9203aff075c16757fd41394a5ea06d33e7 100644 (file)
@@ -52,9 +52,6 @@ static inline struct nouveau_connector *nouveau_connector(
 struct drm_connector *
 nouveau_connector_create(struct drm_device *, int index);
 
-void
-nouveau_connector_set_polling(struct drm_connector *);
-
 int
 nouveau_connector_bpp(struct drm_connector *);
 
index 3a07e580d27af548fe2fd247b4e7df4c67994956..1c7db64c03bf03b45070939f16bc5a0092820ba0 100644 (file)
@@ -100,6 +100,9 @@ struct nouveau_bo {
        int pin_refcnt;
 };
 
+#define nouveau_bo_tile_layout(nvbo)                           \
+       ((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)
+
 static inline struct nouveau_bo *
 nouveau_bo(struct ttm_buffer_object *bo)
 {
@@ -304,6 +307,7 @@ struct nouveau_fifo_engine {
        void (*destroy_context)(struct nouveau_channel *);
        int  (*load_context)(struct nouveau_channel *);
        int  (*unload_context)(struct drm_device *);
+       void (*tlb_flush)(struct drm_device *dev);
 };
 
 struct nouveau_pgraph_object_method {
@@ -336,6 +340,7 @@ struct nouveau_pgraph_engine {
        void (*destroy_context)(struct nouveau_channel *);
        int  (*load_context)(struct nouveau_channel *);
        int  (*unload_context)(struct drm_device *);
+       void (*tlb_flush)(struct drm_device *dev);
 
        void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
                                  uint32_t size, uint32_t pitch);
@@ -485,13 +490,13 @@ enum nv04_fp_display_regs {
 };
 
 struct nv04_crtc_reg {
-       unsigned char MiscOutReg;     /* */
+       unsigned char MiscOutReg;
        uint8_t CRTC[0xa0];
        uint8_t CR58[0x10];
        uint8_t Sequencer[5];
        uint8_t Graphics[9];
        uint8_t Attribute[21];
-       unsigned char DAC[768];       /* Internal Colorlookuptable */
+       unsigned char DAC[768];
 
        /* PCRTC regs */
        uint32_t fb_start;
@@ -539,43 +544,9 @@ struct nv04_output_reg {
 };
 
 struct nv04_mode_state {
-       uint32_t bpp;
-       uint32_t width;
-       uint32_t height;
-       uint32_t interlace;
-       uint32_t repaint0;
-       uint32_t repaint1;
-       uint32_t screen;
-       uint32_t scale;
-       uint32_t dither;
-       uint32_t extra;
-       uint32_t fifo;
-       uint32_t pixel;
-       uint32_t horiz;
-       int arbitration0;
-       int arbitration1;
-       uint32_t pll;
-       uint32_t pllB;
-       uint32_t vpll;
-       uint32_t vpll2;
-       uint32_t vpllB;
-       uint32_t vpll2B;
+       struct nv04_crtc_reg crtc_reg[2];
        uint32_t pllsel;
        uint32_t sel_clk;
-       uint32_t general;
-       uint32_t crtcOwner;
-       uint32_t head;
-       uint32_t head2;
-       uint32_t cursorConfig;
-       uint32_t cursor0;
-       uint32_t cursor1;
-       uint32_t cursor2;
-       uint32_t timingH;
-       uint32_t timingV;
-       uint32_t displayV;
-       uint32_t crtcSync;
-
-       struct nv04_crtc_reg crtc_reg[2];
 };
 
 enum nouveau_card_type {
@@ -613,6 +584,12 @@ struct drm_nouveau_private {
        struct work_struct irq_work;
        struct work_struct hpd_work;
 
+       struct {
+               spinlock_t lock;
+               uint32_t hpd0_bits;
+               uint32_t hpd1_bits;
+       } hpd_state;
+
        struct list_head vbl_waiting;
 
        struct {
@@ -1045,6 +1022,7 @@ extern int  nv50_fifo_create_context(struct nouveau_channel *);
 extern void nv50_fifo_destroy_context(struct nouveau_channel *);
 extern int  nv50_fifo_load_context(struct nouveau_channel *);
 extern int  nv50_fifo_unload_context(struct drm_device *);
+extern void nv50_fifo_tlb_flush(struct drm_device *dev);
 
 /* nvc0_fifo.c */
 extern int  nvc0_fifo_init(struct drm_device *);
@@ -1122,6 +1100,8 @@ extern int  nv50_graph_load_context(struct nouveau_channel *);
 extern int  nv50_graph_unload_context(struct drm_device *);
 extern void nv50_graph_context_switch(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
+extern void nv50_graph_tlb_flush(struct drm_device *dev);
+extern void nv86_graph_tlb_flush(struct drm_device *dev);
 
 /* nvc0_graph.c */
 extern int  nvc0_graph_init(struct drm_device *);
@@ -1239,7 +1219,6 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
 extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
 extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
 extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
-extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
 
 /* nouveau_fence.c */
 struct nouveau_fence;
index 441b12420bb1b713fb56b98edad389d31fe367ea..ab1bbfbf266e6a63755264ad461484f3608a10c1 100644 (file)
@@ -249,6 +249,7 @@ alloc_semaphore(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_semaphore *sema;
+       int ret;
 
        if (!USE_SEMA(dev))
                return NULL;
@@ -257,10 +258,14 @@ alloc_semaphore(struct drm_device *dev)
        if (!sema)
                goto fail;
 
+       ret = drm_mm_pre_get(&dev_priv->fence.heap);
+       if (ret)
+               goto fail;
+
        spin_lock(&dev_priv->fence.lock);
        sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
        if (sema->mem)
-               sema->mem = drm_mm_get_block(sema->mem, 4, 0);
+               sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0);
        spin_unlock(&dev_priv->fence.lock);
 
        if (!sema->mem)
index 5c4c929d7f744d6911c1a16b67924ab770b6de5c..9a1fdcf400c2fea235544f062fe8b33cd1b01fd4 100644 (file)
@@ -107,23 +107,29 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep)
 }
 
 static bool
-nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) {
-       switch (tile_flags) {
-       case 0x0000:
-       case 0x1800:
-       case 0x2800:
-       case 0x4800:
-       case 0x7000:
-       case 0x7400:
-       case 0x7a00:
-       case 0xe000:
-               break;
-       default:
-               NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
-               return false;
+nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->card_type >= NV_50) {
+               switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) {
+               case 0x0000:
+               case 0x1800:
+               case 0x2800:
+               case 0x4800:
+               case 0x7000:
+               case 0x7400:
+               case 0x7a00:
+               case 0xe000:
+                       return true;
+               }
+       } else {
+               if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))
+                       return true;
        }
 
-       return true;
+       NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
+       return false;
 }
 
 int
index bed669a54a2da0692af9a9a1cd4a89064f4d0fd0..b9672a05c411f12866035884acf8778a4742eb9c 100644 (file)
@@ -519,11 +519,11 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
 
        struct pll_lims pll_lim;
        struct nouveau_pll_vals pv;
-       uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
+       enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0;
 
-       if (get_pll_limits(dev, pllreg, &pll_lim))
+       if (get_pll_limits(dev, pll, &pll_lim))
                return;
-       nouveau_hw_get_pllvals(dev, pllreg, &pv);
+       nouveau_hw_get_pllvals(dev, pll, &pv);
 
        if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
            pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
@@ -536,7 +536,7 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
        pv.M1 = pll_lim.vco1.max_m;
        pv.N1 = pll_lim.vco1.min_n;
        pv.log2P = pll_lim.max_usable_log2p;
-       nouveau_hw_setpll(dev, pllreg, &pv);
+       nouveau_hw_setpll(dev, pll_lim.reg, &pv);
 }
 
 /*
index 869130f83602f6cf027a2329eb7be49eafb88ccc..2989090b94349abdcd05096f89735f641a748c3b 100644 (file)
@@ -415,6 +415,25 @@ nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
        NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
 }
 
+static inline void
+nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
+
+       if (dev_priv->card_type == NV_04) {
+               /*
+                * Hilarious, the 24th bit doesn't want to stick to
+                * PCRTC_START...
+                */
+               int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
+
+               NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
+                              (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
+       }
+}
+
 static inline void
 nv_show_cursor(struct drm_device *dev, int head, bool show)
 {
index fdd7e3de79c895138c93706bc023048772f93026..cb389d014326ae4c89b78724f3438a023e0f06b7 100644 (file)
@@ -256,7 +256,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
        if (index >= DCB_MAX_NUM_I2C_ENTRIES)
                return NULL;
 
-       if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
+       if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
                uint32_t reg = 0xe500, val;
 
                if (i2c->port_type == 6) {
index 6fd51a51c60861e697f43755593f4ad2a1830c9c..7bfd9e6c9d67194b298047d7670a54a996c16750 100644 (file)
 #include "nouveau_connector.h"
 #include "nv50_display.h"
 
+static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
+
+static int nouveau_ratelimit(void)
+{
+       return __ratelimit(&nouveau_ratelimit_state);
+}
+
 void
 nouveau_irq_preinstall(struct drm_device *dev)
 {
@@ -53,6 +60,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
        if (dev_priv->card_type >= NV_50) {
                INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
                INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
+               spin_lock_init(&dev_priv->hpd_state.lock);
                INIT_LIST_HEAD(&dev_priv->vbl_waiting);
        }
 }
@@ -202,8 +210,8 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
                }
 
                if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-                       u32 get = nv_rd32(dev, 0x003244);
-                       u32 put = nv_rd32(dev, 0x003240);
+                       u32 dma_get = nv_rd32(dev, 0x003244);
+                       u32 dma_put = nv_rd32(dev, 0x003240);
                        u32 push = nv_rd32(dev, 0x003220);
                        u32 state = nv_rd32(dev, 0x003228);
 
@@ -213,16 +221,18 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
                                u32 ib_get = nv_rd32(dev, 0x003334);
                                u32 ib_put = nv_rd32(dev, 0x003330);
 
-                               NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
+                               if (nouveau_ratelimit())
+                                       NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
                                             "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
                                             "State 0x%08x Push 0x%08x\n",
-                                       chid, ho_get, get, ho_put, put, ib_get, ib_put,
-                                       state, push);
+                                               chid, ho_get, dma_get, ho_put,
+                                               dma_put, ib_get, ib_put, state,
+                                               push);
 
                                /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
                                nv_wr32(dev, 0x003364, 0x00000000);
-                               if (get != put || ho_get != ho_put) {
-                                       nv_wr32(dev, 0x003244, put);
+                               if (dma_get != dma_put || ho_get != ho_put) {
+                                       nv_wr32(dev, 0x003244, dma_put);
                                        nv_wr32(dev, 0x003328, ho_put);
                                } else
                                if (ib_get != ib_put) {
@@ -231,10 +241,10 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
                        } else {
                                NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
                                             "Put 0x%08x State 0x%08x Push 0x%08x\n",
-                                       chid, get, put, state, push);
+                                       chid, dma_get, dma_put, state, push);
 
-                               if (get != put)
-                                       nv_wr32(dev, 0x003244, put);
+                               if (dma_get != dma_put)
+                                       nv_wr32(dev, 0x003244, dma_put);
                        }
 
                        nv_wr32(dev, 0x003228, 0x00000000);
@@ -266,8 +276,9 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
                }
 
                if (status) {
-                       NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
-                               status, chid);
+                       if (nouveau_ratelimit())
+                               NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
+                                       status, chid);
                        nv_wr32(dev, NV03_PFIFO_INTR_0, status);
                        status = 0;
                }
@@ -544,13 +555,6 @@ nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource)
                nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
 }
 
-static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
-
-static int nouveau_ratelimit(void)
-{
-       return __ratelimit(&nouveau_ratelimit_state);
-}
-
 
 static inline void
 nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
index a163c7c612e78eb6b6718620ee75773cd49a26f7..fe4a30dc4b42e929f283d35e1094b26a422f4f2e 100644 (file)
@@ -33,9 +33,9 @@
 #include "drmP.h"
 #include "drm.h"
 #include "drm_sarea.h"
-#include "nouveau_drv.h"
 
-#define MIN(a,b) a < b ? a : b
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
 
 /*
  * NV10-NV40 tiling helpers
@@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
                        }
                }
        }
-       dev_priv->engine.instmem.flush(dev);
 
-       nv50_vm_flush(dev, 5);
-       nv50_vm_flush(dev, 0);
-       nv50_vm_flush(dev, 4);
+       dev_priv->engine.instmem.flush(dev);
+       dev_priv->engine.fifo.tlb_flush(dev);
+       dev_priv->engine.graph.tlb_flush(dev);
        nv50_vm_flush(dev, 6);
        return 0;
 }
@@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
                        pte++;
                }
        }
-       dev_priv->engine.instmem.flush(dev);
 
-       nv50_vm_flush(dev, 5);
-       nv50_vm_flush(dev, 0);
-       nv50_vm_flush(dev, 4);
+       dev_priv->engine.instmem.flush(dev);
+       dev_priv->engine.fifo.tlb_flush(dev);
+       dev_priv->engine.graph.tlb_flush(dev);
        nv50_vm_flush(dev, 6);
 }
 
@@ -653,6 +651,7 @@ nouveau_mem_gart_init(struct drm_device *dev)
 void
 nouveau_mem_timing_init(struct drm_device *dev)
 {
+       /* cards < NVC0 only */
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
        struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
@@ -719,14 +718,14 @@ nouveau_mem_timing_init(struct drm_device *dev)
                tUNK_19 = 1;
                tUNK_20 = 0;
                tUNK_21 = 0;
-               switch (MIN(recordlen,21)) {
-               case 21:
+               switch (min(recordlen, 22)) {
+               case 22:
                        tUNK_21 = entry[21];
-               case 20:
+               case 21:
                        tUNK_20 = entry[20];
-               case 19:
+               case 20:
                        tUNK_19 = entry[19];
-               case 18:
+               case 19:
                        tUNK_18 = entry[18];
                default:
                        tUNK_0  = entry[0];
@@ -756,24 +755,30 @@ nouveau_mem_timing_init(struct drm_device *dev)
                timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
                if(recordlen > 19) {
                        timing->reg_100228 += (tUNK_19 - 1) << 24;
-               } else {
+               }/* I cannot back-up this else-statement right now
+                        else {
                        timing->reg_100228 += tUNK_12 << 24;
-               }
+               }*/
 
                /* XXX: reg_10022c */
+               timing->reg_10022c = tUNK_2 - 1;
 
                timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
                                      tUNK_13 << 8  | tUNK_13);
 
                /* XXX: +6? */
                timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
-               if(tUNK_10 > tUNK_11) {
-                       timing->reg_100234 += tUNK_10 << 16;
-               } else {
-                       timing->reg_100234 += tUNK_11 << 16;
+               timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+
+               /* XXX; reg_100238, reg_10023c
+                * reg: 0x00??????
+                * reg_10023c:
+                *      0 for pre-NV50 cards
+                *      0x????0202 for NV50+ cards (empirical evidence) */
+               if(dev_priv->card_type >= NV_50) {
+                       timing->reg_10023c = 0x202;
                }
 
-               /* XXX; reg_100238, reg_10023c */
                NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
                         timing->reg_100220, timing->reg_100224,
                         timing->reg_100228, timing->reg_10022c);
index 896cf8634144a2b5cf7f69fdd006c848b4b2eb79..dd572adca02ad0232df35715257ccc597adf86f3 100644 (file)
@@ -129,7 +129,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
                        if (ramin == NULL) {
                                spin_unlock(&dev_priv->ramin_lock);
                                nouveau_gpuobj_ref(NULL, &gpuobj);
-                               return ret;
+                               return -ENOMEM;
                        }
 
                        ramin = drm_mm_get_block_atomic(ramin, size, align);
index 1c99c55d6d468a91fb09cda39d5660d3bf712aa5..9f7b158f5825c7dfd97b5f112afef7a9858e7b23 100644 (file)
@@ -284,6 +284,7 @@ nouveau_sysfs_fini(struct drm_device *dev)
        }
 }
 
+#ifdef CONFIG_HWMON
 static ssize_t
 nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
 {
@@ -395,10 +396,12 @@ static struct attribute *hwmon_attributes[] = {
 static const struct attribute_group hwmon_attrgroup = {
        .attrs = hwmon_attributes,
 };
+#endif
 
 static int
 nouveau_hwmon_init(struct drm_device *dev)
 {
+#ifdef CONFIG_HWMON
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
        struct device *hwmon_dev;
@@ -425,13 +428,14 @@ nouveau_hwmon_init(struct drm_device *dev)
        }
 
        pm->hwmon = hwmon_dev;
-
+#endif
        return 0;
 }
 
 static void
 nouveau_hwmon_fini(struct drm_device *dev)
 {
+#ifdef CONFIG_HWMON
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 
@@ -439,6 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
                sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
                hwmon_device_unregister(pm->hwmon);
        }
+#endif
 }
 
 int
index 7f16697cc96ce6438896414735b5fa4d12a84a34..2d8580927ca4579075cd870e5cfdf6459c44d9c6 100644 (file)
@@ -153,26 +153,42 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
        return -ENOMEM;
 }
 
+static struct nouveau_ramht_entry *
+nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
+{
+       struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
+       struct nouveau_ramht_entry *entry;
+       unsigned long flags;
+
+       if (!ramht)
+               return NULL;
+
+       spin_lock_irqsave(&ramht->lock, flags);
+       list_for_each_entry(entry, &ramht->entries, head) {
+               if (entry->channel == chan &&
+                   (!handle || entry->handle == handle)) {
+                       list_del(&entry->head);
+                       spin_unlock_irqrestore(&ramht->lock, flags);
+
+                       return entry;
+               }
+       }
+       spin_unlock_irqrestore(&ramht->lock, flags);
+
+       return NULL;
+}
+
 static void
-nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
+nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
        struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
-       struct nouveau_ramht_entry *entry, *tmp;
+       unsigned long flags;
        u32 co, ho;
 
-       list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
-               if (entry->channel != chan || entry->handle != handle)
-                       continue;
-
-               nouveau_gpuobj_ref(NULL, &entry->gpuobj);
-               list_del(&entry->head);
-               kfree(entry);
-               break;
-       }
-
+       spin_lock_irqsave(&chan->ramht->lock, flags);
        co = ho = nouveau_ramht_hash_handle(chan, handle);
        do {
                if (nouveau_ramht_entry_valid(dev, ramht, co) &&
@@ -184,7 +200,7 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
                        nv_wo32(ramht, co + 0, 0x00000000);
                        nv_wo32(ramht, co + 4, 0x00000000);
                        instmem->flush(dev);
-                       return;
+                       goto out;
                }
 
                co += 8;
@@ -194,17 +210,22 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
 
        NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
                 chan->id, handle);
+out:
+       spin_unlock_irqrestore(&chan->ramht->lock, flags);
 }
 
 void
 nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
 {
-       struct nouveau_ramht *ramht = chan->ramht;
-       unsigned long flags;
+       struct nouveau_ramht_entry *entry;
 
-       spin_lock_irqsave(&ramht->lock, flags);
-       nouveau_ramht_remove_locked(chan, handle);
-       spin_unlock_irqrestore(&ramht->lock, flags);
+       entry = nouveau_ramht_remove_entry(chan, handle);
+       if (!entry)
+               return;
+
+       nouveau_ramht_remove_hash(chan, entry->handle);
+       nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+       kfree(entry);
 }
 
 struct nouveau_gpuobj *
@@ -265,23 +286,19 @@ void
 nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
                  struct nouveau_channel *chan)
 {
-       struct nouveau_ramht_entry *entry, *tmp;
+       struct nouveau_ramht_entry *entry;
        struct nouveau_ramht *ramht;
-       unsigned long flags;
 
        if (ref)
                kref_get(&ref->refcount);
 
        ramht = *ptr;
        if (ramht) {
-               spin_lock_irqsave(&ramht->lock, flags);
-               list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
-                       if (entry->channel != chan)
-                               continue;
-
-                       nouveau_ramht_remove_locked(chan, entry->handle);
+               while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
+                       nouveau_ramht_remove_hash(chan, entry->handle);
+                       nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+                       kfree(entry);
                }
-               spin_unlock_irqrestore(&ramht->lock, flags);
 
                kref_put(&ramht->refcount, nouveau_ramht_del);
        }
index 288bacac7e5aefc2f3c6c9b4f461a7e48d6e9ce7..d4ac970070386cea340283ba459194eb8b1de50a 100644 (file)
@@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
        dev_priv->engine.instmem.flush(nvbe->dev);
 
        if (dev_priv->card_type == NV_50) {
-               nv50_vm_flush(dev, 5); /* PGRAPH */
-               nv50_vm_flush(dev, 0); /* PFIFO */
+               dev_priv->engine.fifo.tlb_flush(dev);
+               dev_priv->engine.graph.tlb_flush(dev);
        }
 
        nvbe->bound = true;
@@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
        dev_priv->engine.instmem.flush(nvbe->dev);
 
        if (dev_priv->card_type == NV_50) {
-               nv50_vm_flush(dev, 5);
-               nv50_vm_flush(dev, 0);
+               dev_priv->engine.fifo.tlb_flush(dev);
+               dev_priv->engine.graph.tlb_flush(dev);
        }
 
        nvbe->bound = false;
@@ -224,7 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev)
        int i, ret;
 
        if (dev_priv->card_type < NV_50) {
-               aper_size = (64 * 1024 * 1024);
+               if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024)
+                       aper_size = 64 * 1024 * 1024;
+               else
+                       aper_size = 512 * 1024 * 1024;
+
                obj_size  = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
                obj_size += 8; /* ctxdma header */
        } else {
index ed7757f14083a17e3122250ca83aa8ee2959ddec..049f755567e5c83b047298f74ff1c24b6ceea5fe 100644 (file)
@@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->graph.destroy_context   = nv50_graph_destroy_context;
                engine->graph.load_context      = nv50_graph_load_context;
                engine->graph.unload_context    = nv50_graph_unload_context;
+               if (dev_priv->chipset != 0x86)
+                       engine->graph.tlb_flush = nv50_graph_tlb_flush;
+               else {
+                       /* from what i can see nvidia do this on every
+                        * pre-NVA3 board except NVAC, but, we've only
+                        * ever seen problems on NV86
+                        */
+                       engine->graph.tlb_flush = nv86_graph_tlb_flush;
+               }
                engine->fifo.channels           = 128;
                engine->fifo.init               = nv50_fifo_init;
                engine->fifo.takedown           = nv50_fifo_takedown;
@@ -365,6 +374,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fifo.destroy_context    = nv50_fifo_destroy_context;
                engine->fifo.load_context       = nv50_fifo_load_context;
                engine->fifo.unload_context     = nv50_fifo_unload_context;
+               engine->fifo.tlb_flush          = nv50_fifo_tlb_flush;
                engine->display.early_init      = nv50_display_early_init;
                engine->display.late_takedown   = nv50_display_late_takedown;
                engine->display.create          = nv50_display_create;
@@ -1041,6 +1051,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
        case NOUVEAU_GETPARAM_PTIMER_TIME:
                getparam->value = dev_priv->engine.timer.read(dev);
                break;
+       case NOUVEAU_GETPARAM_HAS_BO_USAGE:
+               getparam->value = 1;
+               break;
        case NOUVEAU_GETPARAM_GRAPH_UNITS:
                /* NV40 and NV50 versions are quite different, but register
                 * address is the same. User is supposed to know the card
@@ -1051,7 +1064,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
                }
                /* FALLTHRU */
        default:
-               NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
+               NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
                return -EINVAL;
        }
 
@@ -1066,7 +1079,7 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
 
        switch (setparam->param) {
        default:
-               NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
+               NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param);
                return -EINVAL;
        }
 
index 16bbbf1eff63bc5ef37038e37d85fccc7f407a8d..7ecc4adc1e4575aca6ef2791752c25300ff7668b 100644 (file)
@@ -191,7 +191,7 @@ nv40_temp_get(struct drm_device *dev)
        int offset = sensor->offset_mult / sensor->offset_div;
        int core_temp;
 
-       if (dev_priv->chipset >= 0x50) {
+       if (dev_priv->card_type >= NV_50) {
                core_temp = nv_rd32(dev, 0x20008);
        } else {
                core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
index c71abc2a34d5d9cf22a01d3c3bf455a29c5d1dbf..40e180741629e056f72445ffab06104760bd70ec 100644 (file)
@@ -158,7 +158,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_connector *connector;
        unsigned char seq1 = 0, crtc17 = 0;
        unsigned char crtc1A;
 
@@ -213,10 +212,6 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
        NVVgaSeqReset(dev, nv_crtc->index, false);
 
        NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
-
-       /* Update connector polling modes */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-               nouveau_connector_set_polling(connector);
 }
 
 static bool
@@ -831,7 +826,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
        /* Update the framebuffer location. */
        regp->fb_start = nv_crtc->fb.offset & ~3;
        regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8);
-       NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
+       nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start);
 
        /* Update the arbitration parameters. */
        nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
index c936403b26e22f7b4bcc1b4fee4fa6809498689b..ef23550407b5d7da95c0a4a5a6c35b82670ad4e5 100644 (file)
@@ -185,14 +185,15 @@ static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
 
-       /* For internal panels and gpu scaling on DVI we need the native mode */
-       if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
-               if (!nv_connector->native_mode)
-                       return false;
+       if (!nv_connector->native_mode ||
+           nv_connector->scaling_mode == DRM_MODE_SCALE_NONE ||
+           mode->hdisplay > nv_connector->native_mode->hdisplay ||
+           mode->vdisplay > nv_connector->native_mode->vdisplay) {
+               nv_encoder->mode = *adjusted_mode;
+
+       } else {
                nv_encoder->mode = *nv_connector->native_mode;
                adjusted_mode->clock = nv_connector->native_mode->clock;
-       } else {
-               nv_encoder->mode = *adjusted_mode;
        }
 
        return true;
index 6a6eb697d38e0b387941b05b38dadc8a5bd371f1..eb1c70dd82ed41540629792dc7264452f511e6f3 100644 (file)
@@ -76,6 +76,15 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
                reg += 4;
 
        nouveau_hw_setpll(dev, reg, &state->calc);
+
+       if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) {
+               if (dev_priv->card_type == NV_20)
+                       nv_mask(dev, 0x1002c4, 0, 1 << 20);
+
+               /* Reset the DLLs */
+               nv_mask(dev, 0x1002c0, 0, 1 << 8);
+       }
+
        kfree(state);
 }
 
index 2cdc2bfe717924bf4f8e29237c11efcc0865408b..de81151648f831c5a7c97b9491d3670c356276f5 100644 (file)
@@ -51,24 +51,28 @@ nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
               int *N, int *fN, int *M, int *P)
 {
        fixed20_12 fb_div, a, b;
+       u32 refclk = pll->refclk / 10;
+       u32 max_vco_freq = pll->vco1.maxfreq / 10;
+       u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
+       clk /= 10;
 
-       *P = pll->vco1.maxfreq / clk;
+       *P = max_vco_freq / clk;
        if (*P > pll->max_p)
                *P = pll->max_p;
        if (*P < pll->min_p)
                *P = pll->min_p;
 
-       /* *M = ceil(refclk / pll->vco.max_inputfreq); */
-       a.full = dfixed_const(pll->refclk);
-       b.full = dfixed_const(pll->vco1.max_inputfreq);
+       /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
+       a.full = dfixed_const(refclk + max_vco_inputfreq);
+       b.full = dfixed_const(max_vco_inputfreq);
        a.full = dfixed_div(a, b);
-       a.full = dfixed_ceil(a);
+       a.full = dfixed_floor(a);
        *M = dfixed_trunc(a);
 
        /* fb_div = (vco * *M) / refclk; */
        fb_div.full = dfixed_const(clk * *P);
        fb_div.full = dfixed_mul(fb_div, a);
-       a.full = dfixed_const(pll->refclk);
+       a.full = dfixed_const(refclk);
        fb_div.full = dfixed_div(fb_div, a);
 
        /* *N = floor(fb_div); */
index 16380d52cd885599f349219c903f12cf7b9c6159..56476d0c6de8ee5255ff6c8916070a5c5ed86aec 100644 (file)
@@ -546,7 +546,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
        }
 
        nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
-       nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
+       nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
        nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
        if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
                ret = RING_SPACE(evo, 2);
@@ -578,7 +578,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
                                  fb->nvbo->tile_mode);
        }
        if (dev_priv->chipset == 0x50)
-               OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format);
+               OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format);
        else
                OUT_RING(evo, format);
 
index 55c9663ef2bf8ddd4df2cf15b452daed66abc583..f624c611ddeaf39cb1c46010d7da30e4461c35ad 100644 (file)
@@ -1032,11 +1032,18 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
        struct drm_connector *connector;
        const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
        uint32_t unplug_mask, plug_mask, change_mask;
-       uint32_t hpd0, hpd1 = 0;
+       uint32_t hpd0, hpd1;
 
-       hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
+       spin_lock_irq(&dev_priv->hpd_state.lock);
+       hpd0 = dev_priv->hpd_state.hpd0_bits;
+       dev_priv->hpd_state.hpd0_bits = 0;
+       hpd1 = dev_priv->hpd_state.hpd1_bits;
+       dev_priv->hpd_state.hpd1_bits = 0;
+       spin_unlock_irq(&dev_priv->hpd_state.lock);
+
+       hpd0 &= nv_rd32(dev, 0xe050);
        if (dev_priv->chipset >= 0x90)
-               hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
+               hpd1 &= nv_rd32(dev, 0xe070);
 
        plug_mask   = (hpd0 & 0x0000ffff) | (hpd1 << 16);
        unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000);
@@ -1078,10 +1085,6 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
                        helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
        }
 
-       nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
-       if (dev_priv->chipset >= 0x90)
-               nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
-
        drm_helper_hpd_irq_event(dev);
 }
 
@@ -1092,8 +1095,22 @@ nv50_display_irq_handler(struct drm_device *dev)
        uint32_t delayed = 0;
 
        if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) {
-               if (!work_pending(&dev_priv->hpd_work))
-                       queue_work(dev_priv->wq, &dev_priv->hpd_work);
+               uint32_t hpd0_bits, hpd1_bits = 0;
+
+               hpd0_bits = nv_rd32(dev, 0xe054);
+               nv_wr32(dev, 0xe054, hpd0_bits);
+
+               if (dev_priv->chipset >= 0x90) {
+                       hpd1_bits = nv_rd32(dev, 0xe074);
+                       nv_wr32(dev, 0xe074, hpd1_bits);
+               }
+
+               spin_lock(&dev_priv->hpd_state.lock);
+               dev_priv->hpd_state.hpd0_bits |= hpd0_bits;
+               dev_priv->hpd_state.hpd1_bits |= hpd1_bits;
+               spin_unlock(&dev_priv->hpd_state.lock);
+
+               queue_work(dev_priv->wq, &dev_priv->hpd_work);
        }
 
        while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
index a46a961102f39052832856cac762e3cfe8ae1f88..1da65bd60c109f89ea44e20a8eb561ec35a0f237 100644 (file)
@@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev)
        return 0;
 }
 
+void
+nv50_fifo_tlb_flush(struct drm_device *dev)
+{
+       nv50_vm_flush(dev, 5);
+}
index cbf5ae2f67d4a110de1bb9d9c129224fbcdd6c3c..8b669d0af6105fb934c3485457e7db18fb43e0ad 100644 (file)
@@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
        { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
        {}
 };
+
+void
+nv50_graph_tlb_flush(struct drm_device *dev)
+{
+       nv50_vm_flush(dev, 0);
+}
+
+void
+nv86_graph_tlb_flush(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+       bool idle, timeout = false;
+       unsigned long flags;
+       u64 start;
+       u32 tmp;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
+
+       start = ptimer->read(dev);
+       do {
+               idle = true;
+
+               for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
+                       if ((tmp & 7) == 1)
+                               idle = false;
+               }
+
+               for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
+                       if ((tmp & 7) == 1)
+                               idle = false;
+               }
+
+               for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
+                       if ((tmp & 7) == 1)
+                               idle = false;
+               }
+       } while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
+
+       if (timeout) {
+               NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
+                             "0x%08x 0x%08x 0x%08x 0x%08x\n",
+                        nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
+                        nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
+       }
+
+       nv50_vm_flush(dev, 0);
+
+       nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+}
index a53fc974332b38ec659513e91a8421017e43c411..b773229b764793c1ee974462431ab5d9a4e57385 100644 (file)
@@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
        }
        dev_priv->engine.instmem.flush(dev);
 
-       nv50_vm_flush(dev, 4);
        nv50_vm_flush(dev, 6);
 
        gpuobj->im_bound = 1;
index f12a5b3ec050320505c6dc0b1cb44dcdde3fbeed..4dc5b4714c5a6ae1919246ac55ed32d3bacc44ac 100644 (file)
@@ -1650,7 +1650,36 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
                }
        }
 
-       rdev->config.evergreen.tile_config = gb_addr_config;
+       /* setup tiling info dword.  gb_addr_config is not adequate since it does
+        * not have bank info, so create a custom tiling dword.
+        * bits 3:0   num_pipes
+        * bits 7:4   num_banks
+        * bits 11:8  group_size
+        * bits 15:12 row_size
+        */
+       rdev->config.evergreen.tile_config = 0;
+       switch (rdev->config.evergreen.max_tile_pipes) {
+       case 1:
+       default:
+               rdev->config.evergreen.tile_config |= (0 << 0);
+               break;
+       case 2:
+               rdev->config.evergreen.tile_config |= (1 << 0);
+               break;
+       case 4:
+               rdev->config.evergreen.tile_config |= (2 << 0);
+               break;
+       case 8:
+               rdev->config.evergreen.tile_config |= (3 << 0);
+               break;
+       }
+       rdev->config.evergreen.tile_config |=
+               ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+       rdev->config.evergreen.tile_config |=
+               ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
+       rdev->config.evergreen.tile_config |=
+               ((gb_addr_config & 0x30000000) >> 28) << 12;
+
        WREG32(GB_BACKEND_MAP, gb_backend_map);
        WREG32(GB_ADDR_CONFIG, gb_addr_config);
        WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
@@ -2033,7 +2062,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
        u32 grbm_int_cntl = 0;
 
        if (!rdev->irq.installed) {
-               WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+               WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
                return -EINVAL;
        }
        /* don't enable anything if the ih is disabled */
@@ -2295,6 +2324,7 @@ restart_ih:
                        case 0: /* D1 vblank */
                                if (disp_int & LB_D1_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 0);
+                                       rdev->pm.vblank_sync = true;
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int &= ~LB_D1_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D1 vblank\n");
@@ -2316,6 +2346,7 @@ restart_ih:
                        case 0: /* D2 vblank */
                                if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 1);
+                                       rdev->pm.vblank_sync = true;
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D2 vblank\n");
@@ -2337,6 +2368,7 @@ restart_ih:
                        case 0: /* D3 vblank */
                                if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 2);
+                                       rdev->pm.vblank_sync = true;
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D3 vblank\n");
@@ -2358,6 +2390,7 @@ restart_ih:
                        case 0: /* D4 vblank */
                                if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 3);
+                                       rdev->pm.vblank_sync = true;
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D4 vblank\n");
@@ -2379,6 +2412,7 @@ restart_ih:
                        case 0: /* D5 vblank */
                                if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 4);
+                                       rdev->pm.vblank_sync = true;
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D5 vblank\n");
@@ -2400,6 +2434,7 @@ restart_ih:
                        case 0: /* D6 vblank */
                                if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
                                        drm_handle_vblank(rdev->ddev, 5);
+                                       rdev->pm.vblank_sync = true;
                                        wake_up(&rdev->irq.vblank_queue);
                                        disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
                                        DRM_DEBUG("IH: D6 vblank\n");
index ac3b6dde23db7ca1fd5f80083436cb49fcce0312..e0e590110dd47ffb06b2161ed1058e731620c826 100644 (file)
@@ -459,7 +459,7 @@ int evergreen_blit_init(struct radeon_device *rdev)
        obj_size += evergreen_ps_size * 4;
        obj_size = ALIGN(obj_size, 256);
 
-       r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+       r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
                                &rdev->r600_blit.shader_obj);
        if (r) {
                DRM_ERROR("evergreen failed to allocate shader\n");
index 0e8f28a689271c88a88d3865ead4890089049dca..8e10aa9f74b052a25e86d04e65173c8a7a19eb76 100644 (file)
@@ -442,7 +442,7 @@ int r100_pci_gart_init(struct radeon_device *rdev)
        int r;
 
        if (rdev->gart.table.ram.ptr) {
-               WARN(1, "R100 PCI GART already initialized.\n");
+               WARN(1, "R100 PCI GART already initialized\n");
                return 0;
        }
        /* Initialize common gart structure */
@@ -516,7 +516,7 @@ int r100_irq_set(struct radeon_device *rdev)
        uint32_t tmp = 0;
 
        if (!rdev->irq.installed) {
-               WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+               WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
                WREG32(R_000040_GEN_INT_CNTL, 0);
                return -EINVAL;
        }
index 34527e600fe94f91ab33da78285b695afbb6cd6e..cde1d3480d932c55ae33855c3a2336eadfe9ab54 100644 (file)
@@ -91,7 +91,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev)
        int r;
 
        if (rdev->gart.table.vram.robj) {
-               WARN(1, "RV370 PCIE GART already initialized.\n");
+               WARN(1, "RV370 PCIE GART already initialized\n");
                return 0;
        }
        /* Initialize common gart structure */
index 33952a12f0a31a49986a248a39c38cb48cdf618c..a3552594ccc44c69b398980e539daf348d62322a 100644 (file)
@@ -97,14 +97,8 @@ u32 rv6xx_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
-       u32 actual_temp = 0;
 
-       if ((temp >> 7) & 1)
-               actual_temp = 0;
-       else
-               actual_temp = (temp >> 1) & 0xff;
-
-       return actual_temp * 1000;
+       return temp * 1000;
 }
 
 void r600_pm_get_dynpm_state(struct radeon_device *rdev)
@@ -919,7 +913,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev)
        int r;
 
        if (rdev->gart.table.vram.robj) {
-               WARN(1, "R600 PCIE GART already initialized.\n");
+               WARN(1, "R600 PCIE GART already initialized\n");
                return 0;
        }
        /* Initialize common gart structure */
@@ -2724,7 +2718,7 @@ static int r600_ih_ring_alloc(struct radeon_device *rdev)
        /* Allocate ring buffer */
        if (rdev->ih.ring_obj == NULL) {
                r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size,
-                                    true,
+                                    PAGE_SIZE, true,
                                     RADEON_GEM_DOMAIN_GTT,
                                     &rdev->ih.ring_obj);
                if (r) {
@@ -2995,7 +2989,7 @@ int r600_irq_set(struct radeon_device *rdev)
        u32 hdmi1, hdmi2;
 
        if (!rdev->irq.installed) {
-               WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+               WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
                return -EINVAL;
        }
        /* don't enable anything if the ih is disabled */
index 8362974ef41ac9eac713f1e66377661aa7106c0b..86e5aa07f0db32ffe410f1c2dea0330fefd89d9d 100644 (file)
@@ -501,7 +501,7 @@ int r600_blit_init(struct radeon_device *rdev)
        obj_size += r6xx_ps_size * 4;
        obj_size = ALIGN(obj_size, 256);
 
-       r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+       r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
                                &rdev->r600_blit.shader_obj);
        if (r) {
                DRM_ERROR("r600 failed to allocate shader\n");
index 37cc2aa9f923cbace55e151d33870d1ac910a6a2..9bebac1ec006845f719b04cab125da2328c4d6bf 100644 (file)
@@ -50,6 +50,7 @@ struct r600_cs_track {
        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];
        struct radeon_bo        *cb_color_tile_bo[8];
@@ -67,6 +68,7 @@ struct r600_cs_track {
        u32                     db_depth_size;
        u32                     db_offset;
        struct radeon_bo        *db_bo;
+       u64                     db_bo_mc;
 };
 
 static inline int r600_bpe_from_format(u32 *bpe, u32 format)
@@ -140,6 +142,68 @@ static inline int r600_bpe_from_format(u32 *bpe, u32 format)
        return 0;
 }
 
+struct array_mode_checker {
+       int array_mode;
+       u32 group_size;
+       u32 nbanks;
+       u32 npipes;
+       u32 nsamples;
+       u32 bpe;
+};
+
+/* returns alignment in pixels for pitch/height/depth and bytes for base */
+static inline int r600_get_array_mode_alignment(struct array_mode_checker *values,
+                                               u32 *pitch_align,
+                                               u32 *height_align,
+                                               u32 *depth_align,
+                                               u64 *base_align)
+{
+       u32 tile_width = 8;
+       u32 tile_height = 8;
+       u32 macro_tile_width = values->nbanks;
+       u32 macro_tile_height = values->npipes;
+       u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples;
+       u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes;
+
+       switch (values->array_mode) {
+       case ARRAY_LINEAR_GENERAL:
+               /* technically tile_width/_height for pitch/height */
+               *pitch_align = 1; /* tile_width */
+               *height_align = 1; /* tile_height */
+               *depth_align = 1;
+               *base_align = 1;
+               break;
+       case ARRAY_LINEAR_ALIGNED:
+               *pitch_align = max((u32)64, (u32)(values->group_size / values->bpe));
+               *height_align = tile_height;
+               *depth_align = 1;
+               *base_align = values->group_size;
+               break;
+       case ARRAY_1D_TILED_THIN1:
+               *pitch_align = max((u32)tile_width,
+                                  (u32)(values->group_size /
+                                        (tile_height * values->bpe * values->nsamples)));
+               *height_align = tile_height;
+               *depth_align = 1;
+               *base_align = values->group_size;
+               break;
+       case ARRAY_2D_TILED_THIN1:
+               *pitch_align = max((u32)macro_tile_width,
+                                 (u32)(((values->group_size / tile_height) /
+                                        (values->bpe * values->nsamples)) *
+                                       values->nbanks)) * tile_width;
+               *height_align = macro_tile_height * tile_height;
+               *depth_align = 1;
+               *base_align = max(macro_tile_bytes,
+                                 (*pitch_align) * values->bpe * (*height_align) * values->nsamples);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static void r600_cs_track_init(struct r600_cs_track *track)
 {
        int i;
@@ -153,10 +217,12 @@ static void r600_cs_track_init(struct r600_cs_track *track)
                track->cb_color_info[i] = 0;
                track->cb_color_bo[i] = NULL;
                track->cb_color_bo_offset[i] = 0xFFFFFFFF;
+               track->cb_color_bo_mc[i] = 0xFFFFFFFF;
        }
        track->cb_target_mask = 0xFFFFFFFF;
        track->cb_shader_mask = 0xFFFFFFFF;
        track->db_bo = NULL;
+       track->db_bo_mc = 0xFFFFFFFF;
        /* assume the biggest format and that htile is enabled */
        track->db_depth_info = 7 | (1 << 25);
        track->db_depth_view = 0xFFFFC000;
@@ -168,7 +234,10 @@ static void r600_cs_track_init(struct r600_cs_track *track)
 static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
 {
        struct r600_cs_track *track = p->track;
-       u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
+       u32 bpe = 0, slice_tile_max, size, tmp;
+       u32 height, height_align, pitch, pitch_align, depth_align;
+       u64 base_offset, base_align;
+       struct array_mode_checker array_check;
        volatile u32 *ib = p->ib->ptr;
        unsigned array_mode;
 
@@ -183,60 +252,40 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                        i, track->cb_color_info[i]);
                return -EINVAL;
        }
-       /* pitch is the number of 8x8 tiles per row */
-       pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
+       /* pitch in pixels */
+       pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8;
        slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
        slice_tile_max *= 64;
-       height = slice_tile_max / (pitch * 8);
+       height = slice_tile_max / pitch;
        if (height > 8192)
                height = 8192;
        array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
+
+       base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i];
+       array_check.array_mode = array_mode;
+       array_check.group_size = track->group_size;
+       array_check.nbanks = track->nbanks;
+       array_check.npipes = track->npipes;
+       array_check.nsamples = track->nsamples;
+       array_check.bpe = bpe;
+       if (r600_get_array_mode_alignment(&array_check,
+                                         &pitch_align, &height_align, &depth_align, &base_align)) {
+               dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
+                        G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
+                        track->cb_color_info[i]);
+               return -EINVAL;
+       }
        switch (array_mode) {
        case V_0280A0_ARRAY_LINEAR_GENERAL:
-               /* technically height & 0x7 */
                break;
        case V_0280A0_ARRAY_LINEAR_ALIGNED:
-               pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
-               if (!IS_ALIGNED(pitch, pitch_align)) {
-                       dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-                                __func__, __LINE__, pitch);
-                       return -EINVAL;
-               }
-               if (!IS_ALIGNED(height, 8)) {
-                       dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-                                __func__, __LINE__, height);
-                       return -EINVAL;
-               }
                break;
        case V_0280A0_ARRAY_1D_TILED_THIN1:
-               pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8;
-               if (!IS_ALIGNED(pitch, pitch_align)) {
-                       dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-                                __func__, __LINE__, pitch);
-                       return -EINVAL;
-               }
                /* avoid breaking userspace */
                if (height > 7)
                        height &= ~0x7;
-               if (!IS_ALIGNED(height, 8)) {
-                       dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-                                __func__, __LINE__, height);
-                       return -EINVAL;
-               }
                break;
        case V_0280A0_ARRAY_2D_TILED_THIN1:
-               pitch_align = max((u32)track->nbanks,
-                                 (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
-               if (!IS_ALIGNED(pitch, pitch_align)) {
-                       dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-                               __func__, __LINE__, pitch);
-                       return -EINVAL;
-               }
-               if (!IS_ALIGNED((height / 8), track->npipes)) {
-                       dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-                                __func__, __LINE__, height);
-                       return -EINVAL;
-               }
                break;
        default:
                dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -244,13 +293,29 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                        track->cb_color_info[i]);
                return -EINVAL;
        }
+
+       if (!IS_ALIGNED(pitch, pitch_align)) {
+               dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+                        __func__, __LINE__, pitch);
+               return -EINVAL;
+       }
+       if (!IS_ALIGNED(height, height_align)) {
+               dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+                        __func__, __LINE__, height);
+               return -EINVAL;
+       }
+       if (!IS_ALIGNED(base_offset, base_align)) {
+               dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+               return -EINVAL;
+       }
+
        /* check offset */
-       tmp = height * pitch * 8 * bpe;
+       tmp = height * pitch * bpe;
        if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
                if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
                        /* the initial DDX does bad things with the CB size occasionally */
                        /* it rounds up height too far for slice tile max but the BO is smaller */
-                       tmp = (height - 7) * 8 * bpe;
+                       tmp = (height - 7) * pitch * bpe;
                        if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
                                dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
                                return -EINVAL;
@@ -260,15 +325,11 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                        return -EINVAL;
                }
        }
-       if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
-               dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
-               return -EINVAL;
-       }
        /* limit max tile */
-       tmp = (height * pitch * 8) >> 6;
+       tmp = (height * pitch) >> 6;
        if (tmp < slice_tile_max)
                slice_tile_max = tmp;
-       tmp = S_028060_PITCH_TILE_MAX(pitch - 1) |
+       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;
        return 0;
@@ -310,7 +371,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
        /* Check depth buffer */
        if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
                G_028800_Z_ENABLE(track->db_depth_control)) {
-               u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max;
+               u32 nviews, bpe, ntiles, size, slice_tile_max;
+               u32 height, height_align, pitch, pitch_align, depth_align;
+               u64 base_offset, base_align;
+               struct array_mode_checker array_check;
+               int array_mode;
+
                if (track->db_bo == NULL) {
                        dev_warn(p->dev, "z/stencil with no depth buffer\n");
                        return -EINVAL;
@@ -353,41 +419,34 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                        ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
                } else {
                        size = radeon_bo_size(track->db_bo);
-                       pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
+                       /* pitch in pixels */
+                       pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
                        slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
                        slice_tile_max *= 64;
-                       height = slice_tile_max / (pitch * 8);
+                       height = slice_tile_max / pitch;
                        if (height > 8192)
                                height = 8192;
-                       switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
+                       base_offset = track->db_bo_mc + track->db_offset;
+                       array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+                       array_check.array_mode = array_mode;
+                       array_check.group_size = track->group_size;
+                       array_check.nbanks = track->nbanks;
+                       array_check.npipes = track->npipes;
+                       array_check.nsamples = track->nsamples;
+                       array_check.bpe = bpe;
+                       if (r600_get_array_mode_alignment(&array_check,
+                                                         &pitch_align, &height_align, &depth_align, &base_align)) {
+                               dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+                                        G_028010_ARRAY_MODE(track->db_depth_info),
+                                        track->db_depth_info);
+                               return -EINVAL;
+                       }
+                       switch (array_mode) {
                        case V_028010_ARRAY_1D_TILED_THIN1:
-                               pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8);
-                               if (!IS_ALIGNED(pitch, pitch_align)) {
-                                       dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
-                                                __func__, __LINE__, pitch);
-                                       return -EINVAL;
-                               }
                                /* don't break userspace */
                                height &= ~0x7;
-                               if (!IS_ALIGNED(height, 8)) {
-                                       dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
-                                                __func__, __LINE__, height);
-                                       return -EINVAL;
-                               }
                                break;
                        case V_028010_ARRAY_2D_TILED_THIN1:
-                               pitch_align = max((u32)track->nbanks,
-                                                 (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
-                               if (!IS_ALIGNED(pitch, pitch_align)) {
-                                       dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
-                                                __func__, __LINE__, pitch);
-                                       return -EINVAL;
-                               }
-                               if (!IS_ALIGNED((height / 8), track->npipes)) {
-                                       dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
-                                                __func__, __LINE__, height);
-                                       return -EINVAL;
-                               }
                                break;
                        default:
                                dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
@@ -395,15 +454,27 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                                         track->db_depth_info);
                                return -EINVAL;
                        }
-                       if (!IS_ALIGNED(track->db_offset, track->group_size)) {
-                               dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset);
+
+                       if (!IS_ALIGNED(pitch, pitch_align)) {
+                               dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+                                        __func__, __LINE__, pitch);
+                               return -EINVAL;
+                       }
+                       if (!IS_ALIGNED(height, height_align)) {
+                               dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+                                        __func__, __LINE__, height);
                                return -EINVAL;
                        }
+                       if (!IS_ALIGNED(base_offset, base_align)) {
+                               dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+                               return -EINVAL;
+                       }
+
                        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;
                        if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
-                               dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
+                               dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
                                                track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
                                                radeon_bo_size(track->db_bo));
                                return -EINVAL;
@@ -954,6 +1025,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
                ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                track->cb_color_base_last[tmp] = ib[idx];
                track->cb_color_bo[tmp] = reloc->robj;
+               track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
                break;
        case DB_DEPTH_BASE:
                r = r600_cs_packet_next_reloc(p, &reloc);
@@ -965,6 +1037,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx
                track->db_offset = radeon_get_ib_value(p, idx) << 8;
                ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                track->db_bo = reloc->robj;
+               track->db_bo_mc = reloc->lobj.gpu_offset;
                break;
        case DB_HTILE_DATA_BASE:
        case SQ_PGM_START_FS:
@@ -1086,16 +1159,25 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
 static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                                              struct radeon_bo *texture,
                                              struct radeon_bo *mipmap,
+                                             u64 base_offset,
+                                             u64 mip_offset,
                                              u32 tiling_flags)
 {
        struct r600_cs_track *track = p->track;
        u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
-       u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align;
+       u32 word0, word1, l0_size, mipmap_size;
+       u32 height_align, pitch, pitch_align, depth_align;
+       u64 base_align;
+       struct array_mode_checker array_check;
 
        /* on legacy kernel we don't perform advanced check */
        if (p->rdev == NULL)
                return 0;
 
+       /* convert to bytes */
+       base_offset <<= 8;
+       mip_offset <<= 8;
+
        word0 = radeon_get_ib_value(p, idx + 0);
        if (tiling_flags & RADEON_TILING_MACRO)
                word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
@@ -1128,46 +1210,38 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
                return -EINVAL;
        }
 
-       pitch = G_038000_PITCH(word0) + 1;
-       switch (G_038000_TILE_MODE(word0)) {
-       case V_038000_ARRAY_LINEAR_GENERAL:
-               pitch_align = 1;
-               /* XXX check height align */
-               break;
-       case V_038000_ARRAY_LINEAR_ALIGNED:
-               pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
-               if (!IS_ALIGNED(pitch, pitch_align)) {
-                       dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-                                __func__, __LINE__, pitch);
-                       return -EINVAL;
-               }
-               /* XXX check height align */
-               break;
-       case V_038000_ARRAY_1D_TILED_THIN1:
-               pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8;
-               if (!IS_ALIGNED(pitch, pitch_align)) {
-                       dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-                                __func__, __LINE__, pitch);
-                       return -EINVAL;
-               }
-               /* XXX check height align */
-               break;
-       case V_038000_ARRAY_2D_TILED_THIN1:
-               pitch_align = max((u32)track->nbanks,
-                                 (u32)(((track->group_size / 8) / bpe) * track->nbanks)) / 8;
-               if (!IS_ALIGNED(pitch, pitch_align)) {
-                       dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-                               __func__, __LINE__, pitch);
-                       return -EINVAL;
-               }
-               /* XXX check height align */
-               break;
-       default:
-               dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
-                        G_038000_TILE_MODE(word0), word0);
+       /* 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.bpe = bpe;
+       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",
+                        __func__, __LINE__, G_038000_TILE_MODE(word0));
+               return -EINVAL;
+       }
+
+       /* XXX check height as well... */
+
+       if (!IS_ALIGNED(pitch, pitch_align)) {
+               dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+                        __func__, __LINE__, pitch);
+               return -EINVAL;
+       }
+       if (!IS_ALIGNED(base_offset, base_align)) {
+               dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
+                        __func__, __LINE__, base_offset);
+               return -EINVAL;
+       }
+       if (!IS_ALIGNED(mip_offset, base_align)) {
+               dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
+                        __func__, __LINE__, mip_offset);
                return -EINVAL;
        }
-       /* XXX check offset align */
 
        word0 = radeon_get_ib_value(p, idx + 4);
        word1 = radeon_get_ib_value(p, idx + 5);
@@ -1402,7 +1476,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
                                mipmap = reloc->robj;
                                r = r600_check_texture_resource(p,  idx+(i*7)+1,
-                                                               texture, mipmap, reloc->lobj.tiling_flags);
+                                                               texture, mipmap,
+                                                               base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),
+                                                               mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3),
+                                                               reloc->lobj.tiling_flags);
                                if (r)
                                        return r;
                                ib[idx+1+(i*7)+2] += base_offset;
index 966a793e225b79a5bfdf3f8bf4c1f413ee2b3dc5..bff4dc4f410f8d5b514539c8ffecd914436a7f90 100644 (file)
 #define PTE_READABLE                           (1 << 5)
 #define PTE_WRITEABLE                          (1 << 6)
 
+/* tiling bits */
+#define     ARRAY_LINEAR_GENERAL              0x00000000
+#define     ARRAY_LINEAR_ALIGNED              0x00000001
+#define     ARRAY_1D_TILED_THIN1              0x00000002
+#define     ARRAY_2D_TILED_THIN1              0x00000004
+
 /* Registers */
 #define        ARB_POP                                         0x2418
 #define        ENABLE_TC128                                    (1 << 30)
index 73f600d39ad4bb79c4dfdeddee97972a8caeaec0..3a7095743d441b1bf71da544bd0f19007408362c 100644 (file)
@@ -1262,6 +1262,10 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
                (rdev->family == CHIP_RS400) ||                 \
                (rdev->family == CHIP_RS480))
 #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
+#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600)  ||   \
+                           (rdev->family == CHIP_RS690)  ||    \
+                           (rdev->family == CHIP_RS740)  ||    \
+                           (rdev->family >= CHIP_R600))
 #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
 #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
 #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR))
index 04cac7ec90397fa7f4f46f9d966fb41b2d3c5368..87ead090c7d5a5195af6cf8d15be5a5809ff9678 100644 (file)
@@ -526,8 +526,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
        if (crev < 2)
                return false;
 
-       router.valid = false;
-
        obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
        path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
            (ctx->bios + data_offset +
@@ -624,6 +622,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                        if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                                continue;
 
+                       router.ddc_valid = false;
+                       router.cd_valid = false;
                        for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
                                uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
 
@@ -647,9 +647,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                                                                 usDeviceTag));
 
                                } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
-                                       router.valid = false;
                                        for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
-                                               u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
+                                               u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
                                                if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
                                                        ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
                                                                (ctx->bios + data_offset +
@@ -657,6 +656,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                                                        ATOM_I2C_RECORD *i2c_record;
                                                        ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
                                                        ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
+                                                       ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
                                                        ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
                                                                (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
                                                                (ctx->bios + data_offset +
@@ -690,10 +690,18 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
                                                                case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
                                                                        ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
                                                                                record;
-                                                                       router.valid = true;
-                                                                       router.mux_type = ddc_path->ucMuxType;
-                                                                       router.mux_control_pin = ddc_path->ucMuxControlPin;
-                                                                       router.mux_state = ddc_path->ucMuxState[enum_id];
+                                                                       router.ddc_valid = true;
+                                                                       router.ddc_mux_type = ddc_path->ucMuxType;
+                                                                       router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
+                                                                       router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
+                                                                       break;
+                                                               case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
+                                                                       cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
+                                                                               record;
+                                                                       router.cd_valid = true;
+                                                                       router.cd_mux_type = cd_path->ucMuxType;
+                                                                       router.cd_mux_control_pin = cd_path->ucMuxControlPin;
+                                                                       router.cd_mux_state = cd_path->ucMuxState[enum_id];
                                                                        break;
                                                                }
                                                                record = (ATOM_COMMON_RECORD_HEADER *)
@@ -860,7 +868,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
        size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
        struct radeon_router router;
 
-       router.valid = false;
+       router.ddc_valid = false;
+       router.cd_valid = false;
 
        bios_connectors = kzalloc(bc_size, GFP_KERNEL);
        if (!bios_connectors)
index 7932dc4d6b90bde396e258108247402ec90ce8ca..c558685cc637698a83fb7ceed220df897f988b44 100644 (file)
@@ -41,7 +41,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
 
        size = bsize;
        n = 1024;
-       r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj);
+       r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj);
        if (r) {
                goto out_cleanup;
        }
@@ -53,7 +53,7 @@ void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
        if (r) {
                goto out_cleanup;
        }
-       r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj);
+       r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj);
        if (r) {
                goto out_cleanup;
        }
index 7b7ea269549ccef95c1e6c343083071774e7e9de..3bddea5b52956fbd9881193bac47827a7024ebe4 100644 (file)
@@ -571,6 +571,7 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
        }
 
        if (clk_mask && data_mask) {
+               /* system specific masks */
                i2c.mask_clk_mask = clk_mask;
                i2c.mask_data_mask = data_mask;
                i2c.a_clk_mask = clk_mask;
@@ -579,7 +580,19 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                i2c.en_data_mask = data_mask;
                i2c.y_clk_mask = clk_mask;
                i2c.y_data_mask = data_mask;
+       } else if ((ddc_line == RADEON_GPIOPAD_MASK) ||
+                  (ddc_line == RADEON_MDGPIO_MASK)) {
+               /* default gpiopad masks */
+               i2c.mask_clk_mask = (0x20 << 8);
+               i2c.mask_data_mask = 0x80;
+               i2c.a_clk_mask = (0x20 << 8);
+               i2c.a_data_mask = 0x80;
+               i2c.en_clk_mask = (0x20 << 8);
+               i2c.en_data_mask = 0x80;
+               i2c.y_clk_mask = (0x20 << 8);
+               i2c.y_data_mask = 0x80;
        } else {
+               /* default masks for ddc pads */
                i2c.mask_clk_mask = RADEON_GPIO_EN_1;
                i2c.mask_data_mask = RADEON_GPIO_EN_0;
                i2c.a_clk_mask = RADEON_GPIO_A_1;
index 4dac4b0a02eea1928837c7009f88e84f227a81f5..3bef9f6d66fd01299efdc62b0581c18f96ca108f 100644 (file)
@@ -183,13 +183,13 @@ radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
                                        continue;
 
                                if (priority == true) {
-                                       DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
-                                       DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
+                                       DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
+                                       DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(connector));
                                        conflict->status = connector_status_disconnected;
                                        radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
                                } else {
-                                       DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
-                                       DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
+                                       DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
+                                       DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(conflict));
                                        current_status = connector_status_disconnected;
                                }
                                break;
@@ -432,13 +432,13 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
                            mode->vdisplay == native_mode->vdisplay) {
                                *native_mode = *mode;
                                drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
-                               DRM_INFO("Determined LVDS native mode details from EDID\n");
+                               DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
                                break;
                        }
                }
        }
        if (!native_mode->clock) {
-               DRM_INFO("No LVDS native mode details, disabling RMX\n");
+               DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
                radeon_encoder->rmx_type = RMX_OFF;
        }
 }
@@ -1008,9 +1008,21 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector)
 static int radeon_dp_get_modes(struct drm_connector *connector)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
        int ret;
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               if (!radeon_dig_connector->edp_on)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
+       }
        ret = radeon_ddc_get_modes(radeon_connector);
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               if (!radeon_dig_connector->edp_on)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_OFF);
+       }
+
        return ret;
 }
 
@@ -1029,8 +1041,14 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
                /* eDP is always DP */
                radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+               if (!radeon_dig_connector->edp_on)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
                if (radeon_dp_getdpcd(radeon_connector))
                        ret = connector_status_connected;
+               if (!radeon_dig_connector->edp_on)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_OFF);
        } else {
                radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
                if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
@@ -1116,7 +1134,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                radeon_connector->shared_ddc = true;
                                shared_ddc = true;
                        }
-                       if (radeon_connector->router_bus && router->valid &&
+                       if (radeon_connector->router_bus && router->ddc_valid &&
                            (radeon_connector->router.router_id == router->router_id)) {
                                radeon_connector->shared_ddc = false;
                                shared_ddc = false;
@@ -1136,7 +1154,7 @@ radeon_add_atom_connector(struct drm_device *dev,
        radeon_connector->connector_object_id = connector_object_id;
        radeon_connector->hpd = *hpd;
        radeon_connector->router = *router;
-       if (router->valid) {
+       if (router->ddc_valid || router->cd_valid) {
                radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
                if (!radeon_connector->router_bus)
                        goto failed;
index 8adfedfe547f6b6455676deaa26dada2592ff6a5..d8ac1849180d5af379d5fe024057447c922d326f 100644 (file)
@@ -180,7 +180,7 @@ int radeon_wb_init(struct radeon_device *rdev)
        int r;
 
        if (rdev->wb.wb_obj == NULL) {
-               r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
+               r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
                                RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
                if (r) {
                        dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
index 0383631da69c42db417f27f6b87ddf58f19eb24e..1df4dc6c063cc44e0e7e943da9b62e6c85d27d38 100644 (file)
@@ -315,10 +315,14 @@ static void radeon_print_display_setup(struct drm_device *dev)
                                 radeon_connector->ddc_bus->rec.en_data_reg,
                                 radeon_connector->ddc_bus->rec.y_clk_reg,
                                 radeon_connector->ddc_bus->rec.y_data_reg);
-                       if (radeon_connector->router_bus)
+                       if (radeon_connector->router.ddc_valid)
                                DRM_INFO("  DDC Router 0x%x/0x%x\n",
-                                        radeon_connector->router.mux_control_pin,
-                                        radeon_connector->router.mux_state);
+                                        radeon_connector->router.ddc_mux_control_pin,
+                                        radeon_connector->router.ddc_mux_state);
+                       if (radeon_connector->router.cd_valid)
+                               DRM_INFO("  Clock/Data Router 0x%x/0x%x\n",
+                                        radeon_connector->router.cd_mux_control_pin,
+                                        radeon_connector->router.cd_mux_state);
                } else {
                        if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
                            connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
@@ -398,8 +402,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
        int ret = 0;
 
        /* on hw with routers, select right port */
-       if (radeon_connector->router.valid)
-               radeon_router_select_port(radeon_connector);
+       if (radeon_connector->router.ddc_valid)
+               radeon_router_select_ddc_port(radeon_connector);
 
        if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
            (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
@@ -432,8 +436,8 @@ static int radeon_ddc_dump(struct drm_connector *connector)
        int ret = 0;
 
        /* on hw with routers, select right port */
-       if (radeon_connector->router.valid)
-               radeon_router_select_port(radeon_connector);
+       if (radeon_connector->router.ddc_valid)
+               radeon_router_select_ddc_port(radeon_connector);
 
        if (!radeon_connector->ddc_bus)
                return -1;
index ae58b6849a2eaa4fd259b88f3d43d2497733161b..041943df966be15803ebedc2e5291fa00953745e 100644 (file)
@@ -176,6 +176,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
                return false;
        }
 }
+
 void
 radeon_link_encoder_connector(struct drm_device *dev)
 {
@@ -228,6 +229,27 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
        return NULL;
 }
 
+struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_encoder *other_encoder;
+       struct radeon_encoder *other_radeon_encoder;
+
+       if (radeon_encoder->is_ext_encoder)
+               return NULL;
+
+       list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+               if (other_encoder == encoder)
+                       continue;
+               other_radeon_encoder = to_radeon_encoder(other_encoder);
+               if (other_radeon_encoder->is_ext_encoder &&
+                   (radeon_encoder->devices & other_radeon_encoder->devices))
+                       return other_encoder;
+       }
+       return NULL;
+}
+
 void radeon_panel_mode_fixup(struct drm_encoder *encoder,
                             struct drm_display_mode *adjusted_mode)
 {
@@ -426,52 +448,49 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
 
 }
 
-void
-atombios_external_tmds_setup(struct drm_encoder *encoder, int action)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args;
-       int index = 0;
-
-       memset(&args, 0, sizeof(args));
-
-       index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
-
-       args.sXTmdsEncoder.ucEnable = action;
-
-       if (radeon_encoder->pixel_clock > 165000)
-               args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
-
-       /*if (pScrn->rgbBits == 8)*/
-       args.sXTmdsEncoder.ucMisc |= (1 << 1);
-
-       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
-}
+union dvo_encoder_control {
+       ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
+       DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
+       DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+};
 
-static void
-atombios_ddia_setup(struct drm_encoder *encoder, int action)
+void
+atombios_dvo_setup(struct drm_encoder *encoder, int action)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       DVO_ENCODER_CONTROL_PS_ALLOCATION args;
-       int index = 0;
+       union dvo_encoder_control args;
+       int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
 
        memset(&args, 0, sizeof(args));
 
-       index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+       if (ASIC_IS_DCE3(rdev)) {
+               /* DCE3+ */
+               args.dvo_v3.ucAction = action;
+               args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+               args.dvo_v3.ucDVOConfig = 0; /* XXX */
+       } else if (ASIC_IS_DCE2(rdev)) {
+               /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */
+               args.dvo.sDVOEncoder.ucAction = action;
+               args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+               /* DFP1, CRT1, TV1 depending on the type of port */
+               args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
+
+               if (radeon_encoder->pixel_clock > 165000)
+                       args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
+       } else {
+               /* R4xx, R5xx */
+               args.ext_tmds.sXTmdsEncoder.ucEnable = action;
 
-       args.sDVOEncoder.ucAction = action;
-       args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+               if (radeon_encoder->pixel_clock > 165000)
+                       args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
 
-       if (radeon_encoder->pixel_clock > 165000)
-               args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
+               /*if (pScrn->rgbBits == 8)*/
+               args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
+       }
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
 }
 
 union lvds_encoder_control {
@@ -532,14 +551,14 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
                                if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
                                        args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
                                if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
-                                       args.v1.ucMisc |= (1 << 1);
+                                       args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
                        } else {
                                if (dig->linkb)
                                        args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
                                if (radeon_encoder->pixel_clock > 165000)
                                        args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
                                /*if (pScrn->rgbBits == 8) */
-                               args.v1.ucMisc |= (1 << 1);
+                               args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
                        }
                        break;
                case 2:
@@ -595,6 +614,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
 int
 atombios_get_encoder_mode(struct drm_encoder *encoder)
 {
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct drm_connector *connector;
@@ -602,9 +622,20 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct radeon_connector_atom_dig *dig_connector;
 
        connector = radeon_get_connector_for_encoder(encoder);
-       if (!connector)
-               return 0;
-
+       if (!connector) {
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+                       return ATOM_ENCODER_MODE_DVI;
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+               default:
+                       return ATOM_ENCODER_MODE_CRT;
+               }
+       }
        radeon_connector = to_radeon_connector(connector);
 
        switch (connector->connector_type) {
@@ -834,6 +865,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        memset(&args, 0, sizeof(args));
 
        switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+               index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+               break;
        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
@@ -978,6 +1012,105 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void
+atombios_set_edp_panel_power(struct drm_connector *connector, int action)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct drm_device *dev = radeon_connector->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       union dig_transmitter_control args;
+       int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+       uint8_t frev, crev;
+
+       if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+               return;
+
+       if (!ASIC_IS_DCE4(rdev))
+               return;
+
+       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+           (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
+               return;
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return;
+
+       memset(&args, 0, sizeof(args));
+
+       args.v1.ucAction = action;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union external_encoder_control {
+       EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
+};
+
+static void
+atombios_external_encoder_setup(struct drm_encoder *encoder,
+                               struct drm_encoder *ext_encoder,
+                               int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       union external_encoder_control args;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
+       u8 frev, crev;
+       int dp_clock = 0;
+       int dp_lane_count = 0;
+       int connector_object_id = 0;
+
+       if (connector) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               struct radeon_connector_atom_dig *dig_connector =
+                       radeon_connector->con_priv;
+
+               dp_clock = dig_connector->dp_clock;
+               dp_lane_count = dig_connector->dp_lane_count;
+               connector_object_id =
+                       (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+       }
+
+       memset(&args, 0, sizeof(args));
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return;
+
+       switch (frev) {
+       case 1:
+               /* no params on frev 1 */
+               break;
+       case 2:
+               switch (crev) {
+               case 1:
+               case 2:
+                       args.v1.sDigEncoder.ucAction = action;
+                       args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+                       args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+                       if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+                               if (dp_clock == 270000)
+                                       args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+                               args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
+                       } else if (radeon_encoder->pixel_clock > 165000)
+                               args.v1.sDigEncoder.ucLaneNum = 8;
+                       else
+                               args.v1.sDigEncoder.ucLaneNum = 4;
+                       break;
+               default:
+                       DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+                       return;
+               }
+               break;
+       default:
+               DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+               return;
+       }
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 static void
 atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
 {
@@ -1021,6 +1154,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
        DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
        int index = 0;
        bool is_dig = false;
@@ -1043,9 +1177,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DVO1:
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
-       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
                index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
                break;
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+               if (ASIC_IS_DCE3(rdev))
+                       is_dig = true;
+               else
+                       index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+               break;
        case ENCODER_OBJECT_ID_INTERNAL_LVDS:
                index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
                break;
@@ -1082,34 +1221,85 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                        if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
                                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
+                               if (connector &&
+                                   (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+                                       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+                                       struct radeon_connector_atom_dig *radeon_dig_connector =
+                                               radeon_connector->con_priv;
+                                       atombios_set_edp_panel_power(connector,
+                                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
+                                       radeon_dig_connector->edp_on = true;
+                               }
                                dp_link_train(encoder, connector);
                                if (ASIC_IS_DCE4(rdev))
                                        atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
                        }
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
                        break;
                case DRM_MODE_DPMS_STANDBY:
                case DRM_MODE_DPMS_SUSPEND:
                case DRM_MODE_DPMS_OFF:
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
                        if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
+                               struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+
                                if (ASIC_IS_DCE4(rdev))
                                        atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+                               if (connector &&
+                                   (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+                                       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+                                       struct radeon_connector_atom_dig *radeon_dig_connector =
+                                               radeon_connector->con_priv;
+                                       atombios_set_edp_panel_power(connector,
+                                                                    ATOM_TRANSMITTER_ACTION_POWER_OFF);
+                                       radeon_dig_connector->edp_on = false;
+                               }
                        }
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
                        break;
                }
        } else {
                switch (mode) {
                case DRM_MODE_DPMS_ON:
                        args.ucAction = ATOM_ENABLE;
+                       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                               args.ucAction = ATOM_LCD_BLON;
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                       }
                        break;
                case DRM_MODE_DPMS_STANDBY:
                case DRM_MODE_DPMS_SUSPEND:
                case DRM_MODE_DPMS_OFF:
                        args.ucAction = ATOM_DISABLE;
+                       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                               args.ucAction = ATOM_LCD_BLOFF;
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+                       }
                        break;
                }
-               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
        }
+
+       if (ext_encoder) {
+               int action;
+
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+               default:
+                       action = ATOM_ENABLE;
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       action = ATOM_DISABLE;
+                       break;
+               }
+               atombios_external_encoder_setup(encoder, ext_encoder, action);
+       }
+
        radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
 
 }
@@ -1242,7 +1432,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
                break;
        default:
                DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
-               break;
+               return;
        }
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -1357,6 +1547,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
 
        radeon_encoder->pixel_clock = adjusted_mode->clock;
 
@@ -1400,11 +1591,9 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                }
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
-               atombios_ddia_setup(encoder, ATOM_ENABLE);
-               break;
        case ENCODER_OBJECT_ID_INTERNAL_DVO1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-               atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+               atombios_dvo_setup(encoder, ATOM_ENABLE);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1419,6 +1608,11 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                }
                break;
        }
+
+       if (ext_encoder) {
+               atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
+       }
+
        atombios_apply_encoder_quirks(encoder, adjusted_mode);
 
        if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
@@ -1520,6 +1714,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
 static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
        if (radeon_encoder->active_device &
            (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
@@ -1531,6 +1726,13 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
        radeon_atom_output_lock(encoder, true);
        radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
+       /* select the clock/data port if it uses a router */
+       if (connector) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               if (radeon_connector->router.cd_valid)
+                       radeon_router_select_cd_port(radeon_connector);
+       }
+
        /* this is needed for the pll/ss setup to work correctly in some cases */
        atombios_set_encoder_crtc_source(encoder);
 }
@@ -1547,6 +1749,23 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig;
+
+       /* check for pre-DCE3 cards with shared encoders;
+        * can't really use the links individually, so don't disable
+        * the encoder if it's in use by another connector
+        */
+       if (!ASIC_IS_DCE3(rdev)) {
+               struct drm_encoder *other_encoder;
+               struct radeon_encoder *other_radeon_encoder;
+
+               list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+                       other_radeon_encoder = to_radeon_encoder(other_encoder);
+                       if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) &&
+                           drm_helper_encoder_in_use(other_encoder))
+                               goto disable_done;
+               }
+       }
+
        radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
        switch (radeon_encoder->encoder_id) {
@@ -1570,11 +1789,9 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
                }
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
-               atombios_ddia_setup(encoder, ATOM_DISABLE);
-               break;
        case ENCODER_OBJECT_ID_INTERNAL_DVO1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-               atombios_external_tmds_setup(encoder, ATOM_DISABLE);
+               atombios_dvo_setup(encoder, ATOM_DISABLE);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1586,6 +1803,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
                break;
        }
 
+disable_done:
        if (radeon_encoder_is_digital(encoder)) {
                if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
                        r600_hdmi_disable(encoder);
@@ -1595,6 +1813,53 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
        radeon_encoder->active_device = 0;
 }
 
+/* these are handled by the primary encoders */
+static void radeon_atom_ext_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void radeon_atom_ext_commit(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_mode_set(struct drm_encoder *encoder,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void radeon_atom_ext_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder,
+                                      struct drm_display_mode *mode,
+                                      struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = {
+       .dpms = radeon_atom_ext_dpms,
+       .mode_fixup = radeon_atom_ext_mode_fixup,
+       .prepare = radeon_atom_ext_prepare,
+       .mode_set = radeon_atom_ext_mode_set,
+       .commit = radeon_atom_ext_commit,
+       .disable = radeon_atom_ext_disable,
+       /* no detect for TMDS/LVDS yet */
+};
+
 static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
        .dpms = radeon_atom_encoder_dpms,
        .mode_fixup = radeon_atom_mode_fixup,
@@ -1704,6 +1969,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
        radeon_encoder->devices = supported_device;
        radeon_encoder->rmx_type = RMX_OFF;
        radeon_encoder->underscan_type = UNDERSCAN_OFF;
+       radeon_encoder->is_ext_encoder = false;
 
        switch (radeon_encoder->encoder_id) {
        case ENCODER_OBJECT_ID_INTERNAL_LVDS:
@@ -1745,6 +2011,9 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
                        radeon_encoder->rmx_type = RMX_FULL;
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
                        radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
+               } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
+                       drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+                       radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
@@ -1753,5 +2022,22 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
+       case ENCODER_OBJECT_ID_SI170B:
+       case ENCODER_OBJECT_ID_CH7303:
+       case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
+       case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
+       case ENCODER_OBJECT_ID_TITFP513:
+       case ENCODER_OBJECT_ID_VT1623:
+       case ENCODER_OBJECT_ID_HDMI_SI1930:
+               /* these are handled by the primary encoders */
+               radeon_encoder->is_ext_encoder = true;
+               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                       drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+               else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+                       drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+               else
+                       drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+               drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs);
+               break;
        }
 }
index 216392d0353bcace87cd2a80d06dda358e285ee4..daacb281dfafea57f26ac258dfbdca3c6d0c0767 100644 (file)
@@ -240,7 +240,8 @@ retry:
                 */
                if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
                        /* good news we believe it's a lockup */
-                       WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
+                       WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n",
+                            fence->seq, seq);
                        /* FIXME: what should we do ? marking everyone
                         * as signaled for now
                         */
index e65b90317fab282df8b97b6b11b277ea867a2647..65016117d95f2f4e332bc6bdd0d9de63e8dbeafe 100644 (file)
@@ -79,8 +79,8 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
 
        if (rdev->gart.table.vram.robj == NULL) {
                r = radeon_bo_create(rdev, NULL, rdev->gart.table_size,
-                                       true, RADEON_GEM_DOMAIN_VRAM,
-                                       &rdev->gart.table.vram.robj);
+                                    PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+                                    &rdev->gart.table.vram.robj);
                if (r) {
                        return r;
                }
index d1e595d9172396b8104d19c7a1d0a87d3b14b772..df95eb83dac6d52e4cad7f6570d6cca9e2807b1f 100644 (file)
@@ -67,7 +67,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size,
        if (alignment < PAGE_SIZE) {
                alignment = PAGE_SIZE;
        }
-       r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj);
+       r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj);
        if (r) {
                if (r != -ERESTARTSYS)
                        DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
index 6a13ee38a5b9fc71201a0a9a38dd93b3ab5957eb..ded2a45bc95cd5f2845b9d32009d98dc00105c5f 100644 (file)
@@ -53,8 +53,8 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
        };
 
        /* on hw with routers, select right port */
-       if (radeon_connector->router.valid)
-               radeon_router_select_port(radeon_connector);
+       if (radeon_connector->router.ddc_valid)
+               radeon_router_select_ddc_port(radeon_connector);
 
        ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
        if (ret == 2)
@@ -896,7 +896,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
             ((rdev->family <= CHIP_RS480) ||
              ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) {
                /* set the radeon hw i2c adapter */
-               sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name);
+               snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+                        "Radeon i2c hw bus %s", name);
                i2c->adapter.algo = &radeon_i2c_algo;
                ret = i2c_add_adapter(&i2c->adapter);
                if (ret) {
@@ -905,7 +906,8 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
                }
        } else {
                /* set the radeon bit adapter */
-               sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name);
+               snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+                        "Radeon i2c bit bus %s", name);
                i2c->adapter.algo_data = &i2c->algo.bit;
                i2c->algo.bit.pre_xfer = pre_xfer;
                i2c->algo.bit.post_xfer = post_xfer;
@@ -946,6 +948,8 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
        i2c->dev = dev;
+       snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+                "Radeon aux bus %s", name);
        i2c_set_adapdata(&i2c->adapter, i2c);
        i2c->adapter.algo_data = &i2c->algo.dp;
        i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch;
@@ -1084,26 +1088,51 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus,
                          addr, val);
 }
 
-/* router switching */
-void radeon_router_select_port(struct radeon_connector *radeon_connector)
+/* ddc router switching */
+void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
 {
        u8 val;
 
-       if (!radeon_connector->router.valid)
+       if (!radeon_connector->router.ddc_valid)
                return;
 
        radeon_i2c_get_byte(radeon_connector->router_bus,
                            radeon_connector->router.i2c_addr,
                            0x3, &val);
-       val &= radeon_connector->router.mux_control_pin;
+       val &= ~radeon_connector->router.ddc_mux_control_pin;
        radeon_i2c_put_byte(radeon_connector->router_bus,
                            radeon_connector->router.i2c_addr,
                            0x3, val);
        radeon_i2c_get_byte(radeon_connector->router_bus,
                            radeon_connector->router.i2c_addr,
                            0x1, &val);
-       val &= radeon_connector->router.mux_control_pin;
-       val |= radeon_connector->router.mux_state;
+       val &= ~radeon_connector->router.ddc_mux_control_pin;
+       val |= radeon_connector->router.ddc_mux_state;
+       radeon_i2c_put_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x1, val);
+}
+
+/* clock/data router switching */
+void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
+{
+       u8 val;
+
+       if (!radeon_connector->router.cd_valid)
+               return;
+
+       radeon_i2c_get_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x3, &val);
+       val &= ~radeon_connector->router.cd_mux_control_pin;
+       radeon_i2c_put_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x3, val);
+       radeon_i2c_get_byte(radeon_connector->router_bus,
+                           radeon_connector->router.i2c_addr,
+                           0x1, &val);
+       val &= ~radeon_connector->router.cd_mux_control_pin;
+       val |= radeon_connector->router.cd_mux_state;
        radeon_i2c_put_byte(radeon_connector->router_bus,
                            radeon_connector->router.i2c_addr,
                            0x1, val);
index 2f349a300195992c9450c9ddd1d6e091eed23ef8..465746bd51b76e4b88cbb1812f7729be430a6da7 100644 (file)
@@ -76,7 +76,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
                default:
                        DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
                                  crtc);
-                       return EINVAL;
+                       return -EINVAL;
                }
        } else {
                switch (crtc) {
@@ -89,7 +89,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
                default:
                        DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
                                  crtc);
-                       return EINVAL;
+                       return -EINVAL;
                }
        }
 
index 0b8397000f4c68ae98e80df717a652cb2ddf6253..59f834ba283dd3fa15dde00b373c6a330d62decc 100644 (file)
@@ -670,7 +670,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
 
        if (rdev->is_atom_bios) {
                radeon_encoder->pixel_clock = adjusted_mode->clock;
-               atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+               atombios_dvo_setup(encoder, ATOM_ENABLE);
                fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
        } else {
                fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
index 92457163d07094dba9bd5975dc63dfb4968e92a6..e301c6f9e0595889a28a4ab99a10e530d41f2112 100644 (file)
@@ -375,6 +375,7 @@ struct radeon_encoder {
        int hdmi_config_offset;
        int hdmi_audio_workaround;
        int hdmi_buffer_status;
+       bool is_ext_encoder;
 };
 
 struct radeon_connector_atom_dig {
@@ -385,6 +386,7 @@ struct radeon_connector_atom_dig {
        u8 dp_sink_type;
        int dp_clock;
        int dp_lane_count;
+       bool edp_on;
 };
 
 struct radeon_gpio_rec {
@@ -401,13 +403,19 @@ struct radeon_hpd {
 };
 
 struct radeon_router {
-       bool valid;
        u32 router_id;
        struct radeon_i2c_bus_rec i2c_info;
        u8 i2c_addr;
-       u8 mux_type;
-       u8 mux_control_pin;
-       u8 mux_state;
+       /* i2c mux */
+       bool ddc_valid;
+       u8 ddc_mux_type;
+       u8 ddc_mux_control_pin;
+       u8 ddc_mux_state;
+       /* clock/data mux */
+       bool cd_valid;
+       u8 cd_mux_type;
+       u8 cd_mux_control_pin;
+       u8 cd_mux_state;
 };
 
 struct radeon_connector {
@@ -488,7 +496,8 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
                                u8 slave_addr,
                                u8 addr,
                                u8 val);
-extern void radeon_router_select_port(struct radeon_connector *radeon_connector);
+extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
+extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
 extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
@@ -516,9 +525,10 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev
 struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv);
 struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index);
 struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
-extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
 extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
 extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
+extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
 extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
 
 extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
index d7ab914164103bdda7bf9ea72e8e35a2c78a5f37..1d067743fee068174e3a5e85eb0e2d47b5b712ee 100644 (file)
@@ -86,11 +86,12 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
 }
 
 int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
-                       unsigned long size, bool kernel, u32 domain,
-                       struct radeon_bo **bo_ptr)
+                    unsigned long size, int byte_align, bool kernel, u32 domain,
+                    struct radeon_bo **bo_ptr)
 {
        struct radeon_bo *bo;
        enum ttm_bo_type type;
+       int page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
        int r;
 
        if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
@@ -102,6 +103,8 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
                type = ttm_bo_type_device;
        }
        *bo_ptr = NULL;
+
+retry:
        bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
        if (bo == NULL)
                return -ENOMEM;
@@ -109,13 +112,11 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
        bo->gobj = gobj;
        bo->surface_reg = -1;
        INIT_LIST_HEAD(&bo->list);
-
-retry:
        radeon_ttm_placement_from_domain(bo, domain);
        /* Kernel allocation are uninterruptible */
        mutex_lock(&rdev->vram_mutex);
        r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
-                       &bo->placement, 0, 0, !kernel, NULL, size,
+                       &bo->placement, page_align, 0, !kernel, NULL, size,
                        &radeon_ttm_bo_destroy);
        mutex_unlock(&rdev->vram_mutex);
        if (unlikely(r != 0)) {
index 3481bc7f6f582b08a0c2a9ff079fa9787defb6cd..d143702b244a4febdd51aa69ca7023e19d692a62 100644 (file)
@@ -137,9 +137,10 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type,
 }
 
 extern int radeon_bo_create(struct radeon_device *rdev,
-                               struct drm_gem_object *gobj, unsigned long size,
-                               bool kernel, u32 domain,
-                               struct radeon_bo **bo_ptr);
+                           struct drm_gem_object *gobj, unsigned long size,
+                           int byte_align,
+                           bool kernel, u32 domain,
+                           struct radeon_bo **bo_ptr);
 extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
 extern void radeon_bo_kunmap(struct radeon_bo *bo);
 extern void radeon_bo_unref(struct radeon_bo **bo);
index 6ea798ce821896dd4b2704461b260578a63a2516..06e79822a2bff74b68fb74793c9ec906ad0834a1 100644 (file)
@@ -176,8 +176,8 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
        INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib);
        /* Allocate 1M object buffer */
        r = radeon_bo_create(rdev, NULL,  RADEON_IB_POOL_SIZE*64*1024,
-                               true, RADEON_GEM_DOMAIN_GTT,
-                               &rdev->ib_pool.robj);
+                            PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
+                            &rdev->ib_pool.robj);
        if (r) {
                DRM_ERROR("radeon: failed to ib pool (%d).\n", r);
                return r;
@@ -332,7 +332,7 @@ int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size)
        rdev->cp.ring_size = ring_size;
        /* Allocate ring buffer */
        if (rdev->cp.ring_obj == NULL) {
-               r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true,
+               r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true,
                                        RADEON_GEM_DOMAIN_GTT,
                                        &rdev->cp.ring_obj);
                if (r) {
index 313c96bc09da1dcfcb0703ed3aa82a2038af0731..5b44f652145c45cb5b1b588fa263fb318739a168 100644 (file)
@@ -52,7 +52,7 @@ void radeon_test_moves(struct radeon_device *rdev)
                goto out_cleanup;
        }
 
-       r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM,
+       r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
                                &vram_obj);
        if (r) {
                DRM_ERROR("Failed to create VRAM object\n");
@@ -71,7 +71,7 @@ void radeon_test_moves(struct radeon_device *rdev)
                void **gtt_start, **gtt_end;
                void **vram_start, **vram_end;
 
-               r = radeon_bo_create(rdev, NULL, size, true,
+               r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true,
                                         RADEON_GEM_DOMAIN_GTT, gtt_obj + i);
                if (r) {
                        DRM_ERROR("Failed to create GTT object %d\n", i);
index fe95bb35317ea26c2cabe33fc0bae285bfc32cef..1272e4b6a1d45469add57610a397c213704d5446 100644 (file)
@@ -529,7 +529,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
        }
-       r = radeon_bo_create(rdev, NULL, 256 * 1024, true,
+       r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true,
                                RADEON_GEM_DOMAIN_VRAM,
                                &rdev->stollen_vga_memory);
        if (r) {
@@ -689,7 +689,8 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend,
        gtt = container_of(backend, struct radeon_ttm_backend, backend);
        gtt->offset = bo_mem->start << PAGE_SHIFT;
        if (!gtt->num_pages) {
-               WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend);
+               WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
+                    gtt->num_pages, bo_mem, backend);
        }
        r = radeon_gart_bind(gtt->rdev, gtt->offset,
                             gtt->num_pages, gtt->pages);
index f683e51a2a0674518b476d6a2157b39a303170a6..5512e4e5e636ebb91ea73e99d63a4e60bb95bbe6 100644 (file)
@@ -78,7 +78,7 @@ int rs400_gart_init(struct radeon_device *rdev)
        int r;
 
        if (rdev->gart.table.ram.ptr) {
-               WARN(1, "RS400 GART already initialized.\n");
+               WARN(1, "RS400 GART already initialized\n");
                return 0;
        }
        /* Check gart size */
index b091a1f6fa4ed2b86dc1975717abbf017667c251..f1c6e02c2e6b41f18338688b1dc9d49b33dbe8bb 100644 (file)
@@ -375,7 +375,7 @@ int rs600_gart_init(struct radeon_device *rdev)
        int r;
 
        if (rdev->gart.table.vram.robj) {
-               WARN(1, "RS600 GART already initialized.\n");
+               WARN(1, "RS600 GART already initialized\n");
                return 0;
        }
        /* Initialize common gart structure */
@@ -505,7 +505,7 @@ int rs600_irq_set(struct radeon_device *rdev)
                ~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
 
        if (!rdev->irq.installed) {
-               WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+               WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
                WREG32(R_000040_GEN_INT_CNTL, 0);
                return -EINVAL;
        }
index 245374e2b778b7706e9bf828c8a65876c1e11a00..4dfead8cee33907ae025c9c58adede92c12db4f6 100644 (file)
@@ -915,8 +915,8 @@ static int rv770_vram_scratch_init(struct radeon_device *rdev)
 
        if (rdev->vram_scratch.robj == NULL) {
                r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE,
-                                       true, RADEON_GEM_DOMAIN_VRAM,
-                                       &rdev->vram_scratch.robj);
+                                    PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+                                    &rdev->vram_scratch.robj);
                if (r) {
                        return r;
                }
index a1cb783c7131c56de8aa19cf5afb6a668e5e4345..148a322d8f5d7c45d0487351635f89eb9a9a0949 100644 (file)
 /*
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
-/* Notes:
- *
- * We store bo pointer in drm_mm_node struct so we know which bo own a
- * specific node. There is no protection on the pointer, thus to make
- * sure things don't go berserk you have to access this pointer while
- * holding the global lru lock and make sure anytime you free a node you
- * reset the pointer to NULL.
- */
 
 #include "ttm/ttm_module.h"
 #include "ttm/ttm_bo_driver.h"
@@ -45,6 +37,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/module.h>
+#include <asm/atomic.h>
 
 #define TTM_ASSERT_LOCKED(param)
 #define TTM_DEBUG(fmt, arg...)
@@ -231,6 +224,9 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
        int ret;
 
        while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
+               /**
+                * Deadlock avoidance for multi-bo reserving.
+                */
                if (use_sequence && bo->seq_valid &&
                        (sequence - bo->val_seq < (1 << 31))) {
                        return -EAGAIN;
@@ -248,6 +244,14 @@ int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
        }
 
        if (use_sequence) {
+               /**
+                * Wake up waiters that may need to recheck for deadlock,
+                * if we decreased the sequence number.
+                */
+               if (unlikely((bo->val_seq - sequence < (1 << 31))
+                            || !bo->seq_valid))
+                       wake_up_all(&bo->event_queue);
+
                bo->val_seq = sequence;
                bo->seq_valid = true;
        } else {
@@ -452,6 +456,11 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
        ttm_bo_mem_put(bo, &bo->mem);
 
        atomic_set(&bo->reserved, 0);
+
+       /*
+        * Make processes trying to reserve really pick it up.
+        */
+       smp_mb__after_atomic_dec();
        wake_up_all(&bo->event_queue);
 }
 
@@ -460,7 +469,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_bo_global *glob = bo->glob;
        struct ttm_bo_driver *driver;
-       void *sync_obj;
+       void *sync_obj = NULL;
        void *sync_obj_arg;
        int put_count;
        int ret;
@@ -495,17 +504,20 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
                spin_lock(&glob->lru_lock);
        }
 queue:
-       sync_obj = bo->sync_obj;
-       sync_obj_arg = bo->sync_obj_arg;
        driver = bdev->driver;
+       if (bo->sync_obj)
+               sync_obj = driver->sync_obj_ref(bo->sync_obj);
+       sync_obj_arg = bo->sync_obj_arg;
 
        kref_get(&bo->list_kref);
        list_add_tail(&bo->ddestroy, &bdev->ddestroy);
        spin_unlock(&glob->lru_lock);
        spin_unlock(&bo->lock);
 
-       if (sync_obj)
+       if (sync_obj) {
                driver->sync_obj_flush(sync_obj, sync_obj_arg);
+               driver->sync_obj_unref(&sync_obj);
+       }
        schedule_delayed_work(&bdev->wq,
                              ((HZ / 100) < 1) ? 1 : HZ / 100);
 }
@@ -822,7 +834,6 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
                                        bool no_wait_gpu)
 {
        struct ttm_bo_device *bdev = bo->bdev;
-       struct ttm_bo_global *glob = bdev->glob;
        struct ttm_mem_type_manager *man = &bdev->man[mem_type];
        int ret;
 
@@ -832,12 +843,6 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
                        return ret;
                if (mem->mm_node)
                        break;
-               spin_lock(&glob->lru_lock);
-               if (list_empty(&man->lru)) {
-                       spin_unlock(&glob->lru_lock);
-                       break;
-               }
-               spin_unlock(&glob->lru_lock);
                ret = ttm_mem_evict_first(bdev, mem_type, interruptible,
                                                no_wait_reserve, no_wait_gpu);
                if (unlikely(ret != 0))
@@ -1125,35 +1130,9 @@ EXPORT_SYMBOL(ttm_bo_validate);
 int ttm_bo_check_placement(struct ttm_buffer_object *bo,
                                struct ttm_placement *placement)
 {
-       int i;
+       BUG_ON((placement->fpfn || placement->lpfn) &&
+              (bo->mem.num_pages > (placement->lpfn - placement->fpfn)));
 
-       if (placement->fpfn || placement->lpfn) {
-               if (bo->mem.num_pages > (placement->lpfn - placement->fpfn)) {
-                       printk(KERN_ERR TTM_PFX "Page number range to small "
-                               "Need %lu pages, range is [%u, %u]\n",
-                               bo->mem.num_pages, placement->fpfn,
-                               placement->lpfn);
-                       return -EINVAL;
-               }
-       }
-       for (i = 0; i < placement->num_placement; i++) {
-               if (!capable(CAP_SYS_ADMIN)) {
-                       if (placement->placement[i] & TTM_PL_FLAG_NO_EVICT) {
-                               printk(KERN_ERR TTM_PFX "Need to be root to "
-                                       "modify NO_EVICT status.\n");
-                               return -EINVAL;
-                       }
-               }
-       }
-       for (i = 0; i < placement->num_busy_placement; i++) {
-               if (!capable(CAP_SYS_ADMIN)) {
-                       if (placement->busy_placement[i] & TTM_PL_FLAG_NO_EVICT) {
-                               printk(KERN_ERR TTM_PFX "Need to be root to "
-                                       "modify NO_EVICT status.\n");
-                               return -EINVAL;
-                       }
-               }
-       }
        return 0;
 }
 
@@ -1176,6 +1155,10 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
        num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
        if (num_pages == 0) {
                printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n");
+               if (destroy)
+                       (*destroy)(bo);
+               else
+                       kfree(bo);
                return -EINVAL;
        }
        bo->destroy = destroy;
@@ -1369,18 +1352,9 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
        int ret = -EINVAL;
        struct ttm_mem_type_manager *man;
 
-       if (type >= TTM_NUM_MEM_TYPES) {
-               printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", type);
-               return ret;
-       }
-
+       BUG_ON(type >= TTM_NUM_MEM_TYPES);
        man = &bdev->man[type];
-       if (man->has_type) {
-               printk(KERN_ERR TTM_PFX
-                      "Memory manager already initialized for type %d\n",
-                      type);
-               return ret;
-       }
+       BUG_ON(man->has_type);
 
        ret = bdev->driver->init_mem_type(bdev, type, man);
        if (ret)
@@ -1389,13 +1363,6 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
 
        ret = 0;
        if (type != TTM_PL_SYSTEM) {
-               if (!p_size) {
-                       printk(KERN_ERR TTM_PFX
-                              "Zero size memory manager type %d\n",
-                              type);
-                       return ret;
-               }
-
                ret = (*man->func->init)(man, p_size);
                if (ret)
                        return ret;
index 7410c190c8911a9342ba57ea616d77a722061312..038e947d00f986ef987ef914fd8432f2202c25f3 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 #include "ttm/ttm_module.h"
 #include "ttm/ttm_bo_driver.h"
 #include "ttm/ttm_placement.h"
-#include <linux/jiffies.h>
+#include "drm_mm.h"
 #include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/file.h>
+#include <linux/spinlock.h>
 #include <linux/module.h>
 
+/**
+ * Currently we use a spinlock for the lock, but a mutex *may* be
+ * more appropriate to reduce scheduling latency if the range manager
+ * ends up with very fragmented allocation patterns.
+ */
+
+struct ttm_range_manager {
+       struct drm_mm mm;
+       spinlock_t lock;
+};
+
 static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
                               struct ttm_buffer_object *bo,
                               struct ttm_placement *placement,
                               struct ttm_mem_reg *mem)
 {
-       struct ttm_bo_global *glob = man->bdev->glob;
-       struct drm_mm *mm = man->priv;
+       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+       struct drm_mm *mm = &rman->mm;
        struct drm_mm_node *node = NULL;
        unsigned long lpfn;
        int ret;
@@ -57,19 +66,19 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
                if (unlikely(ret))
                        return ret;
 
-               spin_lock(&glob->lru_lock);
+               spin_lock(&rman->lock);
                node = drm_mm_search_free_in_range(mm,
                                        mem->num_pages, mem->page_alignment,
                                        placement->fpfn, lpfn, 1);
                if (unlikely(node == NULL)) {
-                       spin_unlock(&glob->lru_lock);
+                       spin_unlock(&rman->lock);
                        return 0;
                }
                node = drm_mm_get_block_atomic_range(node, mem->num_pages,
-                                                       mem->page_alignment,
-                                                       placement->fpfn,
-                                                       lpfn);
-               spin_unlock(&glob->lru_lock);
+                                                    mem->page_alignment,
+                                                    placement->fpfn,
+                                                    lpfn);
+               spin_unlock(&rman->lock);
        } while (node == NULL);
 
        mem->mm_node = node;
@@ -80,12 +89,12 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
 static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
                                struct ttm_mem_reg *mem)
 {
-       struct ttm_bo_global *glob = man->bdev->glob;
+       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
 
        if (mem->mm_node) {
-               spin_lock(&glob->lru_lock);
+               spin_lock(&rman->lock);
                drm_mm_put_block(mem->mm_node);
-               spin_unlock(&glob->lru_lock);
+               spin_unlock(&rman->lock);
                mem->mm_node = NULL;
        }
 }
@@ -93,49 +102,49 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
 static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
                           unsigned long p_size)
 {
-       struct drm_mm *mm;
+       struct ttm_range_manager *rman;
        int ret;
 
-       mm = kzalloc(sizeof(*mm), GFP_KERNEL);
-       if (!mm)
+       rman = kzalloc(sizeof(*rman), GFP_KERNEL);
+       if (!rman)
                return -ENOMEM;
 
-       ret = drm_mm_init(mm, 0, p_size);
+       ret = drm_mm_init(&rman->mm, 0, p_size);
        if (ret) {
-               kfree(mm);
+               kfree(rman);
                return ret;
        }
 
-       man->priv = mm;
+       spin_lock_init(&rman->lock);
+       man->priv = rman;
        return 0;
 }
 
 static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
 {
-       struct ttm_bo_global *glob = man->bdev->glob;
-       struct drm_mm *mm = man->priv;
-       int ret = 0;
+       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+       struct drm_mm *mm = &rman->mm;
 
-       spin_lock(&glob->lru_lock);
+       spin_lock(&rman->lock);
        if (drm_mm_clean(mm)) {
                drm_mm_takedown(mm);
-               kfree(mm);
+               spin_unlock(&rman->lock);
+               kfree(rman);
                man->priv = NULL;
-       } else
-               ret = -EBUSY;
-       spin_unlock(&glob->lru_lock);
-       return ret;
+               return 0;
+       }
+       spin_unlock(&rman->lock);
+       return -EBUSY;
 }
 
 static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
                             const char *prefix)
 {
-       struct ttm_bo_global *glob = man->bdev->glob;
-       struct drm_mm *mm = man->priv;
+       struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
 
-       spin_lock(&glob->lru_lock);
-       drm_mm_debug_table(mm, prefix);
-       spin_unlock(&glob->lru_lock);
+       spin_lock(&rman->lock);
+       drm_mm_debug_table(&rman->mm, prefix);
+       spin_unlock(&rman->lock);
 }
 
 const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
index a7bab87a548bd25de465d5fff45436a177346e33..af789dc869b94e997621ff615c184383c857377c 100644 (file)
@@ -440,10 +440,8 @@ int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
                return ret;
 
        ret = be->func->bind(be, bo_mem);
-       if (ret) {
-               printk(KERN_ERR TTM_PFX "Couldn't bind backend.\n");
+       if (unlikely(ret != 0))
                return ret;
-       }
 
        ttm->state = tt_bound;
 
index 9b5b4d9dd62c9fceffe9c5fa0dd218ff7119d5a7..3e038a394c510efd6194618a7f3a1f185380f7fc 100644 (file)
@@ -235,9 +235,9 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg,  drm_via_dmablit_t *xfer)
        vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) -
                first_pfn + 1;
 
-       if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
+       vsg->pages = vzalloc(sizeof(struct page *) * vsg->num_pages);
+       if (NULL == vsg->pages)
                return -ENOMEM;
-       memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
        down_read(&current->mm->mmap_sem);
        ret = get_user_pages(current, current->mm,
                             (unsigned long)xfer->mem_addr,
index 51d9f9f1d7f2aa1b2ea04f309569d71bd9244600..76954e3528c1d6ccb763973c22b7f7979ad4f1b4 100644 (file)
@@ -691,6 +691,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
 
        fence_rep.error = ret;
        fence_rep.fence_seq = (uint64_t) sequence;
+       fence_rep.pad64 = 0;
 
        user_fence_rep = (struct drm_vmw_fence_rep __user *)
            (unsigned long)arg->fence_rep;
index 87c6e6156d7de8bc809a62bab06dbf64a7da512b..cceeb42789b655e82e5431d9810b9fa033f883fd 100644 (file)
@@ -720,6 +720,8 @@ static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb)
                               &vmw_vram_ne_placement,
                               false, &vmw_dmabuf_bo_free);
        vmw_overlay_resume_all(dev_priv);
+       if (unlikely(ret != 0))
+               vfbs->buffer = NULL;
 
        return ret;
 }
@@ -730,6 +732,9 @@ static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb)
        struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(&vfb->base);
 
+       if (unlikely(vfbs->buffer == NULL))
+               return 0;
+
        bo = &vfbs->buffer->base;
        ttm_bo_unref(&bo);
        vfbs->buffer = NULL;
index a01c47ddb5bc724617b74c15ad3bffc2ed63067f..29113c9b26a8c01cc217cc82906e98a83a8fa36c 100644 (file)
@@ -557,7 +557,7 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
                return -EINVAL;
        }
 
-       dev_priv->ldu_priv = kmalloc(GFP_KERNEL, sizeof(*dev_priv->ldu_priv));
+       dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL);
 
        if (!dev_priv->ldu_priv)
                return -ENOMEM;
index df2036ed18d5f2c920ba61f99b716998a6f25329..f1a52f9e72988da041c77f19b1035f5b3f160592 100644 (file)
@@ -585,7 +585,7 @@ int vmw_overlay_init(struct vmw_private *dev_priv)
                return -ENOSYS;
        }
 
-       overlay = kmalloc(GFP_KERNEL, sizeof(*overlay));
+       overlay = kmalloc(sizeof(*overlay), GFP_KERNEL);
        if (!overlay)
                return -ENOMEM;
 
index 36e129f0023ffc3d6407b9c0251376aa3fc9f5c0..5408b1b7996f054dee95b9ed5aac4e9d63ee99a1 100644 (file)
@@ -862,7 +862,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
                              &vmw_vram_sys_placement, true,
                              &vmw_user_dmabuf_destroy);
        if (unlikely(ret != 0))
-               return ret;
+               goto out_no_dmabuf;
 
        tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
        ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
@@ -870,19 +870,21 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
                                   false,
                                   ttm_buffer_type,
                                   &vmw_user_dmabuf_release, NULL);
-       if (unlikely(ret != 0)) {
-               ttm_bo_unref(&tmp);
-       else {
+       if (unlikely(ret != 0))
+               goto out_no_base_object;
+       else {
                rep->handle = vmw_user_bo->base.hash.key;
                rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
                rep->cur_gmr_id = vmw_user_bo->base.hash.key;
                rep->cur_gmr_offset = 0;
        }
-       ttm_bo_unref(&tmp);
 
+out_no_base_object:
+       ttm_bo_unref(&tmp);
+out_no_dmabuf:
        ttm_read_unlock(&vmaster->lock);
 
-       return 0;
+       return ret;
 }
 
 int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
index 742c423567cf180e0b46da6477924ac5c7fdcac7..0e1edd7311ff72f5805b8ee616edbe59d52472d1 100644 (file)
@@ -3,6 +3,9 @@ config STUB_POULSBO
        depends on PCI
        # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
+       select VIDEO_OUTPUT_CONTROL if ACPI
+       select BACKLIGHT_CLASS_DEVICE if ACPI
+       select INPUT if ACPI
        select ACPI_VIDEO if ACPI
        help
          Choose this option if you have a system that has Intel GMA500
index 8a4b32dca9f74fd03621f3deffe0912929ee5cf3..e1f07483691f7823b46db14c38dc0d8daa536a13 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/hid.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 #include <linux/hidraw.h>
 
index fedd88df9a18477de2699cb07e48feade407312f..984feb351a5a3205de716fdb68ad9e5f983bdadd 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
index 1e4c21fc1a890b38894e26f0b0713fef1bb0fd63..86d822aa9bbf78a75ff20d1e4bff1bb0623d3a79 100644 (file)
@@ -178,11 +178,13 @@ static int ad7414_probe(struct i2c_client *client,
 {
        struct ad7414_data *data;
        int conf;
-       int err = 0;
+       int err;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-                                    I2C_FUNC_SMBUS_READ_WORD_DATA))
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+               err = -EOPNOTSUPP;
                goto exit;
+       }
 
        data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
        if (!data) {
index 9e775717abb7f36ab8c7aaf8103de53264e95951..87d92a56a939fcc531c934a1dd70f6ab6f83ab0c 100644 (file)
@@ -1286,8 +1286,10 @@ static int adt7470_probe(struct i2c_client *client,
        init_completion(&data->auto_update_stop);
        data->auto_update = kthread_run(adt7470_update_thread, client,
                                        dev_name(data->hwmon_dev));
-       if (IS_ERR(data->auto_update))
+       if (IS_ERR(data->auto_update)) {
+               err = PTR_ERR(data->auto_update);
                goto exit_unregister;
+       }
 
        return 0;
 
index fa9708c2d723d27b52eece60e6a2c525ee65246c..4033974d1bb371223a51e61a17d5c29b9b9a0fa5 100644 (file)
@@ -4,7 +4,7 @@
        Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
 
        Based on max6650.c:
-       Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
+       Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
 
        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
index aa701a18370793a080a40be5e865465e83820159..f141a1de519cb2af822deef686229734c6d94249 100644 (file)
@@ -376,10 +376,6 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
                }
        }
 
-       err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
-       if (err)
-               goto err_free_gpio;
-
        fan_data->num_ctrl = num_ctrl;
        fan_data->ctrl = ctrl;
        fan_data->num_speed = pdata->num_speed;
@@ -391,6 +387,10 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
                goto err_free_gpio;
        }
 
+       err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+       if (err)
+               goto err_free_gpio;
+
        return 0;
 
 err_free_gpio:
index 6669255aadcfcefc783c01f0c345a72b411f70c9..c9ed14eba5a69eb3af13e750d4f563190234a76b 100644 (file)
@@ -20,7 +20,7 @@
     Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
         Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
 
-    Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+    Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
         Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
 
     This program is free software; you can redistribute it and/or modify
@@ -2629,7 +2629,7 @@ static void __exit lm93_exit(void)
 }
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
-               "Hans J. Koch <hjk@linutronix.de");
+               "Hans J. Koch <hjk@hansjkoch.de>");
 MODULE_DESCRIPTION("LM93 driver");
 MODULE_LICENSE("GPL");
 
index 464340f25496402dd15a69e2d59281544e267c37..4546d82f024a4c2acacf3c6d93e0ad2a4a4bf3e6 100644 (file)
@@ -128,9 +128,12 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm95241_data *data = i2c_get_clientdata(client);
+       unsigned long val;
 
-       strict_strtol(buf, 10, &data->interval);
-       data->interval = data->interval * HZ / 1000;
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       data->interval = val * HZ / 1000;
 
        return count;
 }
@@ -188,7 +191,9 @@ static ssize_t set_type##flag(struct device *dev, \
        struct lm95241_data *data = i2c_get_clientdata(client); \
 \
        long val; \
-       strict_strtol(buf, 10, &val); \
+\
+       if (strict_strtol(buf, 10, &val) < 0) \
+               return -EINVAL; \
 \
        if ((val == 1) || (val == 2)) { \
 \
@@ -227,7 +232,9 @@ static ssize_t set_min##flag(struct device *dev, \
        struct lm95241_data *data = i2c_get_clientdata(client); \
 \
        long val; \
-       strict_strtol(buf, 10, &val); \
+\
+       if (strict_strtol(buf, 10, &val) < 0) \
+               return -EINVAL;\
 \
        mutex_lock(&data->update_lock); \
 \
@@ -256,7 +263,9 @@ static ssize_t set_max##flag(struct device *dev, \
        struct lm95241_data *data = i2c_get_clientdata(client); \
 \
        long val; \
-       strict_strtol(buf, 10, &val); \
+\
+       if (strict_strtol(buf, 10, &val) < 0) \
+               return -EINVAL; \
 \
        mutex_lock(&data->update_lock); \
 \
index 267626178678363882ad14d01e96122ccfbfe2d2..4b50601027d3f4787249651c8d58da5126603f12 100644 (file)
@@ -82,7 +82,7 @@ static struct ltc4261_data *ltc4261_update_device(struct device *dev)
                        val = i2c_smbus_read_byte_data(client, i);
                        if (unlikely(val < 0)) {
                                dev_dbg(dev,
-                                       "Failed to read ADC value: error %d",
+                                       "Failed to read ADC value: error %d\n",
                                        val);
                                ret = ERR_PTR(val);
                                goto abort;
@@ -230,8 +230,7 @@ static int ltc4261_probe(struct i2c_client *client,
                return -ENODEV;
 
        if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
-               dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
-                       adapter->id, client->addr, LTC4261_STATUS);
+               dev_err(&client->dev, "Failed to read status register\n");
                return -ENODEV;
        }
 
index a0160ee5caeffcefc6d7da22a7513a13b32fcf43..9a11532ecae84384d105e1f2c0b070a5107c0c3c 100644 (file)
@@ -2,7 +2,7 @@
  * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
  *             monitoring.
  *
- * (C) 2007 by Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
  *
  * based on code written by John Morris <john.morris@spirentcom.com>
  * Copyright (c) 2003 Spirent Communications
index 1d840aa837823a9b0ee6e6f2fe84f7af950d26a8..cdbc7448491e127d8c11e599b57314625010b261 100644 (file)
@@ -165,10 +165,14 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = {
 
 #define W83795_REG_VID_CTRL            0x6A
 
+#define W83795_REG_ALARM_CTRL          0x40
+#define ALARM_CTRL_RTSACS              (1 << 7)
 #define W83795_REG_ALARM(index)                (0x41 + (index))
+#define W83795_REG_CLR_CHASSIS         0x4D
 #define W83795_REG_BEEP(index)         (0x50 + (index))
 
-#define W83795_REG_CLR_CHASSIS         0x4D
+#define W83795_REG_OVT_CFG             0x58
+#define OVT_CFG_SEL                    (1 << 7)
 
 
 #define W83795_REG_FCMS1               0x201
@@ -178,6 +182,14 @@ static const u8 IN_LSB_SHIFT_IDX[][2] = {
 
 #define W83795_REG_TSS(index)          (0x209 + (index))
 
+#define TSS_MAP_RESERVED               0xff
+static const u8 tss_map[4][6] = {
+       { 0,  1,  2,  3,  4,  5},
+       { 6,  7,  8,  9,  0,  1},
+       {10, 11, 12, 13,  2,  3},
+       { 4,  5,  4,  5, TSS_MAP_RESERVED, TSS_MAP_RESERVED},
+};
+
 #define PWM_OUTPUT                     0
 #define PWM_FREQ                       1
 #define PWM_START                      2
@@ -369,6 +381,7 @@ struct w83795_data {
        u8 setup_pwm[3];        /* Register value */
 
        u8 alarms[6];           /* Register value */
+       u8 enable_beep;
        u8 beeps[6];            /* Register value */
 
        char valid;
@@ -499,8 +512,11 @@ static void w83795_update_limits(struct i2c_client *client)
        }
 
        /* Read beep settings */
-       for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
-               data->beeps[i] = w83795_read(client, W83795_REG_BEEP(i));
+       if (data->enable_beep) {
+               for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
+                       data->beeps[i] =
+                               w83795_read(client, W83795_REG_BEEP(i));
+       }
 
        data->valid_limits = 1;
 }
@@ -577,6 +593,7 @@ static struct w83795_data *w83795_update_device(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct w83795_data *data = i2c_get_clientdata(client);
        u16 tmp;
+       u8 intrusion;
        int i;
 
        mutex_lock(&data->update_lock);
@@ -648,9 +665,24 @@ static struct w83795_data *w83795_update_device(struct device *dev)
                    w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
        }
 
-       /* update alarm */
+       /* Update intrusion and alarms
+        * It is important to read intrusion first, because reading from
+        * register SMI STS6 clears the interrupt status temporarily. */
+       tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
+       /* Switch to interrupt status for intrusion if needed */
+       if (tmp & ALARM_CTRL_RTSACS)
+               w83795_write(client, W83795_REG_ALARM_CTRL,
+                            tmp & ~ALARM_CTRL_RTSACS);
+       intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6);
+       /* Switch to real-time alarms */
+       w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS);
        for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
                data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i));
+       data->alarms[5] |= intrusion;
+       /* Restore original configuration if needed */
+       if (!(tmp & ALARM_CTRL_RTSACS))
+               w83795_write(client, W83795_REG_ALARM_CTRL,
+                            tmp & ~ALARM_CTRL_RTSACS);
 
        data->last_updated = jiffies;
        data->valid = 1;
@@ -730,6 +762,10 @@ store_chassis_clear(struct device *dev,
        val = w83795_read(client, W83795_REG_CLR_CHASSIS);
        val |= 0x80;
        w83795_write(client, W83795_REG_CLR_CHASSIS, val);
+
+       /* Clear status and force cache refresh */
+       w83795_read(client, W83795_REG_ALARM(5));
+       data->valid = 0;
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -857,20 +893,20 @@ show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
        int index = sensor_attr->index;
        u8 tmp;
 
-       if (1 == (data->pwm_fcms[0] & (1 << index))) {
+       /* Speed cruise mode */
+       if (data->pwm_fcms[0] & (1 << index)) {
                tmp = 2;
                goto out;
        }
+       /* Thermal cruise or SmartFan IV mode */
        for (tmp = 0; tmp < 6; tmp++) {
                if (data->pwm_tfmr[tmp] & (1 << index)) {
                        tmp = 3;
                        goto out;
                }
        }
-       if (data->pwm_fomc & (1 << index))
-               tmp = 0;
-       else
-               tmp = 1;
+       /* Manual mode */
+       tmp = 1;
 
 out:
        return sprintf(buf, "%u\n", tmp);
@@ -890,23 +926,21 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
 
        if (strict_strtoul(buf, 10, &val) < 0)
                return -EINVAL;
-       if (val > 2)
+       if (val < 1 || val > 2)
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
        switch (val) {
-       case 0:
        case 1:
+               /* Clear speed cruise mode bits */
                data->pwm_fcms[0] &= ~(1 << index);
                w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
+               /* Clear thermal cruise mode bits */
                for (i = 0; i < 6; i++) {
                        data->pwm_tfmr[i] &= ~(1 << index);
                        w83795_write(client, W83795_REG_TFMR(i),
                                data->pwm_tfmr[i]);
                }
-               data->pwm_fomc |= 1 << index;
-               data->pwm_fomc ^= val << index;
-               w83795_write(client, W83795_REG_FOMC, data->pwm_fomc);
                break;
        case 2:
                data->pwm_fcms[0] |= (1 << index);
@@ -917,6 +951,42 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct w83795_data *data = w83795_update_pwm_config(dev);
+       int index = to_sensor_dev_attr_2(attr)->index;
+       unsigned int mode;
+
+       if (data->pwm_fomc & (1 << index))
+               mode = 0;       /* DC */
+       else
+               mode = 1;       /* PWM */
+
+       return sprintf(buf, "%u\n", mode);
+}
+
+/*
+ * Check whether a given temperature source can ever be useful.
+ * Returns the number of selectable temperature channels which are
+ * enabled.
+ */
+static int w83795_tss_useful(const struct w83795_data *data, int tsrc)
+{
+       int useful = 0, i;
+
+       for (i = 0; i < 4; i++) {
+               if (tss_map[i][tsrc] == TSS_MAP_RESERVED)
+                       continue;
+               if (tss_map[i][tsrc] < 6)       /* Analog */
+                       useful += (data->has_temp >> tss_map[i][tsrc]) & 1;
+               else                            /* Digital */
+                       useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1;
+       }
+
+       return useful;
+}
+
 static ssize_t
 show_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -924,17 +994,18 @@ show_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
            to_sensor_dev_attr_2(attr);
        struct w83795_data *data = w83795_update_pwm_config(dev);
        int index = sensor_attr->index;
-       u8 val = index / 2;
-       u8 tmp = data->temp_src[val];
+       u8 tmp = data->temp_src[index / 2];
 
        if (index & 1)
-               val = 4;
+               tmp >>= 4;      /* Pick high nibble */
        else
-               val = 0;
-       tmp >>= val;
-       tmp &= 0x0f;
+               tmp &= 0x0f;    /* Pick low nibble */
 
-       return sprintf(buf, "%u\n", tmp);
+       /* Look-up the actual temperature channel number */
+       if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED)
+               return -EINVAL;         /* Shouldn't happen */
+
+       return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1);
 }
 
 static ssize_t
@@ -946,12 +1017,21 @@ store_temp_src(struct device *dev, struct device_attribute *attr,
        struct sensor_device_attribute_2 *sensor_attr =
            to_sensor_dev_attr_2(attr);
        int index = sensor_attr->index;
-       unsigned long tmp;
+       int tmp;
+       unsigned long channel;
        u8 val = index / 2;
 
-       if (strict_strtoul(buf, 10, &tmp) < 0)
+       if (strict_strtoul(buf, 10, &channel) < 0 ||
+           channel < 1 || channel > 14)
+               return -EINVAL;
+
+       /* Check if request can be fulfilled */
+       for (tmp = 0; tmp < 4; tmp++) {
+               if (tss_map[tmp][index] == channel - 1)
+                       break;
+       }
+       if (tmp == 4)   /* No match */
                return -EINVAL;
-       tmp = SENSORS_LIMIT(tmp, 0, 15);
 
        mutex_lock(&data->update_lock);
        if (index & 1) {
@@ -1515,7 +1595,7 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
 
 #define NOT_USED                       -1
 
-/* Don't change the attribute order, _max and _min are accessed by index
+/* Don't change the attribute order, _max, _min and _beep are accessed by index
  * somewhere else in the code */
 #define SENSOR_ATTR_IN(index) {                                                \
        SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,        \
@@ -1530,6 +1610,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
                show_alarm_beep, store_beep, BEEP_ENABLE,               \
                index + ((index > 14) ? 1 : 0)) }
 
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
 #define SENSOR_ATTR_FAN(index) {                                       \
        SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,            \
                NULL, FAN_INPUT, index - 1), \
@@ -1553,9 +1635,13 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
                show_pwm, store_pwm, PWM_FREQ, index - 1),       \
        SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,           \
                show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+       SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,                       \
+               show_pwm_mode, NULL, NOT_USED, index - 1),              \
        SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
                show_fanin, store_fanin, FANIN_TARGET, index - 1) }
 
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
 #define SENSOR_ATTR_DTS(index) {                                       \
        SENSOR_ATTR_2(temp##index##_type, S_IRUGO ,             \
                show_dts_mode, NULL, NOT_USED, index - 7),      \
@@ -1574,6 +1660,8 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
        SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,            \
                show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
 
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
 #define SENSOR_ATTR_TEMP(index) {                                      \
        SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
                show_temp_mode, store_temp_mode, NOT_USED, index - 1),  \
@@ -1593,8 +1681,6 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
        SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,            \
                show_alarm_beep, store_beep, BEEP_ENABLE,               \
                index + (index > 4 ? 11 : 17)),                         \
-       SENSOR_ATTR_2(temp##index##_source_sel, S_IWUSR | S_IRUGO,      \
-               show_temp_src, store_temp_src, NOT_USED, index - 1),    \
        SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO,      \
                show_temp_pwm_enable, store_temp_pwm_enable,            \
                TEMP_PWM_ENABLE, index - 1),                            \
@@ -1680,7 +1766,7 @@ static const struct sensor_device_attribute_2 w83795_fan[][4] = {
        SENSOR_ATTR_FAN(14),
 };
 
-static const struct sensor_device_attribute_2 w83795_temp[][29] = {
+static const struct sensor_device_attribute_2 w83795_temp[][28] = {
        SENSOR_ATTR_TEMP(1),
        SENSOR_ATTR_TEMP(2),
        SENSOR_ATTR_TEMP(3),
@@ -1700,7 +1786,7 @@ static const struct sensor_device_attribute_2 w83795_dts[][8] = {
        SENSOR_ATTR_DTS(14),
 };
 
-static const struct sensor_device_attribute_2 w83795_pwm[][7] = {
+static const struct sensor_device_attribute_2 w83795_pwm[][8] = {
        SENSOR_ATTR_PWM(1),
        SENSOR_ATTR_PWM(2),
        SENSOR_ATTR_PWM(3),
@@ -1711,13 +1797,24 @@ static const struct sensor_device_attribute_2 w83795_pwm[][7] = {
        SENSOR_ATTR_PWM(8),
 };
 
+static const struct sensor_device_attribute_2 w83795_tss[6] = {
+       SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO,
+                     show_temp_src, store_temp_src, NOT_USED, 0),
+       SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO,
+                     show_temp_src, store_temp_src, NOT_USED, 1),
+       SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO,
+                     show_temp_src, store_temp_src, NOT_USED, 2),
+       SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO,
+                     show_temp_src, store_temp_src, NOT_USED, 3),
+       SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO,
+                     show_temp_src, store_temp_src, NOT_USED, 4),
+       SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO,
+                     show_temp_src, store_temp_src, NOT_USED, 5),
+};
+
 static const struct sensor_device_attribute_2 sda_single_files[] = {
        SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
                      store_chassis_clear, ALARM_STATUS, 46),
-       SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
-                     store_beep, BEEP_ENABLE, 46),
-       SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
-                     store_beep, BEEP_ENABLE, 47),
 #ifdef CONFIG_SENSORS_W83795_FANCTRL
        SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin,
                store_fanin, FANIN_TOL, NOT_USED),
@@ -1730,6 +1827,13 @@ static const struct sensor_device_attribute_2 sda_single_files[] = {
 #endif
 };
 
+static const struct sensor_device_attribute_2 sda_beep_files[] = {
+       SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
+                     store_beep, BEEP_ENABLE, 46),
+       SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
+                     store_beep, BEEP_ENABLE, 47),
+};
+
 /*
  * Driver interface
  */
@@ -1859,6 +1963,8 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
                if (!(data->has_in & (1 << i)))
                        continue;
                for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) {
+                       if (j == 4 && !data->enable_beep)
+                               continue;
                        err = fn(dev, &w83795_in[i][j].dev_attr);
                        if (err)
                                return err;
@@ -1869,18 +1975,37 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
                if (!(data->has_fan & (1 << i)))
                        continue;
                for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) {
+                       if (j == 3 && !data->enable_beep)
+                               continue;
                        err = fn(dev, &w83795_fan[i][j].dev_attr);
                        if (err)
                                return err;
                }
        }
 
+       for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) {
+               j = w83795_tss_useful(data, i);
+               if (!j)
+                       continue;
+               err = fn(dev, &w83795_tss[i].dev_attr);
+               if (err)
+                       return err;
+       }
+
        for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
                err = fn(dev, &sda_single_files[i].dev_attr);
                if (err)
                        return err;
        }
 
+       if (data->enable_beep) {
+               for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) {
+                       err = fn(dev, &sda_beep_files[i].dev_attr);
+                       if (err)
+                               return err;
+               }
+       }
+
 #ifdef CONFIG_SENSORS_W83795_FANCTRL
        for (i = 0; i < data->has_pwm; i++) {
                for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) {
@@ -1899,6 +2024,8 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
 #else
                for (j = 0; j < 8; j++) {
 #endif
+                       if (j == 7 && !data->enable_beep)
+                               continue;
                        err = fn(dev, &w83795_temp[i][j].dev_attr);
                        if (err)
                                return err;
@@ -1910,6 +2037,8 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
                        if (!(data->has_dts & (1 << i)))
                                continue;
                        for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) {
+                               if (j == 7 && !data->enable_beep)
+                                       continue;
                                err = fn(dev, &w83795_dts[i][j].dev_attr);
                                if (err)
                                        return err;
@@ -2049,6 +2178,18 @@ static int w83795_probe(struct i2c_client *client,
        else
                data->has_pwm = 2;
 
+       /* Check if BEEP pin is available */
+       if (data->chip_type == w83795g) {
+               /* The W83795G has a dedicated BEEP pin */
+               data->enable_beep = 1;
+       } else {
+               /* The W83795ADG has a shared pin for OVT# and BEEP, so you
+                * can't have both */
+               tmp = w83795_read(client, W83795_REG_OVT_CFG);
+               if ((tmp & OVT_CFG_SEL) == 0)
+                       data->enable_beep = 1;
+       }
+
        err = w83795_handle_files(dev, device_create_file);
        if (err)
                goto exit_remove;
index d231f683f5763bc286e98200fc46286b35ef65a6..6b4cc567645b4e9d936b47bc0c777a05dc9222b9 100644 (file)
@@ -848,6 +848,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                goto out_list;
        }
 
+       /* Sanity checks */
+       if (unlikely(adap->name[0] == '\0')) {
+               pr_err("i2c-core: Attempt to register an adapter with "
+                      "no name!\n");
+               return -EINVAL;
+       }
+       if (unlikely(!adap->algo)) {
+               pr_err("i2c-core: Attempt to register adapter '%s' with "
+                      "no algo!\n", adap->name);
+               return -EINVAL;
+       }
+
        rt_mutex_init(&adap->bus_lock);
        mutex_init(&adap->userspace_clients_lock);
        INIT_LIST_HEAD(&adap->userspace_clients);
index d32a4843fc3a2b0c502b11a0dcd32d6cf6ebf1b0..d7a4833be4161d37bd4883dfa474b068224ab466 100644 (file)
@@ -120,7 +120,6 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
        snprintf(priv->adap.name, sizeof(priv->adap.name),
                 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
        priv->adap.owner = THIS_MODULE;
-       priv->adap.id = parent->id;
        priv->adap.algo = &priv->algo;
        priv->adap.algo_data = priv;
        priv->adap.dev.parent = &parent->dev;
index 6078992da3f04d6de686838c46ccfd61f6f43922..9292a15ad7c4885b3920724eeeb27b9765051bc4 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/highmem.h>
 #include <linux/io.h>
 #include <linux/jiffies.h>
-#include <linux/smp_lock.h>
 #include <asm/pgtable.h>
 
 #include "ipath_kernel.h"
index cfc1d65c4577bf4ed2ce07bc2ea1924f406bd445..1e1e347a771531aa767f912a5fe38d3c2f2ac2dc 100644 (file)
@@ -1123,7 +1123,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
        }
 }
 
-static int srp_queuecommand(struct scsi_cmnd *scmnd,
+static int srp_queuecommand_lck(struct scsi_cmnd *scmnd,
                            void (*done)(struct scsi_cmnd *))
 {
        struct srp_target_port *target = host_to_target(scmnd->device->host);
@@ -1196,6 +1196,8 @@ err:
        return SCSI_MLQUEUE_HOST_BUSY;
 }
 
+static DEF_SCSI_QCMD(srp_queuecommand)
+
 static int srp_alloc_iu_bufs(struct srp_target_port *target)
 {
        int i;
index d092ef9291dabe1301006bc94310bc1973037808..db409d6bd5d2b9672ad94f370564f870bed25b19 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/rcupdate.h>
-#include <linux/smp_lock.h>
 #include "input-compat.h"
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -74,6 +73,7 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
+                            struct input_handler *src_handler,
                             unsigned int type, unsigned int code, int value)
 {
        struct input_handler *handler;
@@ -92,6 +92,15 @@ static void input_pass_event(struct input_dev *dev,
                                continue;
 
                        handler = handle->handler;
+
+                       /*
+                        * If this is the handler that injected this
+                        * particular event we want to skip it to avoid
+                        * filters firing again and again.
+                        */
+                       if (handler == src_handler)
+                               continue;
+
                        if (!handler->filter) {
                                if (filtered)
                                        break;
@@ -121,7 +130,7 @@ static void input_repeat_key(unsigned long data)
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
 
-               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+               input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
 
                if (dev->sync) {
                        /*
@@ -130,7 +139,7 @@ static void input_repeat_key(unsigned long data)
                         * Otherwise assume that the driver will send
                         * SYN_REPORT once it's done.
                         */
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
                }
 
                if (dev->rep[REP_PERIOD])
@@ -163,6 +172,7 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
+                                 struct input_handler *src_handler,
                                  unsigned int code, int *pval)
 {
        bool is_mt_event;
@@ -206,13 +216,15 @@ static int input_handle_abs_event(struct input_dev *dev,
        /* Flush pending "slot" event */
        if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
                input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+               input_pass_event(dev, src_handler,
+                                EV_ABS, ABS_MT_SLOT, dev->slot);
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
 static void input_handle_event(struct input_dev *dev,
+                              struct input_handler *src_handler,
                               unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
@@ -265,7 +277,8 @@ static void input_handle_event(struct input_dev *dev,
 
        case EV_ABS:
                if (is_event_supported(code, dev->absbit, ABS_MAX))
-                       disposition = input_handle_abs_event(dev, code, &value);
+                       disposition = input_handle_abs_event(dev, src_handler,
+                                                            code, &value);
 
                break;
 
@@ -323,7 +336,7 @@ static void input_handle_event(struct input_dev *dev,
                dev->event(dev, type, code, value);
 
        if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, type, code, value);
+               input_pass_event(dev, src_handler, type, code, value);
 }
 
 /**
@@ -352,7 +365,7 @@ void input_event(struct input_dev *dev,
 
                spin_lock_irqsave(&dev->event_lock, flags);
                add_input_randomness(type, code, value);
-               input_handle_event(dev, type, code, value);
+               input_handle_event(dev, NULL, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 }
@@ -382,7 +395,8 @@ void input_inject_event(struct input_handle *handle,
                rcu_read_lock();
                grab = rcu_dereference(dev->grab);
                if (!grab || grab == handle)
-                       input_handle_event(dev, type, code, value);
+                       input_handle_event(dev, handle->handler,
+                                          type, code, value);
                rcu_read_unlock();
 
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -595,10 +609,10 @@ static void input_dev_release_keys(struct input_dev *dev)
                for (code = 0; code <= KEY_MAX; code++) {
                        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
                            __test_and_clear_bit(code, dev->key)) {
-                               input_pass_event(dev, EV_KEY, code, 0);
+                               input_pass_event(dev, NULL, EV_KEY, code, 0);
                        }
                }
-               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+               input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
        }
 }
 
@@ -738,7 +752,7 @@ static int input_default_setkeycode(struct input_dev *dev,
        if (index >= dev->keycodemax)
                return -EINVAL;
 
-       if (dev->keycodesize < sizeof(dev->keycode) &&
+       if (dev->keycodesize < sizeof(ke->keycode) &&
                        (ke->keycode >> (dev->keycodesize * 8)))
                return -EINVAL;
 
@@ -873,9 +887,9 @@ int input_set_keycode(struct input_dev *dev,
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
 
-               input_pass_event(dev, EV_KEY, old_keycode, 0);
+               input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
                if (dev->sync)
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
        }
 
  out:
@@ -1565,8 +1579,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
                }                                                       \
        } while (0)
 
-#ifdef CONFIG_PM
-static void input_dev_reset(struct input_dev *dev, bool activate)
+static void input_dev_toggle(struct input_dev *dev, bool activate)
 {
        if (!dev->event)
                return;
@@ -1580,12 +1593,44 @@ static void input_dev_reset(struct input_dev *dev, bool activate)
        }
 }
 
+/**
+ * input_reset_device() - reset/restore the state of input device
+ * @dev: input device whose state needs to be reset
+ *
+ * This function tries to reset the state of an opened input device and
+ * bring internal state and state if the hardware in sync with each other.
+ * We mark all keys as released, restore LED state, repeat rate, etc.
+ */
+void input_reset_device(struct input_dev *dev)
+{
+       mutex_lock(&dev->mutex);
+
+       if (dev->users) {
+               input_dev_toggle(dev, true);
+
+               /*
+                * Keys that have been pressed at suspend time are unlikely
+                * to be still pressed when we resume.
+                */
+               spin_lock_irq(&dev->event_lock);
+               input_dev_release_keys(dev);
+               spin_unlock_irq(&dev->event_lock);
+       }
+
+       mutex_unlock(&dev->mutex);
+}
+EXPORT_SYMBOL(input_reset_device);
+
+#ifdef CONFIG_PM
 static int input_dev_suspend(struct device *dev)
 {
        struct input_dev *input_dev = to_input_dev(dev);
 
        mutex_lock(&input_dev->mutex);
-       input_dev_reset(input_dev, false);
+
+       if (input_dev->users)
+               input_dev_toggle(input_dev, false);
+
        mutex_unlock(&input_dev->mutex);
 
        return 0;
@@ -1595,18 +1640,7 @@ static int input_dev_resume(struct device *dev)
 {
        struct input_dev *input_dev = to_input_dev(dev);
 
-       mutex_lock(&input_dev->mutex);
-       input_dev_reset(input_dev, true);
-
-       /*
-        * Keys that have been pressed at suspend time are unlikely
-        * to be still pressed when we resume.
-        */
-       spin_lock_irq(&input_dev->event_lock);
-       input_dev_release_keys(input_dev);
-       spin_unlock_irq(&input_dev->event_lock);
-
-       mutex_unlock(&input_dev->mutex);
+       input_reset_device(input_dev);
 
        return 0;
 }
index b92d1cd5cba1e4ee83923b7bce43c80a7075f5b8..af45d275f6862924979f48def9b1aa43ece095eb 100644 (file)
@@ -4,7 +4,7 @@
  *              I2C QWERTY Keypad and IO Expander
  * Bugs: Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (C) 2008-2009 Analog Devices Inc.
+ * Copyright (C) 2008-2010 Analog Devices Inc.
  * Licensed under the GPL-2 or later.
  */
 
 
 #include <linux/i2c/adp5588.h>
 
- /* Configuration Register1 */
-#define AUTO_INC       (1 << 7)
-#define GPIEM_CFG      (1 << 6)
-#define OVR_FLOW_M     (1 << 5)
-#define INT_CFG                (1 << 4)
-#define OVR_FLOW_IEN   (1 << 3)
-#define K_LCK_IM       (1 << 2)
-#define GPI_IEN                (1 << 1)
-#define KE_IEN         (1 << 0)
-
-/* Interrupt Status Register */
-#define CMP2_INT       (1 << 5)
-#define CMP1_INT       (1 << 4)
-#define OVR_FLOW_INT   (1 << 3)
-#define K_LCK_INT      (1 << 2)
-#define GPI_INT                (1 << 1)
-#define KE_INT         (1 << 0)
-
-/* Key Lock and Event Counter Register */
-#define K_LCK_EN       (1 << 6)
-#define LCK21          0x30
-#define KEC            0xF
-
 /* Key Event Register xy */
 #define KEY_EV_PRESSED         (1 << 7)
 #define KEY_EV_MASK            (0x7F)
 
 #define KEYP_MAX_EVENT         10
 
-#define MAXGPIO                        18
-#define ADP_BANK(offs)         ((offs) >> 3)
-#define ADP_BIT(offs)          (1u << ((offs) & 0x7))
-
 /*
  * Early pre 4.0 Silicon required to delay readout by at least 25ms,
  * since the Event Counter Register updated 25ms after the interrupt
@@ -75,7 +48,7 @@ struct adp5588_kpad {
        const struct adp5588_gpi_map *gpimap;
        unsigned short gpimapsize;
 #ifdef CONFIG_GPIOLIB
-       unsigned char gpiomap[MAXGPIO];
+       unsigned char gpiomap[ADP5588_MAXGPIO];
        bool export_gpio;
        struct gpio_chip gc;
        struct mutex gpio_lock; /* Protect cached dir, dat_out */
@@ -103,8 +76,8 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
 static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
 
        return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
 }
@@ -113,8 +86,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
                                   unsigned off, int val)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
 
        mutex_lock(&kpad->gpio_lock);
 
@@ -132,8 +105,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
 static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
        int ret;
 
        mutex_lock(&kpad->gpio_lock);
@@ -150,8 +123,8 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
                                         unsigned off, int val)
 {
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
-       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
-       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
        int ret;
 
        mutex_lock(&kpad->gpio_lock);
@@ -176,7 +149,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
 static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
                                const struct adp5588_kpad_platform_data *pdata)
 {
-       bool pin_used[MAXGPIO];
+       bool pin_used[ADP5588_MAXGPIO];
        int n_unused = 0;
        int i;
 
@@ -191,7 +164,7 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
        for (i = 0; i < kpad->gpimapsize; i++)
                pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
 
-       for (i = 0; i < MAXGPIO; i++)
+       for (i = 0; i < ADP5588_MAXGPIO; i++)
                if (!pin_used[i])
                        kpad->gpiomap[n_unused++] = i;
 
@@ -234,7 +207,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
                return error;
        }
 
-       for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+       for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
                kpad->dat_out[i] = adp5588_read(kpad->client,
                                                GPIO_DAT_OUT1 + i);
                kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
@@ -318,11 +291,11 @@ static void adp5588_work(struct work_struct *work)
 
        status = adp5588_read(client, INT_STAT);
 
-       if (status & OVR_FLOW_INT)      /* Unlikely and should never happen */
+       if (status & ADP5588_OVR_FLOW_INT)      /* Unlikely and should never happen */
                dev_err(&client->dev, "Event Overflow Error\n");
 
-       if (status & KE_INT) {
-               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
+       if (status & ADP5588_KE_INT) {
+               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & ADP5588_KEC;
                if (ev_cnt) {
                        adp5588_report_events(kpad, ev_cnt);
                        input_sync(kpad->input);
@@ -360,7 +333,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        if (pdata->en_keylock) {
                ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
                ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
-               ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
+               ret |= adp5588_write(client, KEY_LCK_EC_STAT, ADP5588_K_LCK_EN);
        }
 
        for (i = 0; i < KEYP_MAX_EVENT; i++)
@@ -384,7 +357,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        }
 
        if (gpio_data) {
-               for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+               for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
                        int pull_mask = gpio_data->pullup_dis_mask;
 
                        ret |= adp5588_write(client, GPIO_PULL1 + i,
@@ -392,11 +365,14 @@ static int __devinit adp5588_setup(struct i2c_client *client)
                }
        }
 
-       ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
-                                       OVR_FLOW_INT | K_LCK_INT |
-                                       GPI_INT | KE_INT); /* Status is W1C */
+       ret |= adp5588_write(client, INT_STAT,
+                               ADP5588_CMP2_INT | ADP5588_CMP1_INT |
+                               ADP5588_OVR_FLOW_INT | ADP5588_K_LCK_INT |
+                               ADP5588_GPI_INT | ADP5588_KE_INT); /* Status is W1C */
 
-       ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);
+       ret |= adp5588_write(client, CFG, ADP5588_INT_CFG |
+                                         ADP5588_OVR_FLOW_IEN |
+                                         ADP5588_KE_IEN);
 
        if (ret < 0) {
                dev_err(&client->dev, "Write Error\n");
index d358ef8623f490709875b901d82580b1afc7a7fc..11478eb2c27de1ec332b8f3e4a5b1a56408b49ce 100644 (file)
@@ -63,6 +63,10 @@ static bool atkbd_extra;
 module_param_named(extra, atkbd_extra, bool, 0);
 MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
 
+static bool atkbd_terminal;
+module_param_named(terminal, atkbd_terminal, bool, 0);
+MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
+
 /*
  * Scancode to keycode tables. These are just the default setting, and
  * are loadable via a userland utility.
@@ -136,7 +140,8 @@ static const unsigned short atkbd_unxlate_table[128] = {
 #define ATKBD_CMD_ENABLE       0x00f4
 #define ATKBD_CMD_RESET_DIS    0x00f5  /* Reset to defaults and disable */
 #define ATKBD_CMD_RESET_DEF    0x00f6  /* Reset to defaults */
-#define ATKBD_CMD_SETALL_MBR   0x00fa
+#define ATKBD_CMD_SETALL_MB    0x00f8  /* Set all keys to give break codes */
+#define ATKBD_CMD_SETALL_MBR   0x00fa  /* ... and repeat */
 #define ATKBD_CMD_RESET_BAT    0x02ff
 #define ATKBD_CMD_RESEND       0x00fe
 #define ATKBD_CMD_EX_ENABLE    0x10ea
@@ -764,6 +769,11 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
                }
        }
 
+       if (atkbd_terminal) {
+               ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
+               return 3;
+       }
+
        if (target_set != 3)
                return 2;
 
index 4b42ffc0532af1c6a3b36ca64ab411decfac89d9..d1583aea17212b72e4b30f69c5a640d42652dfe2 100644 (file)
@@ -127,14 +127,6 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
        idev->id.product = 0x0001;
        idev->id.version = 0x0100;
 
-       input_set_drvdata(idev, lp);
-
-       ret = input_register_device(idev);
-       if (ret) {
-               dev_err(&client->dev, "input_register_device() failed\n");
-               goto fail_register;
-       }
-
        lp->laststate = read_state(lp);
 
        ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
@@ -142,16 +134,21 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
                                   DRV_NAME, lp);
        if (ret) {
                dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
-               goto fail_irq;
+               goto fail_free_device;
+       }
+
+       ret = input_register_device(idev);
+       if (ret) {
+               dev_err(&client->dev, "input_register_device() failed\n");
+               goto fail_free_irq;
        }
 
        i2c_set_clientdata(client, lp);
        return 0;
 
- fail_irq:
-       input_unregister_device(idev);
- fail_register:
-       input_set_drvdata(idev, NULL);
+ fail_free_irq:
+       free_irq(client->irq, lp);
+ fail_free_device:
        input_free_device(idev);
  fail_allocate:
        kfree(lp);
index ed7ad7416b24d8f40c9cccd61d8371f732b73441..a5475b5770863298609f7ab40850e03286529046 100644 (file)
@@ -350,6 +350,17 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
                },
        },
+       {
+               /*
+                * Most (all?) VAIOs do not have external PS/2 ports nor
+                * they implement active multiplexing properly, and
+                * MUX discovery usually messes up keyboard/touchpad.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
+               },
+       },
        {
                /* Amoi M636/A737 */
                .matches = {
index cd82bb12591593be230f06fbf89aa2a52f6b73b2..b7ba4597f7f0256a7fb4f14b76894a3b76f0ccb6 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/serio.h>
index aea9a9399a36b43a18663b4fd46d8bd3c7303808..d94f7e9aa997f13cbafba7739d59a234bf117726 100644 (file)
@@ -229,12 +229,13 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
 
        err = input_register_device(acecad->input);
        if (err)
-               goto fail2;
+               goto fail3;
 
        usb_set_intfdata(intf, acecad);
 
        return 0;
 
+ fail3:        usb_free_urb(acecad->irq);
  fail2:        usb_free_coherent(dev, 8, acecad->data, acecad->data_dma);
  fail1: input_free_device(input_dev);
        kfree(acecad);
index 57b25b84d1fcfded0408788dbd8cbd2d0dcb3e8f..0a619c558bfb40a8223c94301462d6387f7dc388 100644 (file)
@@ -1097,7 +1097,7 @@ store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const
 }
 
 static DEVICE_ATTR(pointer_mode,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletPointerMode, store_tabletPointerMode);
 
 /***********************************************************************
@@ -1134,7 +1134,7 @@ store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, co
 }
 
 static DEVICE_ATTR(coordinate_mode,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletCoordinateMode, store_tabletCoordinateMode);
 
 /***********************************************************************
@@ -1176,7 +1176,7 @@ store_tabletToolMode(struct device *dev, struct device_attribute *attr, const ch
 }
 
 static DEVICE_ATTR(tool_mode,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletToolMode, store_tabletToolMode);
 
 /***********************************************************************
@@ -1219,7 +1219,7 @@ store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char
 }
 
 static DEVICE_ATTR(xtilt,
-                  S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
+                  S_IRUGO | S_IWUSR, show_tabletXtilt, store_tabletXtilt);
 
 /***********************************************************************
  * support routines for the 'ytilt' file. Note that this file
@@ -1261,7 +1261,7 @@ store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char
 }
 
 static DEVICE_ATTR(ytilt,
-                  S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
+                  S_IRUGO | S_IWUSR, show_tabletYtilt, store_tabletYtilt);
 
 /***********************************************************************
  * support routines for the 'jitter' file. Note that this file
@@ -1288,7 +1288,7 @@ store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const
 }
 
 static DEVICE_ATTR(jitter,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletJitterDelay, store_tabletJitterDelay);
 
 /***********************************************************************
@@ -1317,7 +1317,7 @@ store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr,
 }
 
 static DEVICE_ATTR(delay,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletProgrammableDelay, store_tabletProgrammableDelay);
 
 /***********************************************************************
@@ -1406,7 +1406,7 @@ store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const
 }
 
 static DEVICE_ATTR(stylus_upper,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletStylusUpper, store_tabletStylusUpper);
 
 /***********************************************************************
@@ -1437,7 +1437,7 @@ store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const
 }
 
 static DEVICE_ATTR(stylus_lower,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletStylusLower, store_tabletStylusLower);
 
 /***********************************************************************
@@ -1475,7 +1475,7 @@ store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const c
 }
 
 static DEVICE_ATTR(mouse_left,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletMouseLeft, store_tabletMouseLeft);
 
 /***********************************************************************
@@ -1505,7 +1505,7 @@ store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const
 }
 
 static DEVICE_ATTR(mouse_middle,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletMouseMiddle, store_tabletMouseMiddle);
 
 /***********************************************************************
@@ -1535,7 +1535,7 @@ store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const
 }
 
 static DEVICE_ATTR(mouse_right,
-                  S_IRUGO | S_IWUGO,
+                  S_IRUGO | S_IWUSR,
                   show_tabletMouseRight, store_tabletMouseRight);
 
 /***********************************************************************
@@ -1567,7 +1567,7 @@ store_tabletWheel(struct device *dev, struct device_attribute *attr, const char
 }
 
 static DEVICE_ATTR(wheel,
-                  S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
+                  S_IRUGO | S_IWUSR, show_tabletWheel, store_tabletWheel);
 
 /***********************************************************************
  * support routines for the 'execute' file. Note that this file
@@ -1600,7 +1600,7 @@ store_tabletExecute(struct device *dev, struct device_attribute *attr, const cha
 }
 
 static DEVICE_ATTR(execute,
-                  S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
+                  S_IRUGO | S_IWUSR, show_tabletExecute, store_tabletExecute);
 
 /***********************************************************************
  * support routines for the 'odm_code' file. Note that this file
index 40b914bded8c2a3237abca74d295d8d80a02b2e3..2e72227bd071b9d18329e60a0e4b06a444700ec9 100644 (file)
@@ -1427,8 +1427,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
                                        &bcs->hw.isar.reg->Flags))
                                        bcs->hw.isar.dpath = 1;
                                else {
-                                       printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
-                                       debugl1(cs, "isar modeisar analog funktions only with DP1");
+                                       printk(KERN_WARNING"isar modeisar analog functions only with DP1\n");
+                                       debugl1(cs, "isar modeisar analog functions only with DP1");
                                        return(1);
                                }
                                break;
index cc2a88d5192fbb359f3027082c0843ad34055d97..77b8fd20cd9046b8e0c785c041c7569285aa6043 100644 (file)
@@ -10,7 +10,7 @@ menuconfig NEW_LEDS
 if NEW_LEDS
 
 config LEDS_CLASS
-       tristate "LED Class Support"
+       bool "LED Class Support"
        help
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
@@ -176,6 +176,24 @@ config LEDS_LP3944
          To compile this driver as a module, choose M here: the
          module will be called leds-lp3944.
 
+config LEDS_LP5521
+       tristate "LED Support for N.S. LP5521 LED driver chip"
+       depends on LEDS_CLASS && I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LP5521 LED driver. It is 3 channel chip with programmable engines.
+         Driver provides direct control via LED class and interface for
+         programming the engines.
+
+config LEDS_LP5523
+       tristate "LED Support for N.S. LP5523 LED driver chip"
+       depends on LEDS_CLASS && I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LP5523 LED driver. It is 9 channel chip with programmable engines.
+         Driver provides direct control via LED class and interface for
+         programming the engines.
+
 config LEDS_CLEVO_MAIL
        tristate "Mail LED on Clevo notebook"
        depends on X86 && SERIO_I8042 && DMI
index 9c96db40ef6d7d3a12f776ab4d764371a71026a5..aae6989ff6b63445e6b6c974df537f0f0784fe3f 100644 (file)
@@ -23,6 +23,8 @@ obj-$(CONFIG_LEDS_SUNFIRE)            += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
+obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
+obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
 obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
index 2606600765079f946501717888a411eef20ac3fd..211e21f34bd57d5f6e2b079dcd22194713b3d5f5 100644 (file)
@@ -81,6 +81,79 @@ static struct device_attribute led_class_attrs[] = {
        __ATTR_NULL,
 };
 
+static void led_timer_function(unsigned long data)
+{
+       struct led_classdev *led_cdev = (void *)data;
+       unsigned long brightness;
+       unsigned long delay;
+
+       if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
+               led_set_brightness(led_cdev, LED_OFF);
+               return;
+       }
+
+       brightness = led_get_brightness(led_cdev);
+       if (!brightness) {
+               /* Time to switch the LED on. */
+               brightness = led_cdev->blink_brightness;
+               delay = led_cdev->blink_delay_on;
+       } else {
+               /* Store the current brightness value to be able
+                * to restore it when the delay_off period is over.
+                */
+               led_cdev->blink_brightness = brightness;
+               brightness = LED_OFF;
+               delay = led_cdev->blink_delay_off;
+       }
+
+       led_set_brightness(led_cdev, brightness);
+
+       mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static void led_stop_software_blink(struct led_classdev *led_cdev)
+{
+       /* deactivate previous settings */
+       del_timer_sync(&led_cdev->blink_timer);
+       led_cdev->blink_delay_on = 0;
+       led_cdev->blink_delay_off = 0;
+}
+
+static void led_set_software_blink(struct led_classdev *led_cdev,
+                                  unsigned long delay_on,
+                                  unsigned long delay_off)
+{
+       int current_brightness;
+
+       current_brightness = led_get_brightness(led_cdev);
+       if (current_brightness)
+               led_cdev->blink_brightness = current_brightness;
+       if (!led_cdev->blink_brightness)
+               led_cdev->blink_brightness = led_cdev->max_brightness;
+
+       if (delay_on == led_cdev->blink_delay_on &&
+           delay_off == led_cdev->blink_delay_off)
+               return;
+
+       led_stop_software_blink(led_cdev);
+
+       led_cdev->blink_delay_on = delay_on;
+       led_cdev->blink_delay_off = delay_off;
+
+       /* never on - don't blink */
+       if (!delay_on)
+               return;
+
+       /* never off - just set to brightness */
+       if (!delay_off) {
+               led_set_brightness(led_cdev, led_cdev->blink_brightness);
+               return;
+       }
+
+       mod_timer(&led_cdev->blink_timer, jiffies + 1);
+}
+
+
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -148,6 +221,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        led_update_brightness(led_cdev);
 
+       init_timer(&led_cdev->blink_timer);
+       led_cdev->blink_timer.function = led_timer_function;
+       led_cdev->blink_timer.data = (unsigned long)led_cdev;
+
 #ifdef CONFIG_LEDS_TRIGGERS
        led_trigger_set_default(led_cdev);
 #endif
@@ -157,7 +234,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(led_classdev_register);
 
 /**
@@ -175,6 +251,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
        up_write(&led_cdev->trigger_lock);
 #endif
 
+       /* Stop blinking */
+       led_brightness_set(led_cdev, LED_OFF);
+
        device_unregister(led_cdev->dev);
 
        down_write(&leds_list_lock);
@@ -183,6 +262,30 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 }
 EXPORT_SYMBOL_GPL(led_classdev_unregister);
 
+void led_blink_set(struct led_classdev *led_cdev,
+                  unsigned long *delay_on,
+                  unsigned long *delay_off)
+{
+       if (led_cdev->blink_set &&
+           led_cdev->blink_set(led_cdev, delay_on, delay_off))
+               return;
+
+       /* blink with 1 Hz as default if nothing specified */
+       if (!*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       led_set_software_blink(led_cdev, *delay_on, *delay_off);
+}
+EXPORT_SYMBOL(led_blink_set);
+
+void led_brightness_set(struct led_classdev *led_cdev,
+                       enum led_brightness brightness)
+{
+       led_stop_software_blink(led_cdev);
+       led_cdev->brightness_set(led_cdev, brightness);
+}
+EXPORT_SYMBOL(led_brightness_set);
+
 static int __init leds_init(void)
 {
        leds_class = class_create(THIS_MODULE, "leds");
index f1c00db88b5e148fd229410d5959f4c4e0e9580b..c41eb6180c9c2eb2e88ce2dfbfc64d7ff90daf2a 100644 (file)
@@ -113,7 +113,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
                if (led_cdev->trigger->deactivate)
                        led_cdev->trigger->deactivate(led_cdev);
                led_cdev->trigger = NULL;
-               led_set_brightness(led_cdev, LED_OFF);
+               led_brightness_set(led_cdev, LED_OFF);
        }
        if (trigger) {
                write_lock_irqsave(&trigger->leddev_list_lock, flags);
index ea57e05d08f3f757e67f7a3ed7c5d2c5c0a28aae..4d9fa38d9ff6a3cffb2063823c92b0d147ce13d8 100644 (file)
@@ -316,7 +316,7 @@ static struct of_platform_driver of_gpio_leds_driver = {
 
 static int __init gpio_led_init(void)
 {
-       int ret;
+       int ret = 0;
 
 #ifdef CONFIG_LEDS_GPIO_PLATFORM       
        ret = platform_driver_register(&gpio_led_driver);
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
new file mode 100644 (file)
index 0000000..3782f31
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * LP5521 LED chip driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/leds-lp5521.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define LP5521_PROGRAM_LENGTH          32      /* in bytes */
+
+#define LP5521_MAX_LEDS                        3       /* Maximum number of LEDs */
+#define LP5521_MAX_ENGINES             3       /* Maximum number of engines */
+
+#define LP5521_ENG_MASK_BASE           0x30    /* 00110000 */
+#define LP5521_ENG_STATUS_MASK         0x07    /* 00000111 */
+
+#define LP5521_CMD_LOAD                        0x15    /* 00010101 */
+#define LP5521_CMD_RUN                 0x2a    /* 00101010 */
+#define LP5521_CMD_DIRECT              0x3f    /* 00111111 */
+#define LP5521_CMD_DISABLED            0x00    /* 00000000 */
+
+/* Registers */
+#define LP5521_REG_ENABLE              0x00
+#define LP5521_REG_OP_MODE             0x01
+#define LP5521_REG_R_PWM               0x02
+#define LP5521_REG_G_PWM               0x03
+#define LP5521_REG_B_PWM               0x04
+#define LP5521_REG_R_CURRENT           0x05
+#define LP5521_REG_G_CURRENT           0x06
+#define LP5521_REG_B_CURRENT           0x07
+#define LP5521_REG_CONFIG              0x08
+#define LP5521_REG_R_CHANNEL_PC                0x09
+#define LP5521_REG_G_CHANNEL_PC                0x0A
+#define LP5521_REG_B_CHANNEL_PC                0x0B
+#define LP5521_REG_STATUS              0x0C
+#define LP5521_REG_RESET               0x0D
+#define LP5521_REG_GPO                 0x0E
+#define LP5521_REG_R_PROG_MEM          0x10
+#define LP5521_REG_G_PROG_MEM          0x30
+#define LP5521_REG_B_PROG_MEM          0x50
+
+#define LP5521_PROG_MEM_BASE           LP5521_REG_R_PROG_MEM
+#define LP5521_PROG_MEM_SIZE           0x20
+
+/* Base register to set LED current */
+#define LP5521_REG_LED_CURRENT_BASE    LP5521_REG_R_CURRENT
+
+/* Base register to set the brightness */
+#define LP5521_REG_LED_PWM_BASE                LP5521_REG_R_PWM
+
+/* Bits in ENABLE register */
+#define LP5521_MASTER_ENABLE           0x40    /* Chip master enable */
+#define LP5521_LOGARITHMIC_PWM         0x80    /* Logarithmic PWM adjustment */
+#define LP5521_EXEC_RUN                        0x2A
+
+/* Bits in CONFIG register */
+#define LP5521_PWM_HF                  0x40    /* PWM: 0 = 256Hz, 1 = 558Hz */
+#define LP5521_PWRSAVE_EN              0x20    /* 1 = Power save mode */
+#define LP5521_CP_MODE_OFF             0       /* Charge pump (CP) off */
+#define LP5521_CP_MODE_BYPASS          8       /* CP forced to bypass mode */
+#define LP5521_CP_MODE_1X5             0x10    /* CP forced to 1.5x mode */
+#define LP5521_CP_MODE_AUTO            0x18    /* Automatic mode selection */
+#define LP5521_R_TO_BATT               4       /* R out: 0 = CP, 1 = Vbat */
+#define LP5521_CLK_SRC_EXT             0       /* Ext-clk source (CLK_32K) */
+#define LP5521_CLK_INT                 1       /* Internal clock */
+#define LP5521_CLK_AUTO                        2       /* Automatic clock selection */
+
+/* Status */
+#define LP5521_EXT_CLK_USED            0x08
+
+struct lp5521_engine {
+       const struct attribute_group *attributes;
+       int             id;
+       u8              mode;
+       u8              prog_page;
+       u8              engine_mask;
+};
+
+struct lp5521_led {
+       int                     id;
+       u8                      chan_nr;
+       u8                      led_current;
+       u8                      max_current;
+       struct led_classdev     cdev;
+       struct work_struct      brightness_work;
+       u8                      brightness;
+};
+
+struct lp5521_chip {
+       struct lp5521_platform_data *pdata;
+       struct mutex            lock; /* Serialize control */
+       struct i2c_client       *client;
+       struct lp5521_engine    engines[LP5521_MAX_ENGINES];
+       struct lp5521_led       leds[LP5521_MAX_LEDS];
+       u8                      num_channels;
+       u8                      num_leds;
+};
+
+#define cdev_to_led(c)         container_of(c, struct lp5521_led, cdev)
+#define engine_to_lp5521(eng)  container_of((eng), struct lp5521_chip, \
+                                               engines[(eng)->id - 1])
+#define led_to_lp5521(led)     container_of((led), struct lp5521_chip, \
+                                               leds[(led)->id])
+
+static void lp5521_led_brightness_work(struct work_struct *work);
+
+static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+       s32 ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0)
+               return -EIO;
+
+       *buf = ret;
+       return 0;
+}
+
+static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(engine);
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 engine_state;
+
+       /* Only transition between RUN and DIRECT mode are handled here */
+       if (mode == LP5521_CMD_LOAD)
+               return 0;
+
+       if (mode == LP5521_CMD_DISABLED)
+               mode = LP5521_CMD_DIRECT;
+
+       ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state);
+
+       /* set mode only for this engine */
+       engine_state &= ~(engine->engine_mask);
+       mode &= engine->engine_mask;
+       engine_state |= mode;
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, engine_state);
+
+       return ret;
+}
+
+static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(eng);
+       struct i2c_client *client = chip->client;
+       int ret;
+       int addr;
+       u8 mode;
+
+       /* move current engine to direct mode and remember the state */
+       ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
+       usleep_range(1000, 10000);
+       ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode);
+
+       /* For loading, all the engines to load mode */
+       lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+       usleep_range(1000, 10000);
+       lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+       usleep_range(1000, 10000);
+
+       addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE;
+       i2c_smbus_write_i2c_block_data(client,
+                               addr,
+                               LP5521_PROG_MEM_SIZE,
+                               pattern);
+
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode);
+       return ret;
+}
+
+static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr)
+{
+       return lp5521_write(chip->client,
+                   LP5521_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
+                   curr);
+}
+
+static void lp5521_init_engine(struct lp5521_chip *chip,
+                       const struct attribute_group *attr_group)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
+               chip->engines[i].id = i + 1;
+               chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2);
+               chip->engines[i].prog_page = i;
+               chip->engines[i].attributes = &attr_group[i];
+       }
+}
+
+static int lp5521_configure(struct i2c_client *client,
+                       const struct attribute_group *attr_group)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int ret;
+
+       lp5521_init_engine(chip, attr_group);
+
+       lp5521_write(client, LP5521_REG_RESET, 0xff);
+
+       usleep_range(10000, 20000);
+
+       /* Set all PWMs to direct control mode */
+       ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+
+       /* Enable auto-powersave, set charge pump to auto, red to battery */
+       ret |= lp5521_write(client, LP5521_REG_CONFIG,
+               LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+
+       /* Initialize all channels PWM to zero -> leds off */
+       ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
+       ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
+       ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
+
+       /* Set engines are set to run state when OP_MODE enables engines */
+       ret |= lp5521_write(client, LP5521_REG_ENABLE,
+                       LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
+                       LP5521_EXEC_RUN);
+       /* enable takes 500us */
+       usleep_range(500, 20000);
+
+       return ret;
+}
+
+static int lp5521_run_selftest(struct lp5521_chip *chip, char *buf)
+{
+       int ret;
+       u8 status;
+
+       ret = lp5521_read(chip->client, LP5521_REG_STATUS, &status);
+       if (ret < 0)
+               return ret;
+
+       /* Check that ext clock is really in use if requested */
+       if (chip->pdata && chip->pdata->clock_mode == LP5521_CLOCK_EXT)
+               if  ((status & LP5521_EXT_CLK_USED) == 0)
+                       return -EIO;
+       return 0;
+}
+
+static void lp5521_set_brightness(struct led_classdev *cdev,
+                            enum led_brightness brightness)
+{
+       struct lp5521_led *led = cdev_to_led(cdev);
+       led->brightness = (u8)brightness;
+       schedule_work(&led->brightness_work);
+}
+
+static void lp5521_led_brightness_work(struct work_struct *work)
+{
+       struct lp5521_led *led = container_of(work,
+                                             struct lp5521_led,
+                                             brightness_work);
+       struct lp5521_chip *chip = led_to_lp5521(led);
+       struct i2c_client *client = chip->client;
+
+       mutex_lock(&chip->lock);
+       lp5521_write(client, LP5521_REG_LED_PWM_BASE + led->chan_nr,
+               led->brightness);
+       mutex_unlock(&chip->lock);
+}
+
+/* Detect the chip by setting its ENABLE register and reading it back. */
+static int lp5521_detect(struct i2c_client *client)
+{
+       int ret;
+       u8 buf;
+
+       ret = lp5521_write(client, LP5521_REG_ENABLE,
+                       LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+       if (ret)
+               return ret;
+       usleep_range(1000, 10000);
+       ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
+       if (ret)
+               return ret;
+       if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM))
+               return -ENODEV;
+
+       return 0;
+}
+
+/* Set engine mode and create appropriate sysfs attributes, if required. */
+static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(engine);
+       struct i2c_client *client = chip->client;
+       struct device *dev = &client->dev;
+       int ret = 0;
+
+       /* if in that mode already do nothing, except for run */
+       if (mode == engine->mode && mode != LP5521_CMD_RUN)
+               return 0;
+
+       if (mode == LP5521_CMD_RUN) {
+               ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN);
+       } else if (mode == LP5521_CMD_LOAD) {
+               lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+               lp5521_set_engine_mode(engine, LP5521_CMD_LOAD);
+
+               ret = sysfs_create_group(&dev->kobj, engine->attributes);
+               if (ret)
+                       return ret;
+       } else if (mode == LP5521_CMD_DISABLED) {
+               lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+       }
+
+       /* remove load attribute from sysfs if not in load mode */
+       if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD)
+               sysfs_remove_group(&dev->kobj, engine->attributes);
+
+       engine->mode = mode;
+
+       return ret;
+}
+
+static int lp5521_do_store_load(struct lp5521_engine *engine,
+                               const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(engine);
+       struct i2c_client *client = chip->client;
+       int  ret, nrchars, offset = 0, i = 0;
+       char c[3];
+       unsigned cmd;
+       u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
+
+       while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto fail;
+               pattern[i] = (u8)cmd;
+
+               offset += nrchars;
+               i++;
+       }
+
+       /* Each instruction is 16bit long. Check that length is even */
+       if (i % 2)
+               goto fail;
+
+       mutex_lock(&chip->lock);
+       ret = lp5521_load_program(engine, pattern);
+       mutex_unlock(&chip->lock);
+
+       if (ret) {
+               dev_err(&client->dev, "failed loading pattern\n");
+               return ret;
+       }
+
+       return len;
+fail:
+       dev_err(&client->dev, "wrong pattern format\n");
+       return -EINVAL;
+}
+
+static ssize_t store_engine_load(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       return lp5521_do_store_load(&chip->engines[nr - 1], buf, len);
+}
+
+#define store_load(nr)                                                 \
+static ssize_t store_engine##nr##_load(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_load(dev, attr, buf, len, nr);              \
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
+static ssize_t show_engine_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       switch (chip->engines[nr - 1].mode) {
+       case LP5521_CMD_RUN:
+               return sprintf(buf, "run\n");
+       case LP5521_CMD_LOAD:
+               return sprintf(buf, "load\n");
+       case LP5521_CMD_DISABLED:
+               return sprintf(buf, "disabled\n");
+       default:
+               return sprintf(buf, "disabled\n");
+       }
+}
+
+#define show_mode(nr)                                                  \
+static ssize_t show_engine##nr##_mode(struct device *dev,              \
+                                   struct device_attribute *attr,      \
+                                   char *buf)                          \
+{                                                                      \
+       return show_engine_mode(dev, attr, buf, nr);                    \
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       struct lp5521_engine *engine = &chip->engines[nr - 1];
+       mutex_lock(&chip->lock);
+
+       if (!strncmp(buf, "run", 3))
+               lp5521_set_mode(engine, LP5521_CMD_RUN);
+       else if (!strncmp(buf, "load", 4))
+               lp5521_set_mode(engine, LP5521_CMD_LOAD);
+       else if (!strncmp(buf, "disabled", 8))
+               lp5521_set_mode(engine, LP5521_CMD_DISABLED);
+
+       mutex_unlock(&chip->lock);
+       return len;
+}
+
+#define store_mode(nr)                                                 \
+static ssize_t store_engine##nr##_mode(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_mode(dev, attr, buf, len, nr);              \
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t show_max_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5521_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->max_current);
+}
+
+static ssize_t show_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5521_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t store_current(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5521_led *led = cdev_to_led(led_cdev);
+       struct lp5521_chip *chip = led_to_lp5521(led);
+       ssize_t ret;
+       unsigned long curr;
+
+       if (strict_strtoul(buf, 0, &curr))
+               return -EINVAL;
+
+       if (curr > led->max_current)
+               return -EINVAL;
+
+       mutex_lock(&chip->lock);
+       ret = lp5521_set_led_current(chip, led->id, curr);
+       mutex_unlock(&chip->lock);
+
+       if (ret < 0)
+               return ret;
+
+       led->led_current = (u8)curr;
+
+       return len;
+}
+
+static ssize_t lp5521_selftest(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int ret;
+
+       mutex_lock(&chip->lock);
+       ret = lp5521_run_selftest(chip, buf);
+       mutex_unlock(&chip->lock);
+       return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
+}
+
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5521_led_attributes[] = {
+       &dev_attr_led_current.attr,
+       &dev_attr_max_current.attr,
+       NULL,
+};
+
+static struct attribute_group lp5521_led_attribute_group = {
+       .attrs = lp5521_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+                  show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+                  show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+                  show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+
+static struct attribute *lp5521_attributes[] = {
+       &dev_attr_engine1_mode.attr,
+       &dev_attr_engine2_mode.attr,
+       &dev_attr_engine3_mode.attr,
+       &dev_attr_selftest.attr,
+       NULL
+};
+
+static struct attribute *lp5521_engine1_attributes[] = {
+       &dev_attr_engine1_load.attr,
+       NULL
+};
+
+static struct attribute *lp5521_engine2_attributes[] = {
+       &dev_attr_engine2_load.attr,
+       NULL
+};
+
+static struct attribute *lp5521_engine3_attributes[] = {
+       &dev_attr_engine3_load.attr,
+       NULL
+};
+
+static const struct attribute_group lp5521_group = {
+       .attrs = lp5521_attributes,
+};
+
+static const struct attribute_group lp5521_engine_group[] = {
+       {.attrs = lp5521_engine1_attributes },
+       {.attrs = lp5521_engine2_attributes },
+       {.attrs = lp5521_engine3_attributes },
+};
+
+static int lp5521_register_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       return sysfs_create_group(&dev->kobj, &lp5521_group);
+}
+
+static void lp5521_unregister_sysfs(struct i2c_client *client)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
+       int i;
+
+       sysfs_remove_group(&dev->kobj, &lp5521_group);
+
+       for (i = 0; i <  ARRAY_SIZE(chip->engines); i++) {
+               if (chip->engines[i].mode == LP5521_CMD_LOAD)
+                       sysfs_remove_group(&dev->kobj,
+                                       chip->engines[i].attributes);
+       }
+
+       for (i = 0; i < chip->num_leds; i++)
+               sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
+                               &lp5521_led_attribute_group);
+}
+
+static int __init lp5521_init_led(struct lp5521_led *led,
+                               struct i2c_client *client,
+                               int chan, struct lp5521_platform_data *pdata)
+{
+       struct device *dev = &client->dev;
+       char name[32];
+       int res;
+
+       if (chan >= LP5521_MAX_LEDS)
+               return -EINVAL;
+
+       if (pdata->led_config[chan].led_current == 0)
+               return 0;
+
+       led->led_current = pdata->led_config[chan].led_current;
+       led->max_current = pdata->led_config[chan].max_current;
+       led->chan_nr = pdata->led_config[chan].chan_nr;
+
+       if (led->chan_nr >= LP5521_MAX_LEDS) {
+               dev_err(dev, "Use channel numbers between 0 and %d\n",
+                       LP5521_MAX_LEDS - 1);
+               return -EINVAL;
+       }
+
+       snprintf(name, sizeof(name), "%s:channel%d", client->name, chan);
+       led->cdev.brightness_set = lp5521_set_brightness;
+       led->cdev.name = name;
+       res = led_classdev_register(dev, &led->cdev);
+       if (res < 0) {
+               dev_err(dev, "couldn't register led on channel %d\n", chan);
+               return res;
+       }
+
+       res = sysfs_create_group(&led->cdev.dev->kobj,
+                       &lp5521_led_attribute_group);
+       if (res < 0) {
+               dev_err(dev, "couldn't register current attribute\n");
+               led_classdev_unregister(&led->cdev);
+               return res;
+       }
+       return 0;
+}
+
+static int lp5521_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lp5521_chip              *chip;
+       struct lp5521_platform_data     *pdata;
+       int ret, i, led;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client = client;
+
+       pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data\n");
+               ret = -EINVAL;
+               goto fail1;
+       }
+
+       mutex_init(&chip->lock);
+
+       chip->pdata   = pdata;
+
+       if (pdata->setup_resources) {
+               ret = pdata->setup_resources();
+               if (ret < 0)
+                       goto fail1;
+       }
+
+       if (pdata->enable) {
+               pdata->enable(0);
+               usleep_range(1000, 10000);
+               pdata->enable(1);
+               usleep_range(1000, 10000); /* Spec says min 500us */
+       }
+
+       ret = lp5521_detect(client);
+
+       if (ret) {
+               dev_err(&client->dev, "Chip not found\n");
+               goto fail2;
+       }
+
+       dev_info(&client->dev, "%s programmable led chip found\n", id->name);
+
+       ret = lp5521_configure(client, lp5521_engine_group);
+       if (ret < 0) {
+               dev_err(&client->dev, "error configuring chip\n");
+               goto fail2;
+       }
+
+       /* Initialize leds */
+       chip->num_channels = pdata->num_channels;
+       chip->num_leds = 0;
+       led = 0;
+       for (i = 0; i < pdata->num_channels; i++) {
+               /* Do not initialize channels that are not connected */
+               if (pdata->led_config[i].led_current == 0)
+                       continue;
+
+               ret = lp5521_init_led(&chip->leds[led], client, i, pdata);
+               if (ret) {
+                       dev_err(&client->dev, "error initializing leds\n");
+                       goto fail3;
+               }
+               chip->num_leds++;
+
+               chip->leds[led].id = led;
+               /* Set initial LED current */
+               lp5521_set_led_current(chip, led,
+                               chip->leds[led].led_current);
+
+               INIT_WORK(&(chip->leds[led].brightness_work),
+                       lp5521_led_brightness_work);
+
+               led++;
+       }
+
+       ret = lp5521_register_sysfs(client);
+       if (ret) {
+               dev_err(&client->dev, "registering sysfs failed\n");
+               goto fail3;
+       }
+       return ret;
+fail3:
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+fail2:
+       if (pdata->enable)
+               pdata->enable(0);
+       if (pdata->release_resources)
+               pdata->release_resources();
+fail1:
+       kfree(chip);
+       return ret;
+}
+
+static int lp5521_remove(struct i2c_client *client)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int i;
+
+       lp5521_unregister_sysfs(client);
+
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+
+       if (chip->pdata->enable)
+               chip->pdata->enable(0);
+       if (chip->pdata->release_resources)
+               chip->pdata->release_resources();
+       kfree(chip);
+       return 0;
+}
+
+static const struct i2c_device_id lp5521_id[] = {
+       { "lp5521", 0 }, /* Three channel chip */
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp5521_id);
+
+static struct i2c_driver lp5521_driver = {
+       .driver = {
+               .name   = "lp5521",
+       },
+       .probe          = lp5521_probe,
+       .remove         = lp5521_remove,
+       .id_table       = lp5521_id,
+};
+
+static int __init lp5521_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&lp5521_driver);
+
+       if (ret < 0)
+               printk(KERN_ALERT "Adding lp5521 driver failed\n");
+
+       return ret;
+}
+
+static void __exit lp5521_exit(void)
+{
+       i2c_del_driver(&lp5521_driver);
+}
+
+module_init(lp5521_init);
+module_exit(lp5521_exit);
+
+MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo");
+MODULE_DESCRIPTION("LP5521 LED engine");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
new file mode 100644 (file)
index 0000000..1e11fcc
--- /dev/null
@@ -0,0 +1,1065 @@
+/*
+ * lp5523.c - LP5523 LED Driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/leds-lp5523.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define LP5523_REG_ENABLE              0x00
+#define LP5523_REG_OP_MODE             0x01
+#define LP5523_REG_RATIOMETRIC_MSB     0x02
+#define LP5523_REG_RATIOMETRIC_LSB     0x03
+#define LP5523_REG_ENABLE_LEDS_MSB     0x04
+#define LP5523_REG_ENABLE_LEDS_LSB     0x05
+#define LP5523_REG_LED_CNTRL_BASE      0x06
+#define LP5523_REG_LED_PWM_BASE                0x16
+#define LP5523_REG_LED_CURRENT_BASE    0x26
+#define LP5523_REG_CONFIG              0x36
+#define LP5523_REG_CHANNEL1_PC         0x37
+#define LP5523_REG_CHANNEL2_PC         0x38
+#define LP5523_REG_CHANNEL3_PC         0x39
+#define LP5523_REG_STATUS              0x3a
+#define LP5523_REG_GPO                 0x3b
+#define LP5523_REG_VARIABLE            0x3c
+#define LP5523_REG_RESET               0x3d
+#define LP5523_REG_TEMP_CTRL           0x3e
+#define LP5523_REG_TEMP_READ           0x3f
+#define LP5523_REG_TEMP_WRITE          0x40
+#define LP5523_REG_LED_TEST_CTRL       0x41
+#define LP5523_REG_LED_TEST_ADC                0x42
+#define LP5523_REG_ENG1_VARIABLE       0x45
+#define LP5523_REG_ENG2_VARIABLE       0x46
+#define LP5523_REG_ENG3_VARIABLE       0x47
+#define LP5523_REG_MASTER_FADER1       0x48
+#define LP5523_REG_MASTER_FADER2       0x49
+#define LP5523_REG_MASTER_FADER3       0x4a
+#define LP5523_REG_CH1_PROG_START      0x4c
+#define LP5523_REG_CH2_PROG_START      0x4d
+#define LP5523_REG_CH3_PROG_START      0x4e
+#define LP5523_REG_PROG_PAGE_SEL       0x4f
+#define LP5523_REG_PROG_MEM            0x50
+
+#define LP5523_CMD_LOAD                        0x15 /* 00010101 */
+#define LP5523_CMD_RUN                 0x2a /* 00101010 */
+#define LP5523_CMD_DISABLED            0x00 /* 00000000 */
+
+#define LP5523_ENABLE                  0x40
+#define LP5523_AUTO_INC                        0x40
+#define LP5523_PWR_SAVE                        0x20
+#define LP5523_PWM_PWR_SAVE            0x04
+#define LP5523_CP_1                    0x08
+#define LP5523_CP_1_5                  0x10
+#define LP5523_CP_AUTO                 0x18
+#define LP5523_INT_CLK                 0x01
+#define LP5523_AUTO_CLK                        0x02
+#define LP5523_EN_LEDTEST              0x80
+#define LP5523_LEDTEST_DONE            0x80
+
+#define LP5523_DEFAULT_CURRENT         50 /* microAmps */
+#define LP5523_PROGRAM_LENGTH          32 /* in bytes */
+#define LP5523_PROGRAM_PAGES           6
+#define LP5523_ADC_SHORTCIRC_LIM       80
+
+#define LP5523_LEDS                    9
+#define LP5523_ENGINES                 3
+
+#define LP5523_ENG_MASK_BASE           0x30 /* 00110000 */
+
+#define LP5523_ENG_STATUS_MASK          0x07 /* 00000111 */
+
+#define LP5523_IRQ_FLAGS                IRQF_TRIGGER_FALLING
+
+#define LP5523_EXT_CLK_USED            0x08
+
+#define LED_ACTIVE(mux, led)           (!!(mux & (0x0001 << led)))
+#define SHIFT_MASK(id)                 (((id) - 1) * 2)
+
+struct lp5523_engine {
+       const struct attribute_group *attributes;
+       int             id;
+       u8              mode;
+       u8              prog_page;
+       u8              mux_page;
+       u16             led_mux;
+       u8              engine_mask;
+};
+
+struct lp5523_led {
+       int                     id;
+       u8                      chan_nr;
+       u8                      led_current;
+       u8                      max_current;
+       struct led_classdev     cdev;
+       struct work_struct      brightness_work;
+       u8                      brightness;
+};
+
+struct lp5523_chip {
+       struct mutex            lock; /* Serialize control */
+       struct i2c_client       *client;
+       struct lp5523_engine    engines[LP5523_ENGINES];
+       struct lp5523_led       leds[LP5523_LEDS];
+       struct lp5523_platform_data *pdata;
+       u8                      num_channels;
+       u8                      num_leds;
+};
+
+#define cdev_to_led(c)          container_of(c, struct lp5523_led, cdev)
+
+static struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine)
+{
+       return container_of(engine, struct lp5523_chip,
+                           engines[engine->id - 1]);
+}
+
+static struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
+{
+       return container_of(led, struct lp5523_chip,
+                           leds[led->id]);
+}
+
+static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
+static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
+static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern);
+
+static void lp5523_led_brightness_work(struct work_struct *work);
+
+static int lp5523_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5523_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+       s32 ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               return -EIO;
+
+       *buf = ret;
+       return 0;
+}
+
+static int lp5523_detect(struct i2c_client *client)
+{
+       int ret;
+       u8 buf;
+
+       ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40);
+       if (ret)
+               return ret;
+       ret = lp5523_read(client, LP5523_REG_ENABLE, &buf);
+       if (ret)
+               return ret;
+       if (buf == 0x40)
+               return 0;
+       else
+               return -ENODEV;
+}
+
+static int lp5523_configure(struct i2c_client *client)
+{
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+       u8 status;
+
+       /* one pattern per engine setting led mux start and stop addresses */
+       u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
+               { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
+               { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
+               { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
+       };
+
+       lp5523_write(client, LP5523_REG_RESET, 0xff);
+
+       usleep_range(10000, 100000);
+
+       ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
+       /* Chip startup time after reset is 500 us */
+       usleep_range(1000, 10000);
+
+       ret |= lp5523_write(client, LP5523_REG_CONFIG,
+                           LP5523_AUTO_INC | LP5523_PWR_SAVE |
+                           LP5523_CP_AUTO | LP5523_AUTO_CLK |
+                           LP5523_PWM_PWR_SAVE);
+
+       /* turn on all leds */
+       ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_MSB, 0x01);
+       ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
+
+       /* hardcode 32 bytes of memory for each engine from program memory */
+       ret |= lp5523_write(client, LP5523_REG_CH1_PROG_START, 0x00);
+       ret |= lp5523_write(client, LP5523_REG_CH2_PROG_START, 0x10);
+       ret |= lp5523_write(client, LP5523_REG_CH3_PROG_START, 0x20);
+
+       /* write led mux address space for each channel */
+       ret |= lp5523_load_program(&chip->engines[0], pattern[0]);
+       ret |= lp5523_load_program(&chip->engines[1], pattern[1]);
+       ret |= lp5523_load_program(&chip->engines[2], pattern[2]);
+
+       if (ret) {
+               dev_err(&client->dev, "could not load mux programs\n");
+               return -1;
+       }
+
+       /* set all engines exec state and mode to run 00101010 */
+       ret |= lp5523_write(client, LP5523_REG_ENABLE,
+                           (LP5523_CMD_RUN | LP5523_ENABLE));
+
+       ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_RUN);
+
+       if (ret) {
+               dev_err(&client->dev, "could not start mux programs\n");
+               return -1;
+       }
+
+       /* Wait 3ms and check the engine status */
+       usleep_range(3000, 20000);
+       lp5523_read(client, LP5523_REG_STATUS, &status);
+       status &= LP5523_ENG_STATUS_MASK;
+
+       if (status == LP5523_ENG_STATUS_MASK) {
+               dev_dbg(&client->dev, "all engines configured\n");
+       } else {
+               dev_info(&client->dev, "status == %x\n", status);
+               dev_err(&client->dev, "cound not configure LED engine\n");
+               return -1;
+       }
+
+       dev_info(&client->dev, "disabling engines\n");
+
+       ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+
+       return ret;
+}
+
+static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 engine_state;
+
+       ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state);
+       if (ret)
+               goto fail;
+
+       engine_state &= ~(engine->engine_mask);
+
+       /* set mode only for this engine */
+       mode &= engine->engine_mask;
+
+       engine_state |= mode;
+
+       ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state);
+fail:
+       return ret;
+}
+
+static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+       ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page);
+       ret |= lp5523_write(client, LP5523_REG_PROG_MEM,
+                           (u8)(mux >> 8));
+       ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux));
+       engine->led_mux = mux;
+
+       return ret;
+}
+
+static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+
+       int ret = 0;
+
+       ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+       ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL,
+                           engine->prog_page);
+       ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM,
+                                             LP5523_PROGRAM_LENGTH, pattern);
+
+       return ret;
+}
+
+static int lp5523_run_program(struct lp5523_engine *engine)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       ret = lp5523_write(client, LP5523_REG_ENABLE,
+                                       LP5523_CMD_RUN | LP5523_ENABLE);
+       if (ret)
+               goto fail;
+
+       ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN);
+fail:
+       return ret;
+}
+
+static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
+{
+       int i;
+       u16 tmp_mux = 0;
+       len = len < LP5523_LEDS ? len : LP5523_LEDS;
+       for (i = 0; i < len; i++) {
+               switch (buf[i]) {
+               case '1':
+                       tmp_mux |= (1 << i);
+                       break;
+               case '0':
+                       break;
+               case '\n':
+                       i = len;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+       *mux = tmp_mux;
+
+       return 0;
+}
+
+static void lp5523_mux_to_array(u16 led_mux, char *array)
+{
+       int i, pos = 0;
+       for (i = 0; i < LP5523_LEDS; i++)
+               pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
+
+       array[pos] = '\0';
+}
+
+/*--------------------------------------------------------------*/
+/*                     Sysfs interface                         */
+/*--------------------------------------------------------------*/
+
+static ssize_t show_engine_leds(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       char mux[LP5523_LEDS + 1];
+
+       lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
+
+       return sprintf(buf, "%s\n", mux);
+}
+
+#define show_leds(nr)                                                  \
+static ssize_t show_engine##nr##_leds(struct device *dev,              \
+                           struct device_attribute *attr,              \
+                           char *buf)                                  \
+{                                                                      \
+       return show_engine_leds(dev, attr, buf, nr);                    \
+}
+show_leds(1)
+show_leds(2)
+show_leds(3)
+
+static ssize_t store_engine_leds(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       u16 mux = 0;
+
+       if (lp5523_mux_parse(buf, &mux, len))
+               return -EINVAL;
+
+       if (lp5523_load_mux(&chip->engines[nr - 1], mux))
+               return -EINVAL;
+
+       return len;
+}
+
+#define store_leds(nr)                                         \
+static ssize_t store_engine##nr##_leds(struct device *dev,     \
+                            struct device_attribute *attr,     \
+                            const char *buf, size_t len)       \
+{                                                              \
+       return store_engine_leds(dev, attr, buf, len, nr);      \
+}
+store_leds(1)
+store_leds(2)
+store_leds(3)
+
+static ssize_t lp5523_selftest(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       int i, ret, pos = 0;
+       int led = 0;
+       u8 status, adc, vdd;
+
+       mutex_lock(&chip->lock);
+
+       ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+       if (ret < 0)
+               goto fail;
+
+       /* Check that ext clock is really in use if requested */
+       if ((chip->pdata) && (chip->pdata->clock_mode == LP5523_CLOCK_EXT))
+               if  ((status & LP5523_EXT_CLK_USED) == 0)
+                       goto fail;
+
+       /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */
+       lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL,
+                                   LP5523_EN_LEDTEST | 16);
+       usleep_range(3000, 10000);
+       ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+       if (!(status & LP5523_LEDTEST_DONE))
+               usleep_range(3000, 10000);
+
+       ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd);
+       vdd--;  /* There may be some fluctuation in measurement */
+
+       for (i = 0; i < LP5523_LEDS; i++) {
+               /* Skip non-existing channels */
+               if (chip->pdata->led_config[i].led_current == 0)
+                       continue;
+
+               /* Set default current */
+               lp5523_write(chip->client,
+                       LP5523_REG_LED_CURRENT_BASE + i,
+                       chip->pdata->led_config[i].led_current);
+
+               lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff);
+               /* let current stabilize 2ms before measurements start */
+               usleep_range(2000, 10000);
+               lp5523_write(chip->client,
+                            LP5523_REG_LED_TEST_CTRL,
+                            LP5523_EN_LEDTEST | i);
+               /* ledtest takes 2.7ms */
+               usleep_range(3000, 10000);
+               ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+               if (!(status & LP5523_LEDTEST_DONE))
+                       usleep_range(3000, 10000);
+               ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc);
+
+               if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM)
+                       pos += sprintf(buf + pos, "LED %d FAIL\n", i);
+
+               lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0x00);
+
+               /* Restore current */
+               lp5523_write(chip->client,
+                       LP5523_REG_LED_CURRENT_BASE + i,
+                       chip->leds[led].led_current);
+               led++;
+       }
+       if (pos == 0)
+               pos = sprintf(buf, "OK\n");
+       goto release_lock;
+fail:
+       pos = sprintf(buf, "FAIL\n");
+
+release_lock:
+       mutex_unlock(&chip->lock);
+
+       return pos;
+}
+
+static void lp5523_set_brightness(struct led_classdev *cdev,
+                            enum led_brightness brightness)
+{
+       struct lp5523_led *led = cdev_to_led(cdev);
+
+       led->brightness = (u8)brightness;
+
+       schedule_work(&led->brightness_work);
+}
+
+static void lp5523_led_brightness_work(struct work_struct *work)
+{
+       struct lp5523_led *led = container_of(work,
+                                             struct lp5523_led,
+                                             brightness_work);
+       struct lp5523_chip *chip = led_to_lp5523(led);
+       struct i2c_client *client = chip->client;
+
+       mutex_lock(&chip->lock);
+
+       lp5523_write(client, LP5523_REG_LED_PWM_BASE + led->chan_nr,
+                    led->brightness);
+
+       mutex_unlock(&chip->lock);
+}
+
+static int lp5523_do_store_load(struct lp5523_engine *engine,
+                               const char *buf, size_t len)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int  ret, nrchars, offset = 0, i = 0;
+       char c[3];
+       unsigned cmd;
+       u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
+
+       while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) {
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto fail;
+               pattern[i] = (u8)cmd;
+
+               offset += nrchars;
+               i++;
+       }
+
+       /* Each instruction is 16bit long. Check that length is even */
+       if (i % 2)
+               goto fail;
+
+       mutex_lock(&chip->lock);
+
+       ret = lp5523_load_program(engine, pattern);
+       mutex_unlock(&chip->lock);
+
+       if (ret) {
+               dev_err(&client->dev, "failed loading pattern\n");
+               return ret;
+       }
+
+       return len;
+fail:
+       dev_err(&client->dev, "wrong pattern format\n");
+       return -EINVAL;
+}
+
+static ssize_t store_engine_load(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       return lp5523_do_store_load(&chip->engines[nr - 1], buf, len);
+}
+
+#define store_load(nr)                                                 \
+static ssize_t store_engine##nr##_load(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_load(dev, attr, buf, len, nr);              \
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
+static ssize_t show_engine_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       switch (chip->engines[nr - 1].mode) {
+       case LP5523_CMD_RUN:
+               return sprintf(buf, "run\n");
+       case LP5523_CMD_LOAD:
+               return sprintf(buf, "load\n");
+       case LP5523_CMD_DISABLED:
+               return sprintf(buf, "disabled\n");
+       default:
+               return sprintf(buf, "disabled\n");
+       }
+}
+
+#define show_mode(nr)                                                  \
+static ssize_t show_engine##nr##_mode(struct device *dev,              \
+                                   struct device_attribute *attr,      \
+                                   char *buf)                          \
+{                                                                      \
+       return show_engine_mode(dev, attr, buf, nr);                    \
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       struct lp5523_engine *engine = &chip->engines[nr - 1];
+       mutex_lock(&chip->lock);
+
+       if (!strncmp(buf, "run", 3))
+               lp5523_set_mode(engine, LP5523_CMD_RUN);
+       else if (!strncmp(buf, "load", 4))
+               lp5523_set_mode(engine, LP5523_CMD_LOAD);
+       else if (!strncmp(buf, "disabled", 8))
+               lp5523_set_mode(engine, LP5523_CMD_DISABLED);
+
+       mutex_unlock(&chip->lock);
+       return len;
+}
+
+#define store_mode(nr)                                                 \
+static ssize_t store_engine##nr##_mode(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_mode(dev, attr, buf, len, nr);              \
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t show_max_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5523_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->max_current);
+}
+
+static ssize_t show_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5523_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t store_current(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5523_led *led = cdev_to_led(led_cdev);
+       struct lp5523_chip *chip = led_to_lp5523(led);
+       ssize_t ret;
+       unsigned long curr;
+
+       if (strict_strtoul(buf, 0, &curr))
+               return -EINVAL;
+
+       if (curr > led->max_current)
+               return -EINVAL;
+
+       mutex_lock(&chip->lock);
+       ret = lp5523_write(chip->client,
+                       LP5523_REG_LED_CURRENT_BASE + led->chan_nr,
+                       (u8)curr);
+       mutex_unlock(&chip->lock);
+
+       if (ret < 0)
+               return ret;
+
+       led->led_current = (u8)curr;
+
+       return len;
+}
+
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5523_led_attributes[] = {
+       &dev_attr_led_current.attr,
+       &dev_attr_max_current.attr,
+       NULL,
+};
+
+static struct attribute_group lp5523_led_attribute_group = {
+       .attrs = lp5523_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+                  show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+                  show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+                  show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO,
+                  show_engine1_leds, store_engine1_leds);
+static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO,
+                  show_engine2_leds, store_engine2_leds);
+static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO,
+                  show_engine3_leds, store_engine3_leds);
+static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL);
+
+static struct attribute *lp5523_attributes[] = {
+       &dev_attr_engine1_mode.attr,
+       &dev_attr_engine2_mode.attr,
+       &dev_attr_engine3_mode.attr,
+       &dev_attr_selftest.attr,
+       NULL
+};
+
+static struct attribute *lp5523_engine1_attributes[] = {
+       &dev_attr_engine1_load.attr,
+       &dev_attr_engine1_leds.attr,
+       NULL
+};
+
+static struct attribute *lp5523_engine2_attributes[] = {
+       &dev_attr_engine2_load.attr,
+       &dev_attr_engine2_leds.attr,
+       NULL
+};
+
+static struct attribute *lp5523_engine3_attributes[] = {
+       &dev_attr_engine3_load.attr,
+       &dev_attr_engine3_leds.attr,
+       NULL
+};
+
+static const struct attribute_group lp5523_group = {
+       .attrs = lp5523_attributes,
+};
+
+static const struct attribute_group lp5523_engine_group[] = {
+       {.attrs = lp5523_engine1_attributes },
+       {.attrs = lp5523_engine2_attributes },
+       {.attrs = lp5523_engine3_attributes },
+};
+
+static int lp5523_register_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       int ret;
+
+       ret = sysfs_create_group(&dev->kobj, &lp5523_group);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void lp5523_unregister_sysfs(struct i2c_client *client)
+{
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
+       int i;
+
+       sysfs_remove_group(&dev->kobj, &lp5523_group);
+
+       for (i = 0; i < ARRAY_SIZE(chip->engines); i++)
+               if (chip->engines[i].mode == LP5523_CMD_LOAD)
+                       sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]);
+
+       for (i = 0; i < chip->num_leds; i++)
+               sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
+                               &lp5523_led_attribute_group);
+}
+
+/*--------------------------------------------------------------*/
+/*                     Set chip operating mode                 */
+/*--------------------------------------------------------------*/
+static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
+{
+       /*  engine to chip */
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       struct device *dev = &client->dev;
+       int ret = 0;
+
+       /* if in that mode already do nothing, except for run */
+       if (mode == engine->mode && mode != LP5523_CMD_RUN)
+               return 0;
+
+       if (mode == LP5523_CMD_RUN) {
+               ret = lp5523_run_program(engine);
+       } else if (mode == LP5523_CMD_LOAD) {
+               lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+               lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+               ret = sysfs_create_group(&dev->kobj, engine->attributes);
+               if (ret)
+                       return ret;
+       } else if (mode == LP5523_CMD_DISABLED) {
+               lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+       }
+
+       /* remove load attribute from sysfs if not in load mode */
+       if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD)
+               sysfs_remove_group(&dev->kobj, engine->attributes);
+
+       engine->mode = mode;
+
+       return ret;
+}
+
+/*--------------------------------------------------------------*/
+/*                     Probe, Attach, Remove                   */
+/*--------------------------------------------------------------*/
+static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
+{
+       if (id < 1 || id > LP5523_ENGINES)
+               return -1;
+       engine->id = id;
+       engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id);
+       engine->prog_page = id - 1;
+       engine->mux_page = id + 2;
+       engine->attributes = &lp5523_engine_group[id - 1];
+
+       return 0;
+}
+
+static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev,
+                          int chan, struct lp5523_platform_data *pdata)
+{
+       char name[32];
+       int res;
+
+       if (chan >= LP5523_LEDS)
+               return -EINVAL;
+
+       if (pdata->led_config[chan].led_current) {
+               led->led_current = pdata->led_config[chan].led_current;
+               led->max_current = pdata->led_config[chan].max_current;
+               led->chan_nr = pdata->led_config[chan].chan_nr;
+
+               if (led->chan_nr >= LP5523_LEDS) {
+                       dev_err(dev, "Use channel numbers between 0 and %d\n",
+                               LP5523_LEDS - 1);
+                       return -EINVAL;
+               }
+
+               snprintf(name, 32, "lp5523:channel%d", chan);
+
+               led->cdev.name = name;
+               led->cdev.brightness_set = lp5523_set_brightness;
+               res = led_classdev_register(dev, &led->cdev);
+               if (res < 0) {
+                       dev_err(dev, "couldn't register led on channel %d\n",
+                               chan);
+                       return res;
+               }
+               res = sysfs_create_group(&led->cdev.dev->kobj,
+                               &lp5523_led_attribute_group);
+               if (res < 0) {
+                       dev_err(dev, "couldn't register current attribute\n");
+                       led_classdev_unregister(&led->cdev);
+                       return res;
+               }
+       } else {
+               led->led_current = 0;
+       }
+       return 0;
+}
+
+static struct i2c_driver lp5523_driver;
+
+static int lp5523_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lp5523_chip              *chip;
+       struct lp5523_platform_data     *pdata;
+       int ret, i, led;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client = client;
+
+       pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data\n");
+               ret = -EINVAL;
+               goto fail1;
+       }
+
+       mutex_init(&chip->lock);
+
+       chip->pdata   = pdata;
+
+       if (pdata->setup_resources) {
+               ret = pdata->setup_resources();
+               if (ret < 0)
+                       goto fail1;
+       }
+
+       if (pdata->enable) {
+               pdata->enable(0);
+               usleep_range(1000, 10000);
+               pdata->enable(1);
+               usleep_range(1000, 10000); /* Spec says min 500us */
+       }
+
+       ret = lp5523_detect(client);
+       if (ret)
+               goto fail2;
+
+       dev_info(&client->dev, "LP5523 Programmable led chip found\n");
+
+       /* Initialize engines */
+       for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
+               ret = lp5523_init_engine(&chip->engines[i], i + 1);
+               if (ret) {
+                       dev_err(&client->dev, "error initializing engine\n");
+                       goto fail2;
+               }
+       }
+       ret = lp5523_configure(client);
+       if (ret < 0) {
+               dev_err(&client->dev, "error configuring chip\n");
+               goto fail2;
+       }
+
+       /* Initialize leds */
+       chip->num_channels = pdata->num_channels;
+       chip->num_leds = 0;
+       led = 0;
+       for (i = 0; i < pdata->num_channels; i++) {
+               /* Do not initialize channels that are not connected */
+               if (pdata->led_config[i].led_current == 0)
+                       continue;
+
+               ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata);
+               if (ret) {
+                       dev_err(&client->dev, "error initializing leds\n");
+                       goto fail3;
+               }
+               chip->num_leds++;
+
+               chip->leds[led].id = led;
+               /* Set LED current */
+               lp5523_write(client,
+                         LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
+                         chip->leds[led].led_current);
+
+               INIT_WORK(&(chip->leds[led].brightness_work),
+                       lp5523_led_brightness_work);
+
+               led++;
+       }
+
+       ret = lp5523_register_sysfs(client);
+       if (ret) {
+               dev_err(&client->dev, "registering sysfs failed\n");
+               goto fail3;
+       }
+       return ret;
+fail3:
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+fail2:
+       if (pdata->enable)
+               pdata->enable(0);
+       if (pdata->release_resources)
+               pdata->release_resources();
+fail1:
+       kfree(chip);
+       return ret;
+}
+
+static int lp5523_remove(struct i2c_client *client)
+{
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       int i;
+
+       lp5523_unregister_sysfs(client);
+
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+
+       if (chip->pdata->enable)
+               chip->pdata->enable(0);
+       if (chip->pdata->release_resources)
+               chip->pdata->release_resources();
+       kfree(chip);
+       return 0;
+}
+
+static const struct i2c_device_id lp5523_id[] = {
+       { "lp5523", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, lp5523_id);
+
+static struct i2c_driver lp5523_driver = {
+       .driver = {
+               .name   = "lp5523",
+       },
+       .probe          = lp5523_probe,
+       .remove         = lp5523_remove,
+       .id_table       = lp5523_id,
+};
+
+static int __init lp5523_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&lp5523_driver);
+
+       if (ret < 0)
+               printk(KERN_ALERT "Adding lp5523 driver failed\n");
+
+       return ret;
+}
+
+static void __exit lp5523_exit(void)
+{
+       i2c_del_driver(&lp5523_driver);
+}
+
+module_init(lp5523_init);
+module_exit(lp5523_exit);
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
+MODULE_DESCRIPTION("LP5523 LED engine");
+MODULE_LICENSE("GPL");
index 3063f591f0dca0e0eb809bb4b490039d8bcf2943..1739557a903881a246c14d5047cca5a454081894 100644 (file)
@@ -92,3 +92,5 @@ unmap:
 }
 
 arch_initcall(soekris_init);
+
+MODULE_LICENSE("GPL");
index 82b77bd482ffdb4f952f0785c197db6efe1e8736..b09bcbeade9c433c56365204b4848690bf08a366 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
 #include <linux/device.h>
-#include <linux/sysdev.h>
-#include <linux/timer.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
-#include <linux/slab.h>
 #include "leds.h"
 
-struct timer_trig_data {
-       int brightness_on;              /* LED brightness during "on" period.
-                                        * (LED_OFF < brightness_on <= LED_FULL)
-                                        */
-       unsigned long delay_on;         /* milliseconds on */
-       unsigned long delay_off;        /* milliseconds off */
-       struct timer_list timer;
-};
-
-static void led_timer_function(unsigned long data)
-{
-       struct led_classdev *led_cdev = (struct led_classdev *) data;
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
-       unsigned long brightness;
-       unsigned long delay;
-
-       if (!timer_data->delay_on || !timer_data->delay_off) {
-               led_set_brightness(led_cdev, LED_OFF);
-               return;
-       }
-
-       brightness = led_get_brightness(led_cdev);
-       if (!brightness) {
-               /* Time to switch the LED on. */
-               brightness = timer_data->brightness_on;
-               delay = timer_data->delay_on;
-       } else {
-               /* Store the current brightness value to be able
-                * to restore it when the delay_off period is over.
-                */
-               timer_data->brightness_on = brightness;
-               brightness = LED_OFF;
-               delay = timer_data->delay_off;
-       }
-
-       led_set_brightness(led_cdev, brightness);
-
-       mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
-}
-
 static ssize_t led_delay_on_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
-       return sprintf(buf, "%lu\n", timer_data->delay_on);
+       return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
 }
 
 static ssize_t led_delay_on_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
        int ret = -EINVAL;
        char *after;
        unsigned long state = simple_strtoul(buf, &after, 10);
@@ -88,21 +40,7 @@ static ssize_t led_delay_on_store(struct device *dev,
                count++;
 
        if (count == size) {
-               if (timer_data->delay_on != state) {
-                       /* the new value differs from the previous */
-                       timer_data->delay_on = state;
-
-                       /* deactivate previous settings */
-                       del_timer_sync(&timer_data->timer);
-
-                       /* try to activate hardware acceleration, if any */
-                       if (!led_cdev->blink_set ||
-                           led_cdev->blink_set(led_cdev,
-                             &timer_data->delay_on, &timer_data->delay_off)) {
-                               /* no hardware acceleration, blink via timer */
-                               mod_timer(&timer_data->timer, jiffies + 1);
-                       }
-               }
+               led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
                ret = count;
        }
 
@@ -113,16 +51,14 @@ static ssize_t led_delay_off_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
-       return sprintf(buf, "%lu\n", timer_data->delay_off);
+       return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
 }
 
 static ssize_t led_delay_off_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
        int ret = -EINVAL;
        char *after;
        unsigned long state = simple_strtoul(buf, &after, 10);
@@ -132,21 +68,7 @@ static ssize_t led_delay_off_store(struct device *dev,
                count++;
 
        if (count == size) {
-               if (timer_data->delay_off != state) {
-                       /* the new value differs from the previous */
-                       timer_data->delay_off = state;
-
-                       /* deactivate previous settings */
-                       del_timer_sync(&timer_data->timer);
-
-                       /* try to activate hardware acceleration, if any */
-                       if (!led_cdev->blink_set ||
-                           led_cdev->blink_set(led_cdev,
-                             &timer_data->delay_on, &timer_data->delay_off)) {
-                               /* no hardware acceleration, blink via timer */
-                               mod_timer(&timer_data->timer, jiffies + 1);
-                       }
-               }
+               led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
                ret = count;
        }
 
@@ -158,60 +80,34 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
 
 static void timer_trig_activate(struct led_classdev *led_cdev)
 {
-       struct timer_trig_data *timer_data;
        int rc;
 
-       timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
-       if (!timer_data)
-               return;
-
-       timer_data->brightness_on = led_get_brightness(led_cdev);
-       if (timer_data->brightness_on == LED_OFF)
-               timer_data->brightness_on = led_cdev->max_brightness;
-       led_cdev->trigger_data = timer_data;
-
-       init_timer(&timer_data->timer);
-       timer_data->timer.function = led_timer_function;
-       timer_data->timer.data = (unsigned long) led_cdev;
+       led_cdev->trigger_data = NULL;
 
        rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
        if (rc)
-               goto err_out;
+               return;
        rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
        if (rc)
                goto err_out_delayon;
 
-       /* If there is hardware support for blinking, start one
-        * user friendly blink rate chosen by the driver.
-        */
-       if (led_cdev->blink_set)
-               led_cdev->blink_set(led_cdev,
-                       &timer_data->delay_on, &timer_data->delay_off);
+       led_cdev->trigger_data = (void *)1;
 
        return;
 
 err_out_delayon:
        device_remove_file(led_cdev->dev, &dev_attr_delay_on);
-err_out:
-       led_cdev->trigger_data = NULL;
-       kfree(timer_data);
 }
 
 static void timer_trig_deactivate(struct led_classdev *led_cdev)
 {
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
-       unsigned long on = 0, off = 0;
-
-       if (timer_data) {
+       if (led_cdev->trigger_data) {
                device_remove_file(led_cdev->dev, &dev_attr_delay_on);
                device_remove_file(led_cdev->dev, &dev_attr_delay_off);
-               del_timer_sync(&timer_data->timer);
-               kfree(timer_data);
        }
 
-       /* If there is hardware support for blinking, stop it */
-       if (led_cdev->blink_set)
-               led_cdev->blink_set(led_cdev, &on, &off);
+       /* Stop blinking */
+       led_brightness_set(led_cdev, LED_OFF);
 }
 
 static struct led_trigger timer_led_trigger = {
index 444696625171e42a6948eb858299a8a489626510..f5f4da3d0b675644963af93f327f03f455368bd8 100644 (file)
@@ -80,7 +80,7 @@ static void adb_iop_end_req(struct adb_request *req, int state)
 static void adb_iop_complete(struct iop_msg *msg)
 {
        struct adb_request *req;
-       uint flags;
+       unsigned long flags;
 
        local_irq_save(flags);
 
@@ -103,7 +103,7 @@ static void adb_iop_listen(struct iop_msg *msg)
 {
        struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
        struct adb_request *req;
-       uint flags;
+       unsigned long flags;
 #ifdef DEBUG_ADB_IOP
        int i;
 #endif
index 4e957f3140a81c64a75982d8764436962d929a15..324a3663fcdaa35dc9d0553f532543aa8019dd38 100644 (file)
@@ -706,7 +706,7 @@ static struct mdk_personality *find_pers(int level, char *clevel)
 /* return the offset of the super block in 512byte sectors */
 static inline sector_t calc_dev_sboffset(struct block_device *bdev)
 {
-       sector_t num_sectors = bdev->bd_inode->i_size / 512;
+       sector_t num_sectors = i_size_read(bdev->bd_inode) / 512;
        return MD_NEW_SIZE_SECTORS(num_sectors);
 }
 
@@ -1386,7 +1386,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
         */
        switch(minor_version) {
        case 0:
-               sb_start = rdev->bdev->bd_inode->i_size >> 9;
+               sb_start = i_size_read(rdev->bdev->bd_inode) >> 9;
                sb_start -= 8*2;
                sb_start &= ~(sector_t)(4*2-1);
                break;
@@ -1472,7 +1472,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
                        ret = 0;
        }
        if (minor_version)
-               rdev->sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+               rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
                        le64_to_cpu(sb->data_offset);
        else
                rdev->sectors = rdev->sb_start;
@@ -1680,7 +1680,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
                return 0; /* component must fit device */
        if (rdev->sb_start < rdev->data_offset) {
                /* minor versions 1 and 2; superblock before data */
-               max_sectors = rdev->bdev->bd_inode->i_size >> 9;
+               max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
                max_sectors -= rdev->data_offset;
                if (!num_sectors || num_sectors > max_sectors)
                        num_sectors = max_sectors;
@@ -1690,7 +1690,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
        } else {
                /* minor version 0; superblock after data */
                sector_t sb_start;
-               sb_start = (rdev->bdev->bd_inode->i_size >> 9) - 8*2;
+               sb_start = (i_size_read(rdev->bdev->bd_inode) >> 9) - 8*2;
                sb_start &= ~(sector_t)(4*2 - 1);
                max_sectors = rdev->sectors + sb_start - rdev->sb_start;
                if (!num_sectors || num_sectors > max_sectors)
@@ -2584,7 +2584,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                        if (!sectors)
                                return -EBUSY;
                } else if (!sectors)
-                       sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+                       sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
                                rdev->data_offset;
        }
        if (sectors < my_mddev->dev_sectors)
@@ -2797,7 +2797,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
 
        kobject_init(&rdev->kobj, &rdev_ktype);
 
-       size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+       size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
        if (!size) {
                printk(KERN_WARNING 
                        "md: %s has zero or unknown size, marking faulty!\n",
@@ -5235,8 +5235,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 
                if (!mddev->persistent) {
                        printk(KERN_INFO "md: nonpersistent superblock ...\n");
-                       rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
-               } else 
+                       rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
+               } else
                        rdev->sb_start = calc_dev_sboffset(rdev->bdev);
                rdev->sectors = rdev->sb_start;
 
@@ -5306,7 +5306,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
        if (mddev->persistent)
                rdev->sb_start = calc_dev_sboffset(rdev->bdev);
        else
-               rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
+               rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
 
        rdev->sectors = rdev->sb_start;
 
index bad2cedb8d96886cec38af4b0003c476fbdd11f9..a28541b2b1a219e5a2804f20201191f1ff98c953 100644 (file)
@@ -19,7 +19,6 @@ comment "Multimedia core support"
 
 config VIDEO_DEV
        tristate "Video For Linux"
-       depends on BKL # used in many drivers for ioctl handling, need to kill
        ---help---
          V4L core support for video capture and overlay devices, webcams and
          AM/FM radio cards.
index 3d88542612eabfffc799a348c88c8c4a1bf551df..74ee172b5bc992d8dd151338b67ab5d9d65cb271 100644 (file)
@@ -391,7 +391,6 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in
 
 /*****************************************************************************/
 /* i2c-adapter helper functions                                              */
-#include <linux/i2c-id.h>
 
 /* exported algorithm data */
 static struct i2c_algorithm saa7146_algo = {
index 4d0646da6087b05e02c87767232417c2b1f94d93..7ea517b7e18626fd5723c255cb0aee2a102970a8 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 
 #include "dvb_ca_en50221.h"
index 1589d5a5cb4696ab2114019780866aab93622135..cad6634610ea5fb0d6ea59e6c86e322bd1e9638e 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/list.h>
 #include <linux/freezer.h>
 #include <linux/jiffies.h>
-#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 #include <asm/processor.h>
 
index a4991026254dc0223c71f06f475634338c8e2e2d..2311c0a3406c953e4199c627a135be7fdc97843c 100644 (file)
@@ -130,6 +130,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
                            struct dibx000_i2c_master *mst)
 {
        strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
+       i2c_adap->algo = algo;
        i2c_adap->algo_data = NULL;
        i2c_set_adapdata(i2c_adap, mst);
        if (i2c_add_adapter(i2c_adap) < 0)
index 4caeb163a66668da958cdae28058c2e0bb67a3af..3a7ef71087be7110174df8df4968bc65b995a04f 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/io.h>
 #include <asm/div64.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/byteorder/generic.h>
 #include <linux/firmware.h>
index 48f980b21d663ad94b89b17689d62737104b6ac4..3832e5983c19104b92c29d273392dfdae53cc074 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/io.h>
 #include <asm/div64.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/byteorder/generic.h>
 #include <linux/firmware.h>
index c3ae956714e77501954d17bc1a34843200365b2f..d28554f8ce9961f1102a9a22e8f28d71f057e7cd 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/div64.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/byteorder/generic.h>
 #include <linux/firmware.h>
index b540e8072e9295ca8551e65858e5f2670e381d0c..e6b2d085a449ae0a7ba4a424a70014e5a03b7112 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
index ea12782359a024d415dcda5cc87f724ba423f7ae..b9914d7a0c9ffeef06a0b7f02bd2f82c10f1dd9f 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/version.h>
 #include <linux/videodev2.h>
index 3da6e80e1041358e594836fbd9b8146b4dfedb7d..a529619e51f687d1386c6c673a0feaa9ba8d517a 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kdev_t.h>
 #include "bttvp.h"
index 2934770dacc3fee149baef4a20f7d6ed770addad..7bc36670071a8ba333ed0d67999d5f9079adc895 100644 (file)
@@ -2065,8 +2065,9 @@ static int cafe_pci_probe(struct pci_dev *pdev,
                sensor_cfg.clock_speed = 45;
 
        cam->sensor_addr = 0x42;
-       cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
-                       NULL, "ov7670", cam->sensor_addr, NULL);
+       cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
+                       "ov7670", "ov7670", 0, &sensor_cfg, cam->sensor_addr,
+                       NULL);
        if (cam->sensor == NULL) {
                ret = -ENODEV;
                goto out_smbus;
index aab21f3ce4721591c4773b80879524acac1dd43c..4c7cac3b6254eb9ed0b9ca7c47bd525d12cc1c81 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
@@ -1927,10 +1926,9 @@ static int mpeg_open(struct file *file)
                        dev = h;
        }
 
-       if (dev == NULL) {
-               unlock_kernel();
+       if (dev == NULL)
                return -ENODEV;
-       }
+
        mutex_lock(&dev->lock);
 
        /* allocate + initialize per filehandle data */
index a6cc12f8736c803cc1418a0fc0b4b86e3d248f66..9a98dc55f6572fac82e0c6e0936d1af8a03218d9 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
@@ -1576,12 +1575,8 @@ static int mpeg_open(struct file *file)
 
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (NULL == fh) {
-               unlock_kernel();
+       if (!fh)
                return -ENOMEM;
-       }
-
-       lock_kernel();
 
        file->private_data = fh;
        fh->dev      = dev;
@@ -1592,8 +1587,6 @@ static int mpeg_open(struct file *file)
                            V4L2_FIELD_INTERLACED,
                            sizeof(struct cx23885_buffer),
                            fh, NULL);
-       unlock_kernel();
-
        return 0;
 }
 
index 93af9c65b484d26e361bf5f69c7e7318f742a399..3cc9f462d08d9d1d391b8cfcec5fbebc6b6c66d4 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
@@ -743,8 +742,6 @@ static int video_open(struct file *file)
        if (NULL == fh)
                return -ENOMEM;
 
-       lock_kernel();
-
        file->private_data = fh;
        fh->dev      = dev;
        fh->radio    = radio;
@@ -762,8 +759,6 @@ static int video_open(struct file *file)
 
        dprintk(1, "post videobuf_queue_init()\n");
 
-       unlock_kernel();
-
        return 0;
 }
 
index 417d1d5c73c4fead58a7c0133454debaed8a7f73..d7c94848249e1252018e58e25417d6fdd710cc47 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
-#include <linux/smp_lock.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/cx2341x.h>
index d2f159daa8b506d34c5f027f8650a64a7518d184..88b51194f917956a17c734a21d9c2a893b2e5104 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index 380e459f899d3ff0105a274987a7940cd426a5e9..27b5dfdfbb931253fb3f02567084e39ecd97858c 100644 (file)
@@ -451,7 +451,6 @@ static int imx074_probe(struct i2c_client *client,
        ret = imx074_video_probe(icd, client);
        if (ret < 0) {
                icd->ops = NULL;
-               i2c_set_clientdata(client, NULL);
                kfree(priv);
                return ret;
        }
@@ -468,7 +467,6 @@ static int imx074_remove(struct i2c_client *client)
        icd->ops = NULL;
        if (icl->free_bus)
                icl->free_bus(icl);
-       i2c_set_clientdata(client, NULL);
        client->driver = NULL;
        kfree(priv);
 
index 5a000c65ae98ab3f4fa75b26b4f87ba885874290..ce4a75375909b6872e7860f55bc1d66d3e90a414 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/workqueue.h>
 
 #include <media/ir-core.h>
index 4a27862da30d3d0810efb11965ae7019bb1c15c9..072bd2d1cfad46f4c5a25ea33f789409c2848a5c 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
 #include <media/videobuf-dma-contig.h>
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
@@ -903,8 +904,6 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
 static int mx2_camera_set_fmt(struct soc_camera_device *icd,
                               struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct mx2_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
        struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -943,8 +942,6 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
 static int mx2_camera_try_fmt(struct soc_camera_device *icd,
                                  struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct mx2_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
        struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -1024,13 +1021,13 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static int mx2_camera_reqbufs(struct soc_camera_file *icf,
+static int mx2_camera_reqbufs(struct soc_camera_device *icd,
                              struct v4l2_requestbuffers *p)
 {
        int i;
 
        for (i = 0; i < p->count; i++) {
-               struct mx2_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+               struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
                                                      struct mx2_buffer, vb);
                INIT_LIST_HEAD(&buf->vb.queue);
        }
@@ -1151,9 +1148,9 @@ err_out:
 
 static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
 
-       return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+       return videobuf_poll_stream(file, &icd->vb_vidq, pt);
 }
 
 static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
index 29c5fc3481331eb7055dff25f09a90cfc52709b9..aa871c2936b31d9bb821067932f2103889392539 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <mach/ipu.h>
 #include <mach/mx3_camera.h>
+#include <mach/dma.h>
 
 #define MX3_CAM_DRV_NAME "mx3-camera"
 
@@ -638,6 +639,9 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
        struct dma_chan_request *rq = arg;
        struct mx3_camera_pdata *pdata;
 
+       if (!imx_dma_is_ipu(chan))
+               return false;
+
        if (!rq)
                return false;
 
index 7c30e62b50db29357aabbf700203b0c1f7809e03..cbfd07f2d9da71e6563d4b317f51084c438ebc96 100644 (file)
@@ -235,7 +235,7 @@ static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
 
        BUG_ON(in_interrupt());
 
-       videobuf_waiton(vb, 0, 0);
+       videobuf_waiton(vq, vb, 0, 0);
 
        if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
                videobuf_dma_contig_free(vq, vb);
@@ -504,7 +504,7 @@ static void omap1_videobuf_queue(struct videobuf_queue *vq,
                 * empty. Since the transfer of the DMA programming register set
                 * content to the DMA working register set is done automatically
                 * by the DMA hardware, this can pretty well happen while we
-                * are keeping the lock here. Levae fetching it from the queue
+                * are keeping the lock here. Leave fetching it from the queue
                 * to be done when a next DMA interrupt occures instead.
                 */
                return;
@@ -1365,12 +1365,12 @@ static void omap1_cam_init_videobuf(struct videobuf_queue *q,
                videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
                                icd->dev.parent, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-                               sizeof(struct omap1_cam_buf), icd);
+                               sizeof(struct omap1_cam_buf), icd, NULL);
        else
                videobuf_queue_sg_init(q, &omap1_videobuf_ops,
                                icd->dev.parent, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-                               sizeof(struct omap1_cam_buf), icd);
+                               sizeof(struct omap1_cam_buf), icd, NULL);
 
        /* use videobuf mode (auto)selected with the module parameter */
        pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
@@ -1386,7 +1386,7 @@ static void omap1_cam_init_videobuf(struct videobuf_queue *q,
        }
 }
 
-static int omap1_cam_reqbufs(struct soc_camera_file *icf,
+static int omap1_cam_reqbufs(struct soc_camera_device *icd,
                              struct v4l2_requestbuffers *p)
 {
        int i;
@@ -1398,7 +1398,7 @@ static int omap1_cam_reqbufs(struct soc_camera_file *icf,
         * it hadn't triggered
         */
        for (i = 0; i < p->count; i++) {
-               struct omap1_cam_buf *buf = container_of(icf->vb_vidq.bufs[i],
+               struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i],
                                                      struct omap1_cam_buf, vb);
                buf->inwork = 0;
                INIT_LIST_HEAD(&buf->vb.queue);
@@ -1485,10 +1485,10 @@ static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
 
 static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
 {
-       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = file->private_data;
        struct omap1_cam_buf *buf;
 
-       buf = list_entry(icf->vb_vidq.stream.next, struct omap1_cam_buf,
+       buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf,
                         vb.stream);
 
        poll_wait(file, &buf->vb.done, pt);
index b7cfeab0948c9519477725650a1f262db16fad43..cf93de98806894f36ff0a4504efe88d9658f06bf 100644 (file)
@@ -754,7 +754,7 @@ static int ov6650_g_fmt(struct v4l2_subdev *sd,
 
 static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
 {
-       return (width > rect->width >> 1 || height > rect->height >> 1);
+       return width > rect->width >> 1 || height > rect->height >> 1;
 }
 
 static u8 to_clkrc(struct v4l2_fract *timeperframe,
@@ -840,8 +840,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
                coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
                coma_set |= COMA_RAW_RGB | COMA_RGB;
                break;
-       case 0:
-               break;
        default:
                dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
                return -EINVAL;
@@ -1176,7 +1174,6 @@ static int ov6650_probe(struct i2c_client *client,
 
        if (ret) {
                icd->ops = NULL;
-               i2c_set_clientdata(client, NULL);
                kfree(priv);
        }
 
@@ -1187,7 +1184,6 @@ static int ov6650_remove(struct i2c_client *client)
 {
        struct ov6650 *priv = to_ov6650(client);
 
-       i2c_set_clientdata(client, NULL);
        kfree(priv);
        return 0;
 }
index e62beb4efdb472e811609ec96717013ca6ffa74d..f3dc89da4c4eefcd23f7c457c75322c5eb96b0c9 100644 (file)
@@ -62,7 +62,6 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 #include <linux/usb/input.h>
 #endif
index f5a46c45871713df2eab2c0f43bccff5717fc05d..a845753665c1ed267002353703877b33c9d8f1db 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/videodev2.h>
 #include <linux/version.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
index 10a6cbf6a790b05e9bf84df4e1d8e2e3a8ea7a83..0911cb580e186a61ac8a2f781eea1eee05954089 100644 (file)
@@ -6660,6 +6660,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x13c2,
                .subdevice    = 0x2804,
                .driver_data  = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+               .subdevice    = 0x7190,
+               .driver_data  = SAA7134_BOARD_BEHOLD_H7,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+               .subdevice    = 0x7090,
+               .driver_data  = SAA7134_BOARD_BEHOLD_A7,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -6698,18 +6710,6 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = PCI_ANY_ID,
                .subdevice    = PCI_ANY_ID,
                .driver_data  = SAA7134_BOARD_UNKNOWN,
-       }, {
-               .vendor       = PCI_VENDOR_ID_PHILIPS,
-               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-               .subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
-               .subdevice    = 0x7190,
-               .driver_data  = SAA7134_BOARD_BEHOLD_H7,
-       }, {
-               .vendor       = PCI_VENDOR_ID_PHILIPS,
-               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
-               .subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
-               .subdevice    = 0x7090,
-               .driver_data  = SAA7134_BOARD_BEHOLD_A7,
        },{
                /* --- end of list --- */
        }
index 1467a30a434fe29d677d3289d322e6d34a940cff..b890aafe7d640bcc141b2c6edddb3009d73c5245 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 
 #include "saa7134-reg.h"
index 1d9c5cbbbc52cbef4c8f4fe97719967b0f5250b7..041ae8e20f685fdd6a37831dca38862f5fa06927 100644 (file)
@@ -58,7 +58,6 @@
 #include <media/tveeprom.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
-#include <linux/smp_lock.h>
 #include <dvb_demux.h>
 #include <dvb_frontend.h>
 #include <dvb_net.h>
index 41d0166c0f95b5ff8156770155d3affe6ce874c5..41360d7c3e96237d50f9aec1bb449ec2b084eb7e 100644 (file)
@@ -31,7 +31,6 @@ static const char version[] = "0.24";
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/usb.h>
 #include "se401.h"
@@ -951,9 +950,9 @@ static int se401_open(struct file *file)
        struct usb_se401 *se401 = (struct usb_se401 *)dev;
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&se401->lock);
        if (se401->user) {
-               unlock_kernel();
+               mutex_unlock(&se401->lock);
                return -EBUSY;
        }
        se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
@@ -962,7 +961,7 @@ static int se401_open(struct file *file)
        else
                err = -ENOMEM;
        se401->user = !err;
-       unlock_kernel();
+       mutex_unlock(&se401->lock);
 
        return err;
 }
index f07a0f6b71c455a253845df29705ed96c3b32083..b5afe5f841ce27fb5aac5fd259d10d43fb53a837 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include <linux/usb.h>
 #include <linux/mm.h>
@@ -673,14 +672,11 @@ static int v4l_stk_open(struct file *fp)
        vdev = video_devdata(fp);
        dev = vdev_to_camera(vdev);
 
-       lock_kernel();
        if (dev == NULL || !is_present(dev)) {
-               unlock_kernel();
                return -ENXIO;
        }
        fp->private_data = dev;
        usb_autopm_get_interface(dev->interface);
-       unlock_kernel();
 
        return 0;
 }
index 4555f4a5f4c84b94f532d6993a5d0591e4569ae9..c91424c0c1353565f4f599004c46b81d5eaa83bd 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/firmware.h>
-#include <linux/smp_lock.h>
 
 #include "vendorcmds.h"
 #include "pd-common.h"
@@ -485,15 +484,11 @@ static void poseidon_disconnect(struct usb_interface *interface)
        /*unregister v4l2 device */
        v4l2_device_unregister(&pd->v4l2_dev);
 
-       lock_kernel();
-       {
-               pd_dvb_usb_device_exit(pd);
-               poseidon_fm_exit(pd);
+       pd_dvb_usb_device_exit(pd);
+       poseidon_fm_exit(pd);
 
-               poseidon_audio_free(pd);
-               pd_video_exit(pd);
-       }
-       unlock_kernel();
+       poseidon_audio_free(pd);
+       pd_video_exit(pd);
 
        usb_set_intfdata(interface, NULL);
        kref_put(&pd->kref, poseidon_delete);
index 5d6fd01f918a4d5869edcf59eca93154794d38e3..dc17cce2fbb6d39104979b6e51260d8cf21fff07 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/firmware.h>
 #include <linux/ihex.h>
@@ -483,29 +482,28 @@ vicam_open(struct file *file)
                return -EINVAL;
        }
 
-       /* the videodev_lock held above us protects us from
-        * simultaneous opens...for now. we probably shouldn't
-        * rely on this fact forever.
+       /* cam_lock/open_count protects us from simultaneous opens
+        * ... for now. we probably shouldn't rely on this fact forever.
         */
 
-       lock_kernel();
+       mutex_lock(&cam->cam_lock);
        if (cam->open_count > 0) {
                printk(KERN_INFO
                       "vicam_open called on already opened camera");
-               unlock_kernel();
+               mutex_unlock(&cam->cam_lock);
                return -EBUSY;
        }
 
        cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
        if (!cam->raw_image) {
-               unlock_kernel();
+               mutex_unlock(&cam->cam_lock);
                return -ENOMEM;
        }
 
        cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
        if (!cam->framebuf) {
                kfree(cam->raw_image);
-               unlock_kernel();
+               mutex_unlock(&cam->cam_lock);
                return -ENOMEM;
        }
 
@@ -513,10 +511,17 @@ vicam_open(struct file *file)
        if (!cam->cntrlbuf) {
                kfree(cam->raw_image);
                rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-               unlock_kernel();
+               mutex_unlock(&cam->cam_lock);
                return -ENOMEM;
        }
 
+       cam->needsDummyRead = 1;
+       cam->open_count++;
+
+       file->private_data = cam;
+       mutex_unlock(&cam->cam_lock);
+
+
        // First upload firmware, then turn the camera on
 
        if (!cam->is_initialized) {
@@ -527,12 +532,6 @@ vicam_open(struct file *file)
 
        set_camera_power(cam, 1);
 
-       cam->needsDummyRead = 1;
-       cam->open_count++;
-
-       file->private_data = cam;
-       unlock_kernel();
-
        return 0;
 }
 
index db6b828594f513ac562485692e918f63798e41dc..011c0c386995966cddaba715a7b13ced0a122a61 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/vmalloc.h>
index 86294ed35c9b643cc7bab7411904476d0f7467a7..e30e8dfb62052b70bf8d596c80c697d6a23405f3 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <media/v4l2-ioctl.h>
 
 #ifdef CONFIG_COMPAT
index 0ca7978654b56699989a01222fdf9bcdd6fbd45b..03f7f4670e9badd4491f8cddb8e748a848c14119 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
@@ -247,10 +246,12 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                        mutex_unlock(vdev->lock);
        } else if (vdev->fops->ioctl) {
                /* TODO: convert all drivers to unlocked_ioctl */
-               lock_kernel();
+               static DEFINE_MUTEX(v4l2_ioctl_mutex);
+
+               mutex_lock(&v4l2_ioctl_mutex);
                if (video_is_registered(vdev))
                        ret = vdev->fops->ioctl(filp, cmd, arg);
-               unlock_kernel();
+               mutex_unlock(&v4l2_ioctl_mutex);
        } else
                ret = -ENOTTY;
 
index 37fe16181e3c7e13dbeb4e8a58706a3931172577..27f05551183f18ff6bbf739e63a9ff8ec00d1be7 100644 (file)
@@ -388,6 +388,7 @@ struct zoran {
        struct videocodec *vfe; /* video front end */
 
        struct mutex resource_lock;     /* prevent evil stuff */
+       struct mutex other_lock;        /* please merge with above */
 
        u8 initialized;         /* flag if zoran has been correctly initialized */
        int user;               /* number of current users */
index 0aac376c3f7a362e6c7b1345099ecf7ac224a44b..7e6d62467eaaa7bd1e913d5ce104608005ccbc58 100644 (file)
@@ -1227,6 +1227,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
        snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
        spin_lock_init(&zr->spinlock);
        mutex_init(&zr->resource_lock);
+       mutex_init(&zr->other_lock);
        if (pci_enable_device(pdev))
                goto zr_unreg;
        pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
index 401082b853f086bbe67046a561d810fe43e8b173..67a52e844ae613307665f338f67bd5d6ef69828c 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
@@ -913,7 +912,7 @@ static int zoran_open(struct file *file)
        dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
                ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
 
-       lock_kernel();
+       mutex_lock(&zr->other_lock);
 
        if (zr->user >= 2048) {
                dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
@@ -963,14 +962,14 @@ static int zoran_open(struct file *file)
        file->private_data = fh;
        fh->zr = zr;
        zoran_open_init_session(fh);
-       unlock_kernel();
+       mutex_unlock(&zr->other_lock);
 
        return 0;
 
 fail_fh:
        kfree(fh);
 fail_unlock:
-       unlock_kernel();
+       mutex_unlock(&zr->other_lock);
 
        dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n",
                ZR_DEVNAME(zr), res, zr->user);
@@ -989,7 +988,7 @@ zoran_close(struct file  *file)
 
        /* kernel locks (fs/device.c), so don't do that ourselves
         * (prevents deadlocks) */
-       /*mutex_lock(&zr->resource_lock);*/
+       mutex_lock(&zr->other_lock);
 
        zoran_close_end_session(fh);
 
@@ -1023,6 +1022,7 @@ zoran_close(struct file  *file)
                        encoder_call(zr, video, s_routing, 2, 0, 0);
                }
        }
+       mutex_unlock(&zr->other_lock);
 
        file->private_data = NULL;
        kfree(fh->overlay_mask);
@@ -3370,11 +3370,26 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
 #endif
 };
 
+/* please use zr->resource_lock consistently and kill this wrapper */
+static long zoran_ioctl(struct file *file, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct zoran_fh *fh = file->private_data;
+       struct zoran *zr = fh->zr;
+       int ret;
+
+       mutex_lock(&zr->other_lock);
+       ret = video_ioctl2(file, cmd, arg);
+       mutex_unlock(&zr->other_lock);
+
+       return ret;
+}
+
 static const struct v4l2_file_operations zoran_fops = {
        .owner = THIS_MODULE,
        .open = zoran_open,
        .release = zoran_close,
-       .ioctl = video_ioctl2,
+       .unlocked_ioctl = zoran_ioctl,
        .read = zoran_read,
        .write = zoran_write,
        .mmap = zoran_mmap,
index e15220ff52fc7b150da7a11e04c1f7d84c4a5d55..d784c36707c0b12c318c1f2be20fe98b425eabad 100644 (file)
@@ -97,8 +97,7 @@ static u8     mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
 
 static int mptfc_target_alloc(struct scsi_target *starget);
 static int mptfc_slave_alloc(struct scsi_device *sdev);
-static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
-                     void (*done)(struct scsi_cmnd *));
+static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt);
 static void mptfc_target_destroy(struct scsi_target *starget);
 static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
 static void __devexit mptfc_remove(struct pci_dev *pdev);
@@ -650,7 +649,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
 }
 
 static int
-mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptfc_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        struct mptfc_rport_info *ri;
        struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
@@ -681,6 +680,8 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        return mptscsih_qcmd(SCpnt,done);
 }
 
+static DEF_SCSI_QCMD(mptfc_qcmd)
+
 /*
  *     mptfc_display_port_link_speed - displaying link speed
  *     @ioc: Pointer to MPT_ADAPTER structure
index 83a5115f025113d89eb2c793901b443691d5f397..d48c2c6058e1d12f62316d2541cd36dfdb27daaa 100644 (file)
@@ -1889,7 +1889,7 @@ mptsas_slave_alloc(struct scsi_device *sdev)
 }
 
 static int
-mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptsas_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        MPT_SCSI_HOST   *hd;
        MPT_ADAPTER     *ioc;
@@ -1913,6 +1913,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        return mptscsih_qcmd(SCpnt,done);
 }
 
+static DEF_SCSI_QCMD(mptsas_qcmd)
+
 /**
  *     mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
  *             if the device under question is currently in the
index 0e2803155ae20a1cacb1d67037e4d7de0d6155e8..6d9568d2ec59693235e2bf886c6daf46199e659f 100644 (file)
@@ -780,7 +780,7 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
 }
 
 static int
-mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptspi_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
        VirtDevice      *vdevice = SCpnt->device->hostdata;
@@ -805,6 +805,8 @@ mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        return mptscsih_qcmd(SCpnt,done);
 }
 
+static DEF_SCSI_QCMD(mptspi_qcmd)
+
 static void mptspi_slave_destroy(struct scsi_device *sdev)
 {
        struct scsi_target *starget = scsi_target(sdev);
index ea6b2197da8a2fc38afd18aaebd3d0a32338a993..97bdf82ec9059ddced228220d21bbb3e64dc2b99 100644 (file)
@@ -506,7 +506,7 @@ static struct i2o_driver i2o_scsi_driver = {
  *     Locks: takes the controller lock on error path only
  */
 
-static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
+static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
                                 void (*done) (struct scsi_cmnd *))
 {
        struct i2o_controller *c;
@@ -688,7 +688,9 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
 
       exit:
        return rc;
-};
+}
+
+static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
 
 /**
  *     i2o_scsi_abort - abort a running command
index f9b91ba8900c96f027a284185b97fc9dd1e755b0..644d4cd071cc58eb2afc02d09b53bab2f5a3ff38 100644 (file)
@@ -123,7 +123,7 @@ static ssize_t als_sensing_range_store(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct als_data *data = i2c_get_clientdata(client);
-       unsigned int ret_val;
+       int ret_val;
        unsigned long val;
 
        if (strict_strtoul(buf, 10, &val))
@@ -251,7 +251,6 @@ static int apds9802als_probe(struct i2c_client *client,
 
        return res;
 als_error1:
-       i2c_set_clientdata(client, NULL);
        kfree(data);
        return res;
 }
index cee632e645e1982fee9e99ef84e065daf0d17d39..d79a972f2c799c11b2aa4780efb86417eff13854 100644 (file)
@@ -649,7 +649,7 @@ static ssize_t bh1770_power_state_store(struct device *dev,
 {
        struct bh1770_chip *chip =  dev_get_drvdata(dev);
        unsigned long value;
-       size_t ret;
+       ssize_t ret;
 
        if (strict_strtoul(buf, 0, &value))
                return -EINVAL;
@@ -659,8 +659,12 @@ static ssize_t bh1770_power_state_store(struct device *dev,
                pm_runtime_get_sync(dev);
 
                ret = bh1770_lux_rate(chip, chip->lux_rate_index);
-               ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+               if (ret < 0) {
+                       pm_runtime_put(dev);
+                       goto leave;
+               }
 
+               ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
                if (ret < 0) {
                        pm_runtime_put(dev);
                        goto leave;
index 34fe835921c4b751beafaff119ca97fb352e63f6..ca47e62850752b80772bd3d77a246bfe1109b742 100644 (file)
@@ -87,7 +87,7 @@ static ssize_t als_sensing_range_store(struct device *dev,
                struct device_attribute *attr, const  char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
-       unsigned int ret_val;
+       int ret_val;
        unsigned long val;
 
        if (strict_strtoul(buf, 10, &val))
@@ -106,6 +106,8 @@ static ssize_t als_sensing_range_store(struct device *dev,
                val = 4;
 
        ret_val = i2c_smbus_read_byte_data(client, 0x00);
+       if (ret_val < 0)
+               return ret_val;
 
        ret_val &= 0xFC; /*reset the bit before setting them */
        ret_val |= val - 1;
index e1da258bbfb7bfd89c24354e7deb626f4da777f9..0a92436f05389883e8485bdf13fafc19cccd2ca2 100644 (file)
@@ -699,7 +699,8 @@ DEFINE_WINDOW_IO(32)
 #define DEVICE_PCI(dev) NULL
 #endif
 
-#define VORTEX_PCI(vp) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)
+#define VORTEX_PCI(vp)                                                 \
+       ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL))
 
 #ifdef CONFIG_EISA
 #define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL)
@@ -707,7 +708,8 @@ DEFINE_WINDOW_IO(32)
 #define DEVICE_EISA(dev) NULL
 #endif
 
-#define VORTEX_EISA(vp) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL)
+#define VORTEX_EISA(vp)                                                        \
+       ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL))
 
 /* The action to take with a media selection timer tick.
    Note that we deviate from the 3Com order by checking 10base2 before AUI.
index ac422cd332eadd687823fcc4db7ca2eaef997fea..dd16e83933a28f817c1eaa0d47003cb4482c3aa5 100644 (file)
@@ -490,13 +490,11 @@ static inline unsigned int cp_rx_csum_ok (u32 status)
 {
        unsigned int protocol = (status >> 16) & 0x3;
 
-       if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))
+       if (((protocol == RxProtoTCP) && !(status & TCPFail)) ||
+           ((protocol == RxProtoUDP) && !(status & UDPFail)))
                return 1;
-       else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))
-               return 1;
-       else if ((protocol == RxProtoIP) && (!(status & IPFail)))
-               return 1;
-       return 0;
+       else
+               return 0;
 }
 
 static int cp_rx_poll(struct napi_struct *napi, int budget)
index 919080b2c3a50eb48bea7311ac0db4e8d3e8103e..1bf67200994827fd76250e718b3bdf4a67a609e8 100644 (file)
@@ -82,7 +82,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
        addr[0] = addr[1] = 0;
        AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
        if (atl1c_check_eeprom_exist(hw)) {
-               if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+               if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
                        /* Enable OTP CLK */
                        if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
                                otp_ctrl_data |= OTP_CTRL_CLK_EN;
index 43579b3b24acce4e23caac9e9ce1d2f2f811af44..53363108994ee93bed670940b0eb91170a389456 100644 (file)
@@ -3043,7 +3043,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
        atl1_pcie_patch(adapter);
        /* assume we have no link for now */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        setup_timer(&adapter->phy_config_timer, atl1_phy_config,
                    (unsigned long)adapter);
index c36cd2ffbadcaa41e15a043a937d1b1ad62c22b4..93354eee2cfd1e679929054c9cc28fe7b35dea51 100644 (file)
@@ -2458,6 +2458,12 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
        int status, i = 0, num_imgs = 0;
        const u8 *p;
 
+       if (!netif_running(adapter->netdev)) {
+               dev_err(&adapter->pdev->dev,
+                       "Firmware load not allowed (interface is down)\n");
+               return -EPERM;
+       }
+
        strcpy(fw_file, func);
 
        status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
index 9eea225decaf724e7d88243fc8c462c62020f81e..863e73a85fbe0ef4cd48ebac5cd5e95846397ebc 100644 (file)
@@ -20,8 +20,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.60.00-3"
-#define DRV_MODULE_RELDATE      "2010/10/19"
+#define DRV_MODULE_VERSION      "1.60.00-4"
+#define DRV_MODULE_RELDATE      "2010/11/01"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
index 459614d2d7bcfff471f08f2866a1cc667a272a76..94d5f59d5a6f0a1de6dd8cc5ad44fc2083649b98 100644 (file)
@@ -1680,7 +1680,7 @@ static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
                rc = XMIT_PLAIN;
 
        else {
-               if (skb->protocol == htons(ETH_P_IPV6)) {
+               if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) {
                        rc = XMIT_CSUM_V6;
                        if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
                                rc |= XMIT_CSUM_TCP;
index 18c8e23a0e82fafaabe0183700960a194c9524af..4cfd4e9b5586f1740d547b02aa8f86e756c86033 100644 (file)
@@ -244,7 +244,14 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 
        u16 xgxs_config_tx[4];                              /* 0x1A0 */
 
-       u32 Reserved1[57];                                  /* 0x1A8 */
+       u32 Reserved1[56];                                  /* 0x1A8 */
+       u32 default_cfg;                                    /* 0x288 */
+       /*  Enable BAM on KR */
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK                    0x00100000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT                   20
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED                0x00000000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED                 0x00100000
+
        u32 speed_capability_mask2;                         /* 0x28C */
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK                0x0000FFFF
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT               0
index 2326774df843841315d783dfa6c53a073a2ef4b5..580919619252e3d0594f5365226bc295a8efcba9 100644 (file)
@@ -610,7 +610,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params,
        /* reset and unreset the BigMac */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-       udelay(10);
+       msleep(1);
 
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -3525,13 +3525,19 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
 
        /* Enable CL37 BAM */
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_AN_DEVAD,
-                       MDIO_AN_REG_8073_BAM, &val);
-       bnx2x_cl45_write(bp, phy,
-                        MDIO_AN_DEVAD,
-                        MDIO_AN_REG_8073_BAM, val | 1);
+       if (REG_RD(bp, params->shmem_base +
+                        offsetof(struct shmem_region, dev_info.
+                                 port_hw_config[params->port].default_cfg)) &
+           PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
 
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8073_BAM, &val);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8073_BAM, val | 1);
+               DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
+       }
        if (params->loopback_mode == LOOPBACK_EXT) {
                bnx2x_807x_force_10G(bp, phy);
                DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
@@ -5302,7 +5308,7 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u16 autoneg_val, an_1000_val, an_10_100_val;
-       bnx2x_wait_reset_complete(bp, phy);
+
        bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
                      1 << NIG_LATCH_BC_ENABLE_MI_INT);
 
@@ -5431,6 +5437,7 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
 
        /* HW reset */
        bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_wait_reset_complete(bp, phy);
 
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
        return bnx2x_848xx_cmn_config_init(phy, params, vars);
@@ -5441,7 +5448,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port, initialize = 1;
+       u8 port, initialize = 1;
        u16 val;
        u16 temp;
        u32 actual_phy_selection;
@@ -5450,11 +5457,16 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
        /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
 
        msleep(1);
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                       MISC_REGISTERS_GPIO_OUTPUT_HIGH,
                       port);
-       msleep(200); /* 100 is not enough */
-
+       bnx2x_wait_reset_complete(bp, phy);
+       /* Wait for GPHY to come out of reset */
+       msleep(50);
        /* BCM84823 requires that XGXS links up first @ 10G for normal
        behavior */
        temp = vars->line_speed;
@@ -5625,7 +5637,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
                                   struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port;
+       u8 port;
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                            MISC_REGISTERS_GPIO_OUTPUT_LOW,
                            port);
@@ -6928,7 +6944,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                  u8 reset_ext_phy)
 {
        struct bnx2x *bp = params->bp;
-       u8 phy_index, port = params->port;
+       u8 phy_index, port = params->port, clear_latch_ind = 0;
        DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
        /* disable attentions */
        vars->link_status = 0;
@@ -6966,9 +6982,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                                params->phy[phy_index].link_reset(
                                        &params->phy[phy_index],
                                        params);
+                       if (params->phy[phy_index].flags &
+                           FLAGS_REARM_LATCH_SIGNAL)
+                               clear_latch_ind = 1;
                }
        }
 
+       if (clear_latch_ind) {
+               /* Clear latching indication */
+               bnx2x_rearm_latch_signal(bp, port, 0);
+               bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
+                              1 << NIG_LATCH_BC_ENABLE_MI_INT);
+       }
        if (params->phy[INT_PHY].link_reset)
                params->phy[INT_PHY].link_reset(
                        &params->phy[INT_PHY], params);
@@ -6999,6 +7024,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        s8 port;
        s8 port_of_path = 0;
 
+       bnx2x_ext_phy_hw_reset(bp, 0);
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
@@ -7021,7 +7047,8 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
                        return -EINVAL;
                }
                /* disable attentions */
-               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+                              port_of_path*4,
                             (NIG_MASK_XGXS0_LINK_STATUS |
                              NIG_MASK_XGXS0_LINK10G |
                              NIG_MASK_SERDES0_LINK_STATUS |
@@ -7132,7 +7159,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
                (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
        REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
 
-       bnx2x_ext_phy_hw_reset(bp, 1);
+       bnx2x_ext_phy_hw_reset(bp, 0);
        msleep(5);
        for (port = 0; port < PORT_MAX; port++) {
                u32 shmem_base, shmem2_base;
index e9ad16f00b56755847eb887a898c999ef2c08c04..9709b8569666d56ff84fb263429eb6f27c244033 100644 (file)
@@ -9064,7 +9064,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        default:
                pr_err("Unknown board_type (%ld), aborting\n",
                           ent->driver_data);
-               return ENODEV;
+               return -ENODEV;
        }
 
        cid_count += CNIC_CONTEXT_USE;
index bdb68a600382bdcfbe8a9e2cf70f8360821e2567..71a169740d05daf463b04f2ff591a943f8c1847e 100644 (file)
@@ -878,8 +878,10 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(dev);
        if (in_dev) {
+               read_lock(&in_dev->mc_list_lock);
                for (im = in_dev->mc_list; im; im = im->next)
                        ip_mc_rejoin_group(im);
+               read_unlock(&in_dev->mc_list_lock);
        }
 
        rcu_read_unlock();
index 8427533fe313c35cb38727e533cd77dd35cdb4af..20da1996d354d563d8a2616276de477041b2368d 100644 (file)
@@ -33,6 +33,9 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
 MODULE_DESCRIPTION("CAIF SPI driver");
 
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
+
 static int spi_loop;
 module_param(spi_loop, bool, S_IRUGO);
 MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
@@ -41,7 +44,10 @@ MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
 module_param(spi_frm_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
 
-/* SPI padding options. */
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
 module_param(spi_up_head_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
 
@@ -240,15 +246,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
 static const struct file_operations dbgfs_state_fops = {
        .open = dbgfs_open,
        .read = dbgfs_state,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static const struct file_operations dbgfs_frame_fops = {
        .open = dbgfs_open,
        .read = dbgfs_frame,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static inline void dev_debugfs_add(struct cfspi *cfspi)
@@ -337,6 +341,9 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
        u8 *dst = buf;
        caif_assert(buf);
 
+       if (cfspi->slave && !cfspi->slave_talked)
+               cfspi->slave_talked = true;
+
        do {
                struct sk_buff *skb;
                struct caif_payload_info *info;
@@ -357,8 +364,8 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align) {
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1) {
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
                        *dst = (u8)(spad - 1);
                        dst += spad;
                }
@@ -373,7 +380,7 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
                dst += epad;
 
                dev_kfree_skb(skb);
@@ -417,14 +424,14 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align)
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1)
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
 
                /*
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
 
                if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
                        skb_queue_tail(&cfspi->chead, skb);
@@ -433,6 +440,7 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                } else {
                        /* Put back packet. */
                        skb_queue_head(&cfspi->qhead, skb);
+                       break;
                }
        } while (pkts <= CAIF_MAX_SPI_PKTS);
 
@@ -453,6 +461,15 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
 {
        struct cfspi *cfspi = (struct cfspi *)ifc->priv;
 
+       /*
+        * The slave device is the master on the link. Interrupts before the
+        * slave has transmitted are considered spurious.
+        */
+       if (cfspi->slave && !cfspi->slave_talked) {
+               printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
+               return;
+       }
+
        if (!in_interrupt())
                spin_lock(&cfspi->lock);
        if (assert) {
@@ -465,7 +482,8 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
                spin_unlock(&cfspi->lock);
 
        /* Wake up the xfer thread. */
-       wake_up_interruptible(&cfspi->wait);
+       if (assert)
+               wake_up_interruptible(&cfspi->wait);
 }
 
 static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
@@ -523,7 +541,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes added to
                 * get the start of the payload aligned.
                 */
-               if (spi_down_head_align) {
+               if (spi_down_head_align > 1) {
                        spad = 1 + *src;
                        src += spad;
                }
@@ -564,7 +582,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes added to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (pkt_len + spad) & spi_down_tail_align;
+               epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
                src += epad;
        } while ((src - buf) < len);
 
@@ -617,19 +635,28 @@ int cfspi_spi_probe(struct platform_device *pdev)
 
        ndev = alloc_netdev(sizeof(struct cfspi),
                        "cfspi%d", cfspi_setup);
-       if (!dev)
-               return -ENODEV;
+       if (!ndev)
+               return -ENOMEM;
 
        cfspi = netdev_priv(ndev);
        netif_stop_queue(ndev);
        cfspi->ndev = ndev;
        cfspi->pdev = pdev;
 
-       /* Set flow info */
+       /* Set flow info. */
        cfspi->flow_off_sent = 0;
        cfspi->qd_low_mark = LOW_WATER_MARK;
        cfspi->qd_high_mark = HIGH_WATER_MARK;
 
+       /* Set slave info. */
+       if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
+               cfspi->slave = true;
+               cfspi->slave_talked = false;
+       } else {
+               cfspi->slave = false;
+               cfspi->slave_talked = false;
+       }
+
        /* Assign the SPI device. */
        cfspi->dev = dev;
        /* Assign the device ifc to this SPI interface. */
index 2111dbfea6feb8b53f56e73567e54fd4d11a818b..1b9943a4edabb8f48678d7384ac2141d47264908 100644 (file)
@@ -36,10 +36,15 @@ static inline int forward_to_spi_cmd(struct cfspi *cfspi)
 #endif
 
 int spi_frm_align = 2;
-int spi_up_head_align = 1;
-int spi_up_tail_align;
-int spi_down_head_align = 3;
-int spi_down_tail_align = 1;
+
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+int spi_up_head_align   = 1 << 1;
+int spi_up_tail_align   = 1 << 0;
+int spi_down_head_align = 1 << 2;
+int spi_down_tail_align = 1 << 1;
 
 #ifdef CONFIG_DEBUG_FS
 static inline void debugfs_store_prev(struct cfspi *cfspi)
index 407d4e2720750246356af4cf7fd627fe9cad3d91..046d846c652dc4c807bb79b9ee5ffe343368919d 100644 (file)
@@ -3341,7 +3341,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                                adapter->name = adapter->port[i]->name;
 
                        __set_bit(i, &adapter->registered_device_map);
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index f17703f410b3673a096aec05f9085329650c5c52..f50bc98310f8b319cf8cdfe1f1b63a23fff19e72 100644 (file)
@@ -3736,7 +3736,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 
                        __set_bit(i, &adapter->registered_device_map);
                        adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index 555ecc5a2e939b25028ac6a61cf2792da379caa7..c3449bbc585a682b57a39b306f251f9691e27e0b 100644 (file)
@@ -753,7 +753,9 @@ static int cxgb4vf_open(struct net_device *dev)
        if (err)
                return err;
        set_bit(pi->port_id, &adapter->open_device_map);
-       link_start(dev);
+       err = link_start(dev);
+       if (err)
+               return err;
        netif_tx_start_all_queues(dev);
        return 0;
 }
@@ -1103,18 +1105,6 @@ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr)
        return 0;
 }
 
-/*
- * Return a TX Queue on which to send the specified skb.
- */
-static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb)
-{
-       /*
-        * XXX For now just use the default hash but we probably want to
-        * XXX look at other possibilities ...
-        */
-       return skb_tx_hash(dev, skb);
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Poll all of our receive queues.  This is called outside of normal interrupt
@@ -2074,6 +2064,22 @@ static int adap_init0(struct adapter *adapter)
                return err;
        }
 
+       /*
+        * Some environments do not properly handle PCIE FLRs -- e.g. in Linux
+        * 2.6.31 and later we can't call pci_reset_function() in order to
+        * issue an FLR because of a self- deadlock on the device semaphore.
+        * Meanwhile, the OS infrastructure doesn't issue FLRs in all the
+        * cases where they're needed -- for instance, some versions of KVM
+        * fail to reset "Assigned Devices" when the VM reboots.  Therefore we
+        * use the firmware based reset in order to reset any per function
+        * state.
+        */
+       err = t4vf_fw_reset(adapter);
+       if (err < 0) {
+               dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err);
+               return err;
+       }
+
        /*
         * Grab basic operational parameters.  These will predominantly have
         * been set up by the Physical Function Driver or will be hard coded
@@ -2417,7 +2423,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops     = {
        .ndo_get_stats          = cxgb4vf_get_stats,
        .ndo_set_rx_mode        = cxgb4vf_set_rxmode,
        .ndo_set_mac_address    = cxgb4vf_set_mac_addr,
-       .ndo_select_queue       = cxgb4vf_select_queue,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_do_ioctl           = cxgb4vf_do_ioctl,
        .ndo_change_mtu         = cxgb4vf_change_mtu,
@@ -2600,7 +2605,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                netif_carrier_off(netdev);
-               netif_tx_stop_all_queues(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
@@ -2625,7 +2629,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                netdev->do_ioctl = cxgb4vf_do_ioctl;
                netdev->change_mtu = cxgb4vf_change_mtu;
                netdev->set_mac_address = cxgb4vf_set_mac_addr;
-               netdev->select_queue = cxgb4vf_select_queue;
 #ifdef CONFIG_NET_POLL_CONTROLLER
                netdev->poll_controller = cxgb4vf_poll_controller;
 #endif
@@ -2844,6 +2847,14 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
        CH_DEVICE(0x4800, 0),   /* T440-dbg */
        CH_DEVICE(0x4801, 0),   /* T420-cr */
        CH_DEVICE(0x4802, 0),   /* T422-cr */
+       CH_DEVICE(0x4803, 0),   /* T440-cr */
+       CH_DEVICE(0x4804, 0),   /* T420-bch */
+       CH_DEVICE(0x4805, 0),   /* T440-bch */
+       CH_DEVICE(0x4806, 0),   /* T460-ch */
+       CH_DEVICE(0x4807, 0),   /* T420-so */
+       CH_DEVICE(0x4808, 0),   /* T420-cx */
+       CH_DEVICE(0x4809, 0),   /* T420-bt */
+       CH_DEVICE(0x480a, 0),   /* T404-bt */
        { 0, }
 };
 
index f10864ddafbef62492fc95608e0d0f7b8737c561..ecf0770bf0ff60bde745ff12c00e337a4aa54982 100644 (file)
@@ -154,13 +154,14 @@ enum {
         */
        RX_COPY_THRES = 256,
        RX_PULL_LEN = 128,
-};
 
-/*
- * Can't define this in the above enum because PKTSHIFT isn't a constant in
- * the VF Driver ...
- */
-#define RX_PKT_PULL_LEN (RX_PULL_LEN + PKTSHIFT)
+       /*
+        * Main body length for sk_buffs used for RX Ethernet packets with
+        * fragments.  Should be >= RX_PULL_LEN but possibly bigger to give
+        * pskb_may_pull() some room.
+        */
+       RX_SKB_LEN = 512,
+};
 
 /*
  * Software state per TX descriptor.
@@ -1354,6 +1355,67 @@ out_free:
        return NETDEV_TX_OK;
 }
 
+/**
+ *     t4vf_pktgl_to_skb - build an sk_buff from a packet gather list
+ *     @gl: the gather list
+ *     @skb_len: size of sk_buff main body if it carries fragments
+ *     @pull_len: amount of data to move to the sk_buff's main body
+ *
+ *     Builds an sk_buff from the given packet gather list.  Returns the
+ *     sk_buff or %NULL if sk_buff allocation failed.
+ */
+struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl,
+                                 unsigned int skb_len, unsigned int pull_len)
+{
+       struct sk_buff *skb;
+       struct skb_shared_info *ssi;
+
+       /*
+        * If the ingress packet is small enough, allocate an skb large enough
+        * for all of the data and copy it inline.  Otherwise, allocate an skb
+        * with enough room to pull in the header and reference the rest of
+        * the data via the skb fragment list.
+        *
+        * Below we rely on RX_COPY_THRES being less than the smallest Rx
+        * buff!  size, which is expected since buffers are at least
+        * PAGE_SIZEd.  In this case packets up to RX_COPY_THRES have only one
+        * fragment.
+        */
+       if (gl->tot_len <= RX_COPY_THRES) {
+               /* small packets have only one fragment */
+               skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
+               if (unlikely(!skb))
+                       goto out;
+               __skb_put(skb, gl->tot_len);
+               skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
+       } else {
+               skb = alloc_skb(skb_len, GFP_ATOMIC);
+               if (unlikely(!skb))
+                       goto out;
+               __skb_put(skb, pull_len);
+               skb_copy_to_linear_data(skb, gl->va, pull_len);
+
+               ssi = skb_shinfo(skb);
+               ssi->frags[0].page = gl->frags[0].page;
+               ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len;
+               ssi->frags[0].size = gl->frags[0].size - pull_len;
+               if (gl->nfrags > 1)
+                       memcpy(&ssi->frags[1], &gl->frags[1],
+                              (gl->nfrags-1) * sizeof(skb_frag_t));
+               ssi->nr_frags = gl->nfrags;
+
+               skb->len = gl->tot_len;
+               skb->data_len = skb->len - pull_len;
+               skb->truesize += skb->data_len;
+
+               /* Get a reference for the last page, we don't own it */
+               get_page(gl->frags[gl->nfrags - 1].page);
+       }
+
+out:
+       return skb;
+}
+
 /**
  *     t4vf_pktgl_free - free a packet gather list
  *     @gl: the gather list
@@ -1463,10 +1525,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
 {
        struct sk_buff *skb;
        struct port_info *pi;
-       struct skb_shared_info *ssi;
        const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
        bool csum_ok = pkt->csum_calc && !pkt->err_vec;
-       unsigned int len = be16_to_cpu(pkt->len);
        struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
 
        /*
@@ -1481,42 +1541,14 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
        }
 
        /*
-        * If the ingress packet is small enough, allocate an skb large enough
-        * for all of the data and copy it inline.  Otherwise, allocate an skb
-        * with enough room to pull in the header and reference the rest of
-        * the data via the skb fragment list.
+        * Convert the Packet Gather List into an skb.
         */
-       if (len <= RX_COPY_THRES) {
-               /* small packets have only one fragment */
-               skb = alloc_skb(gl->frags[0].size, GFP_ATOMIC);
-               if (!skb)
-                       goto nomem;
-               __skb_put(skb, gl->frags[0].size);
-               skb_copy_to_linear_data(skb, gl->va, gl->frags[0].size);
-       } else {
-               skb = alloc_skb(RX_PKT_PULL_LEN, GFP_ATOMIC);
-               if (!skb)
-                       goto nomem;
-               __skb_put(skb, RX_PKT_PULL_LEN);
-               skb_copy_to_linear_data(skb, gl->va, RX_PKT_PULL_LEN);
-
-               ssi = skb_shinfo(skb);
-               ssi->frags[0].page = gl->frags[0].page;
-               ssi->frags[0].page_offset = (gl->frags[0].page_offset +
-                                            RX_PKT_PULL_LEN);
-               ssi->frags[0].size = gl->frags[0].size - RX_PKT_PULL_LEN;
-               if (gl->nfrags > 1)
-                       memcpy(&ssi->frags[1], &gl->frags[1],
-                              (gl->nfrags-1) * sizeof(skb_frag_t));
-               ssi->nr_frags = gl->nfrags;
-               skb->len = len + PKTSHIFT;
-               skb->data_len = skb->len - RX_PKT_PULL_LEN;
-               skb->truesize += skb->data_len;
-
-               /* Get a reference for the last page, we don't own it */
-               get_page(gl->frags[gl->nfrags - 1].page);
+       skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN);
+       if (unlikely(!skb)) {
+               t4vf_pktgl_free(gl);
+               rxq->stats.rx_drops++;
+               return 0;
        }
-
        __skb_pull(skb, PKTSHIFT);
        skb->protocol = eth_type_trans(skb, rspq->netdev);
        skb_record_rx_queue(skb, rspq->idx);
@@ -1549,11 +1581,6 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
                netif_receive_skb(skb);
 
        return 0;
-
-nomem:
-       t4vf_pktgl_free(gl);
-       rxq->stats.rx_drops++;
-       return 0;
 }
 
 /**
@@ -1679,6 +1706,7 @@ int process_responses(struct sge_rspq *rspq, int budget)
                                }
                                len = RSPD_LEN(len);
                        }
+                       gl.tot_len = len;
 
                        /*
                         * Gather packet fragments.
index 873cb7d86c57fc50ae3c71d6638c5e2b58e2ca07..a65c80aed1f2a214d99e520a2125755e2c16ecec 100644 (file)
@@ -235,6 +235,7 @@ static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
 int __devinit t4vf_wait_dev_ready(struct adapter *);
 int __devinit t4vf_port_init(struct adapter *, int);
 
+int t4vf_fw_reset(struct adapter *);
 int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *);
 int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
 
index ea1c123f0cb4b9e44eeac857920622aa9d51e8b5..e306c20dfaee3fd2c54a7d4e3497ddd8ba787d19 100644 (file)
@@ -325,6 +325,25 @@ int __devinit t4vf_port_init(struct adapter *adapter, int pidx)
        return 0;
 }
 
+/**
+ *      t4vf_fw_reset - issue a reset to FW
+ *      @adapter: the adapter
+ *
+ *     Issues a reset command to FW.  For a Physical Function this would
+ *     result in the Firmware reseting all of its state.  For a Virtual
+ *     Function this just resets the state associated with the VF.
+ */
+int t4vf_fw_reset(struct adapter *adapter)
+{
+       struct fw_reset_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) |
+                                     FW_CMD_WRITE);
+       cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+       return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
 /**
  *     t4vf_query_params - query FW or device parameters
  *     @adapter: the adapter
index 4686c3983fc3044f0e0af47cf75dee71b6dadb02..4d62f7bfa0367578471f2773f04a365fed7db972 100644 (file)
@@ -31,7 +31,7 @@
 
 char e1000_driver_name[] = "e1000";
 static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-#define DRV_VERSION "7.3.21-k6-NAPI"
+#define DRV_VERSION "7.3.21-k8-NAPI"
 const char e1000_driver_version[] = DRV_VERSION;
 static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 
@@ -485,9 +485,6 @@ void e1000_down(struct e1000_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        u32 rctl, tctl;
 
-       /* signal that we're down so the interrupt handler does not
-        * reschedule our watchdog timer */
-       set_bit(__E1000_DOWN, &adapter->flags);
 
        /* disable receives in the hardware */
        rctl = er32(RCTL);
@@ -508,6 +505,13 @@ void e1000_down(struct e1000_adapter *adapter)
 
        e1000_irq_disable(adapter);
 
+       /*
+        * Setting DOWN must be after irq_disable to prevent
+        * a screaming interrupt.  Setting DOWN also prevents
+        * timers and tasks from rescheduling.
+        */
+       set_bit(__E1000_DOWN, &adapter->flags);
+
        del_timer_sync(&adapter->tx_fifo_stall_timer);
        del_timer_sync(&adapter->watchdog_timer);
        del_timer_sync(&adapter->phy_info_timer);
index 49e4ce1246a75e01c30a623de0031707fe0273c9..d1bec6269173844cfb17786c99936beee8dfd197 100644 (file)
@@ -577,11 +577,10 @@ static int gfar_parse_group(struct device_node *np,
                        irq_of_parse_and_map(np, 1);
                priv->gfargrp[priv->num_grps].interruptError =
                        irq_of_parse_and_map(np,2);
-               if (priv->gfargrp[priv->num_grps].interruptTransmit < 0 ||
-                       priv->gfargrp[priv->num_grps].interruptReceive < 0 ||
-                       priv->gfargrp[priv->num_grps].interruptError < 0) {
+               if (priv->gfargrp[priv->num_grps].interruptTransmit == NO_IRQ ||
+                   priv->gfargrp[priv->num_grps].interruptReceive  == NO_IRQ ||
+                   priv->gfargrp[priv->num_grps].interruptError    == NO_IRQ)
                        return -EINVAL;
-               }
        }
 
        priv->gfargrp[priv->num_grps].grp_id = priv->num_grps;
index 5c566ebc54b80f7da56a4cdf71b68368065c864f..3bc8e276ba4d713370f86af90d7b4b1b22209dfb 100644 (file)
@@ -635,9 +635,10 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
 
+       device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC);
+
        spin_lock_irqsave(&priv->bflock, flags);
-       priv->wol_en = wol->wolopts & WAKE_MAGIC ? 1 : 0;
-       device_set_wakeup_enable(&dev->dev, priv->wol_en);
+       priv->wol_en =  !!device_may_wakeup(&dev->dev);
        spin_unlock_irqrestore(&priv->bflock, flags);
 
        return 0;
index 385dc3204cb7eefbbaa184f0601267abe7c392ee..06bb9b7994585318bb723046a0804a39a4a4a5e8 100644 (file)
@@ -2871,7 +2871,6 @@ static int __devinit emac_probe(struct platform_device *ofdev,
        SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
 
        netif_carrier_off(ndev);
-       netif_stop_queue(ndev);
 
        err = register_netdev(ndev);
        if (err) {
index dc019809234352418978474531efa675a4e879a2..aa93655c3aa7c1da10f8aeda9eaf2a1535b06756 100644 (file)
@@ -88,16 +88,14 @@ static const char *ipg_brand_name[] = {
        "IC PLUS IP1000 1000/100/10 based NIC",
        "Sundance Technology ST2021 based NIC",
        "Tamarack Microelectronics TC9020/9021 based NIC",
-       "Tamarack Microelectronics TC9020/9021 based NIC",
        "D-Link NIC IP1000A"
 };
 
 static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = {
        { PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
        { PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
-       { PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
-       { PCI_VDEVICE(DLINK,    0x9021), 3 },
-       { PCI_VDEVICE(DLINK,    0x4020), 4 },
+       { PCI_VDEVICE(DLINK,    0x9021), 2 },
+       { PCI_VDEVICE(DLINK,    0x4020), 3 },
        { 0, }
 };
 
index 00b38bccd6d0fd51f19cfe383f71a1f5952d6a43..52a7c86af66347c388d24d29b043fe52e6a2ca5f 100644 (file)
@@ -258,7 +258,7 @@ static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
 
        /* Baud Rate Error Correction x 10000 */
        u32 rate_err_array[] = {
-               0000, 0625, 1250, 1875,
+                  0,  625, 1250, 1875,
                2500, 3125, 3750, 4375,
                5000, 5625, 6250, 6875,
                7500, 8125, 8750, 9375,
index 2bd3eb4ee5a1996d9c219c90419c0b9a455c0b5b..fbad4d819608f234d0eff25175bccf9a8545c20b 100644 (file)
@@ -764,8 +764,9 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
 #ifdef IXGBE_FCOE
                                /* adjust for FCoE Sequence Offload */
                                if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
-                                   && (skb->protocol == htons(ETH_P_FCOE)) &&
-                                   skb_is_gso(skb)) {
+                                   && skb_is_gso(skb)
+                                   && vlan_get_protocol(skb) ==
+                                   htons(ETH_P_FCOE)) {
                                        hlen = skb_transport_offset(skb) +
                                                sizeof(struct fc_frame_header) +
                                                sizeof(struct fcoe_crc_eof);
@@ -5823,7 +5824,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
 
 static int ixgbe_tso(struct ixgbe_adapter *adapter,
                     struct ixgbe_ring *tx_ring, struct sk_buff *skb,
-                    u32 tx_flags, u8 *hdr_len)
+                    u32 tx_flags, u8 *hdr_len, __be16 protocol)
 {
        struct ixgbe_adv_tx_context_desc *context_desc;
        unsigned int i;
@@ -5841,7 +5842,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
                l4len = tcp_hdrlen(skb);
                *hdr_len += l4len;
 
-               if (skb->protocol == htons(ETH_P_IP)) {
+               if (protocol == htons(ETH_P_IP)) {
                        struct iphdr *iph = ip_hdr(skb);
                        iph->tot_len = 0;
                        iph->check = 0;
@@ -5880,7 +5881,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
                type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
                                   IXGBE_ADVTXD_DTYP_CTXT);
 
-               if (skb->protocol == htons(ETH_P_IP))
+               if (protocol == htons(ETH_P_IP))
                        type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
                type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
                context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
@@ -5906,16 +5907,10 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
        return false;
 }
 
-static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
+static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb,
+                     __be16 protocol)
 {
        u32 rtn = 0;
-       __be16 protocol;
-
-       if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
-               protocol = ((const struct vlan_ethhdr *)skb->data)->
-                                       h_vlan_encapsulated_proto;
-       else
-               protocol = skb->protocol;
 
        switch (protocol) {
        case cpu_to_be16(ETH_P_IP):
@@ -5943,7 +5938,7 @@ static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
        default:
                if (unlikely(net_ratelimit()))
                        e_warn(probe, "partial checksum but proto=%x!\n",
-                              skb->protocol);
+                              protocol);
                break;
        }
 
@@ -5952,7 +5947,8 @@ static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
 
 static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
                          struct ixgbe_ring *tx_ring,
-                         struct sk_buff *skb, u32 tx_flags)
+                         struct sk_buff *skb, u32 tx_flags,
+                         __be16 protocol)
 {
        struct ixgbe_adv_tx_context_desc *context_desc;
        unsigned int i;
@@ -5981,7 +5977,7 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
                                    IXGBE_ADVTXD_DTYP_CTXT);
 
                if (skb->ip_summed == CHECKSUM_PARTIAL)
-                       type_tucmd_mlhl |= ixgbe_psum(adapter, skb);
+                       type_tucmd_mlhl |= ixgbe_psum(adapter, skb, protocol);
 
                context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
                /* use index zero for tx checksum offload */
@@ -6179,7 +6175,7 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
 }
 
 static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
-                     int queue, u32 tx_flags)
+                     int queue, u32 tx_flags, __be16 protocol)
 {
        struct ixgbe_atr_input atr_input;
        struct tcphdr *th;
@@ -6190,7 +6186,7 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
        u8 l4type = 0;
 
        /* Right now, we support IPv4 only */
-       if (skb->protocol != htons(ETH_P_IP))
+       if (protocol != htons(ETH_P_IP))
                return;
        /* check if we're UDP or TCP */
        if (iph->protocol == IPPROTO_TCP) {
@@ -6257,10 +6253,13 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
        int txq = smp_processor_id();
-
 #ifdef IXGBE_FCOE
-       if ((skb->protocol == htons(ETH_P_FCOE)) ||
-           (skb->protocol == htons(ETH_P_FIP))) {
+       __be16 protocol;
+
+       protocol = vlan_get_protocol(skb);
+
+       if ((protocol == htons(ETH_P_FCOE)) ||
+           (protocol == htons(ETH_P_FIP))) {
                if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
                        txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1);
                        txq += adapter->ring_feature[RING_F_FCOE].mask;
@@ -6303,6 +6302,9 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
        int tso;
        int count = 0;
        unsigned int f;
+       __be16 protocol;
+
+       protocol = vlan_get_protocol(skb);
 
        if (vlan_tx_tag_present(skb)) {
                tx_flags |= vlan_tx_tag_get(skb);
@@ -6323,8 +6325,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
        /* for FCoE with DCB, we force the priority to what
         * was specified by the switch */
        if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED &&
-           (skb->protocol == htons(ETH_P_FCOE) ||
-            skb->protocol == htons(ETH_P_FIP))) {
+           (protocol == htons(ETH_P_FCOE) ||
+            protocol == htons(ETH_P_FIP))) {
 #ifdef CONFIG_IXGBE_DCB
                if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
                        tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK
@@ -6334,7 +6336,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
                }
 #endif
                /* flag for FCoE offloads */
-               if (skb->protocol == htons(ETH_P_FCOE))
+               if (protocol == htons(ETH_P_FCOE))
                        tx_flags |= IXGBE_TX_FLAGS_FCOE;
        }
 #endif
@@ -6368,9 +6370,10 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
                        tx_flags |= IXGBE_TX_FLAGS_FSO;
 #endif /* IXGBE_FCOE */
        } else {
-               if (skb->protocol == htons(ETH_P_IP))
+               if (protocol == htons(ETH_P_IP))
                        tx_flags |= IXGBE_TX_FLAGS_IPV4;
-               tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+               tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len,
+                               protocol);
                if (tso < 0) {
                        dev_kfree_skb_any(skb);
                        return NETDEV_TX_OK;
@@ -6378,7 +6381,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
 
                if (tso)
                        tx_flags |= IXGBE_TX_FLAGS_TSO;
-               else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+               else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags,
+                                      protocol) &&
                         (skb->ip_summed == CHECKSUM_PARTIAL))
                        tx_flags |= IXGBE_TX_FLAGS_CSUM;
        }
@@ -6392,7 +6396,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev
                             test_bit(__IXGBE_FDIR_INIT_DONE,
                                      &tx_ring->reinit_state)) {
                                ixgbe_atr(adapter, skb, tx_ring->queue_index,
-                                         tx_flags);
+                                         tx_flags, protocol);
                                tx_ring->atr_count = 0;
                        }
                }
index d85edf3119c2625d999b22a41b6159ba9ebf7a24..c57d9a43cecacbf8a668a0c4b1cca5e7b93c3521 100644 (file)
@@ -2955,11 +2955,7 @@ jme_init_one(struct pci_dev *pdev,
         * Tell stack that we are not ready to work until open()
         */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
-       /*
-        * Register netdev
-        */
        rc = register_netdev(netdev);
        if (rc) {
                pr_err("Cannot register net device\n");
index a75ba9517404d94ca7c3da59472cfb80a57025c6..e1d30d7f207121a5de4636fd85b8bf7d9b76acb5 100644 (file)
@@ -41,9 +41,6 @@
 MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
-MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME);
 MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME);
 
 char netxen_nic_driver_name[] = "netxen_nic";
index d2e166e29dda2ea5e972526a89af60097221fa0a..8a4d19e5de064bd3fbbb11a2d2e916a28cf593b0 100644 (file)
@@ -111,13 +111,14 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id);
 
 typedef struct axnet_dev_t {
        struct pcmcia_device    *p_dev;
-    caddr_t            base;
-    struct timer_list  watchdog;
-    int                        stale, fast_poll;
-    u_short            link_status;
-    u_char             duplex_flag;
-    int                        phy_id;
-    int                        flags;
+       caddr_t base;
+       struct timer_list       watchdog;
+       int     stale, fast_poll;
+       u_short link_status;
+       u_char  duplex_flag;
+       int     phy_id;
+       int     flags;
+       int     active_low;
 } axnet_dev_t;
 
 static inline axnet_dev_t *PRIV(struct net_device *dev)
@@ -322,6 +323,8 @@ static int axnet_config(struct pcmcia_device *link)
     if (info->flags & IS_AX88790)
        outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
 
+    info->active_low = 0;
+
     for (i = 0; i < 32; i++) {
        j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
        j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
@@ -329,15 +332,18 @@ static int axnet_config(struct pcmcia_device *link)
        if ((j != 0) && (j != 0xffff)) break;
     }
 
-    /* Maybe PHY is in power down mode. (PPD_SET = 1) 
-       Bit 2 of CCSR is active low. */ 
     if (i == 32) {
+       /* Maybe PHY is in power down mode. (PPD_SET = 1)
+          Bit 2 of CCSR is active low. */
        pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
        for (i = 0; i < 32; i++) {
            j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
            j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
            if (j == j2) continue;
-           if ((j != 0) && (j != 0xffff)) break;
+           if ((j != 0) && (j != 0xffff)) {
+               info->active_low = 1;
+               break;
+           }
        }
     }
 
@@ -383,8 +389,12 @@ static int axnet_suspend(struct pcmcia_device *link)
 static int axnet_resume(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
+       axnet_dev_t *info = PRIV(dev);
 
        if (link->open) {
+               if (info->active_low == 1)
+                       pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
+
                axnet_reset_8390(dev);
                AX88190_init(dev, 1);
                netif_device_attach(dev);
index f0bd1a1aba3ab3413a16eab296b4881d99ea1145..e8b9c53c304b63d2ba2b4a530504e5fafb08f6dc 100644 (file)
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/marvell_phy.h>
+#include <linux/of.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#define MII_MARVELL_PHY_PAGE           22
+
 #define MII_M1011_IEVENT               0x13
 #define MII_M1011_IEVENT_CLEAR         0x0000
 
@@ -80,7 +83,6 @@
 #define MII_88E1121_PHY_LED_CTRL       16
 #define MII_88E1121_PHY_LED_PAGE       3
 #define MII_88E1121_PHY_LED_DEF                0x0030
-#define MII_88E1121_PHY_PAGE           22
 
 #define MII_M1011_PHY_STATUS           0x11
 #define MII_M1011_PHY_STATUS_1000      0x8000
@@ -186,13 +188,94 @@ static int marvell_config_aneg(struct phy_device *phydev)
        return 0;
 }
 
+#ifdef CONFIG_OF_MDIO
+/*
+ * Set and/or override some configuration registers based on the
+ * marvell,reg-init property stored in the of_node for the phydev.
+ *
+ * marvell,reg-init = <reg-page reg mask value>,...;
+ *
+ * There may be one or more sets of <reg-page reg mask value>:
+ *
+ * reg-page: which register bank to use.
+ * reg: the register.
+ * mask: if non-zero, ANDed with existing register value.
+ * value: ORed with the masked value and written to the regiser.
+ *
+ */
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+       const __be32 *paddr;
+       int len, i, saved_page, current_page, page_changed, ret;
+
+       if (!phydev->dev.of_node)
+               return 0;
+
+       paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
+       if (!paddr || len < (4 * sizeof(*paddr)))
+               return 0;
+
+       saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+       if (saved_page < 0)
+               return saved_page;
+       page_changed = 0;
+       current_page = saved_page;
+
+       ret = 0;
+       len /= sizeof(*paddr);
+       for (i = 0; i < len - 3; i += 4) {
+               u16 reg_page = be32_to_cpup(paddr + i);
+               u16 reg = be32_to_cpup(paddr + i + 1);
+               u16 mask = be32_to_cpup(paddr + i + 2);
+               u16 val_bits = be32_to_cpup(paddr + i + 3);
+               int val;
+
+               if (reg_page != current_page) {
+                       current_page = reg_page;
+                       page_changed = 1;
+                       ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
+                       if (ret < 0)
+                               goto err;
+               }
+
+               val = 0;
+               if (mask) {
+                       val = phy_read(phydev, reg);
+                       if (val < 0) {
+                               ret = val;
+                               goto err;
+                       }
+                       val &= mask;
+               }
+               val |= val_bits;
+
+               ret = phy_write(phydev, reg, val);
+               if (ret < 0)
+                       goto err;
+
+       }
+err:
+       if (page_changed) {
+               i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
+               if (ret == 0)
+                       ret = i;
+       }
+       return ret;
+}
+#else
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+       return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
 static int m88e1121_config_aneg(struct phy_device *phydev)
 {
        int err, oldpage, mscr;
 
-       oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+       oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
 
-       err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
                        MII_88E1121_PHY_MSCR_PAGE);
        if (err < 0)
                return err;
@@ -218,7 +301,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
                        return err;
        }
 
-       phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+       phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
 
        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
        if (err < 0)
@@ -229,11 +312,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+       oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
 
-       phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
+       phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
        phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
-       phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+       phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
 
        err = genphy_config_aneg(phydev);
 
@@ -244,9 +327,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
 {
        int err, oldpage, mscr;
 
-       oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+       oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
 
-       err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
                        MII_88E1121_PHY_MSCR_PAGE);
        if (err < 0)
                return err;
@@ -258,7 +341,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
        if (err < 0)
                return err;
 
@@ -368,6 +451,9 @@ static int m88e1111_config_init(struct phy_device *phydev)
                        return err;
        }
 
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
 
        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
        if (err < 0)
@@ -398,7 +484,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
        int err;
 
        /* Change address */
-       err = phy_write(phydev, 0x16, 0x0002);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
        if (err < 0)
                return err;
 
@@ -408,7 +494,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
                return err;
 
        /* Change address */
-       err = phy_write(phydev, 0x16, 0x0003);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
        if (err < 0)
                return err;
 
@@ -420,8 +506,42 @@ static int m88e1118_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
+
        /* Reset address */
-       err = phy_write(phydev, 0x16, 0x0);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int m88e1149_config_init(struct phy_device *phydev)
+{
+       int err;
+
+       /* Change address */
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
+       if (err < 0)
+               return err;
+
+       /* Enable 1000 Mbit */
+       err = phy_write(phydev, 0x15, 0x1048);
+       if (err < 0)
+               return err;
+
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
+
+       /* Reset address */
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
        if (err < 0)
                return err;
 
@@ -491,6 +611,10 @@ static int m88e1145_config_init(struct phy_device *phydev)
                }
        }
 
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
+
        return 0;
 }
 
@@ -684,6 +808,19 @@ static struct phy_driver marvell_drivers[] = {
                .config_intr = &marvell_config_intr,
                .driver = { .owner = THIS_MODULE },
        },
+       {
+               .phy_id = MARVELL_PHY_ID_88E1149R,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
+               .name = "Marvell 88E1149R",
+               .features = PHY_GBIT_FEATURES,
+               .flags = PHY_HAS_INTERRUPT,
+               .config_init = &m88e1149_config_init,
+               .config_aneg = &m88e1118_config_aneg,
+               .read_status = &genphy_read_status,
+               .ack_interrupt = &marvell_ack_interrupt,
+               .config_intr = &marvell_config_intr,
+               .driver = { .owner = THIS_MODULE },
+       },
        {
                .phy_id = MARVELL_PHY_ID_88E1240,
                .phy_id_mask = MARVELL_PHY_ID_MASK,
@@ -735,6 +872,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = {
        { 0x01410e10, 0xfffffff0 },
        { 0x01410cb0, 0xfffffff0 },
        { 0x01410cd0, 0xfffffff0 },
+       { 0x01410e50, 0xfffffff0 },
        { 0x01410e30, 0xfffffff0 },
        { 0x01410e90, 0xfffffff0 },
        { }
index 7a298cdf9ab398135b2f59df9c7ad642c8f8840b..a3dcd04be22f6291e2546f84e474cef31e7fae34 100644 (file)
@@ -1450,7 +1450,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        netdev->irq = adapter->msix_entries[0].vector;
 
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        err = register_netdev(netdev);
        if (err) {
index c30e0fe55a314858828c2caa4d464b0c2301fe81..528eaef5308fa59460c8697ffc4fc0400d74a6cb 100644 (file)
@@ -62,15 +62,15 @@ static const u32 default_msg =
 /* NETIF_MSG_PKTDATA | */
     NETIF_MSG_HW | NETIF_MSG_WOL | 0;
 
-static int debug = 0x00007fff; /* defaults above */
-module_param(debug, int, 0);
+static int debug = -1; /* defaults above */
+module_param(debug, int, 0664);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 #define MSIX_IRQ 0
 #define MSI_IRQ 1
 #define LEG_IRQ 2
 static int qlge_irq_type = MSIX_IRQ;
-module_param(qlge_irq_type, int, MSIX_IRQ);
+module_param(qlge_irq_type, int, 0664);
 MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
 
 static int qlge_mpi_coredump;
index d88ce9fb1cbdacd4c04e802369f504af15e17d37..7d33ef4bcb4a1d6ca7125d6780e173889ebbb0d8 100644 (file)
@@ -846,10 +846,10 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        else
                tp->features &= ~RTL_FEATURE_WOL;
        __rtl8169_set_wol(tp, wol->wolopts);
-       device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
-
        spin_unlock_irq(&tp->lock);
 
+       device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
+
        return 0;
 }
 
@@ -2931,7 +2931,7 @@ static const struct rtl_cfg_info {
                .hw_start       = rtl_hw_start_8168,
                .region         = 2,
                .align          = 8,
-               .intr_event     = SYSErr | RxFIFOOver | LinkChg | RxOverflow |
+               .intr_event     = SYSErr | LinkChg | RxOverflow |
                                  TxErr | TxOK | RxOK | RxErr,
                .napi_event     = TxErr | TxOK | RxOK | RxOverflow,
                .features       = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
@@ -4440,8 +4440,7 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
        u32 status = opts1 & RxProtoMask;
 
        if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
-           ((status == RxProtoUDP) && !(opts1 & UDPFail)) ||
-           ((status == RxProtoIP) && !(opts1 & IPFail)))
+           ((status == RxProtoUDP) && !(opts1 & UDPFail)))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        else
                skb_checksum_none_assert(skb);
@@ -4588,7 +4587,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
                }
 
                /* Work around for rx fifo overflow */
-               if (unlikely(status & RxFIFOOver)) {
+               if (unlikely(status & RxFIFOOver) &&
+               (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
                        netif_stop_queue(dev);
                        rtl8169_tx_timeout(dev);
                        break;
index bfec2e0f52757bdb1097d158b813aaecd7164d66..220e0398f1d519130c63628b3e0461c45227fa7c 100644 (file)
@@ -3858,7 +3858,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 
        /* device is off until link detection */
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
 
        return dev;
 }
index 52f38e12a879db9d344fb80f169f05eba31fa860..50f712e99e9634d2a348ba497a146b3d86c9dfde 100644 (file)
@@ -22,7 +22,7 @@
 #define __SMSC911X_H__
 
 #define TX_FIFO_LOW_THRESHOLD  ((u32)1600)
-#define SMSC911X_EEPROM_SIZE   ((u32)7)
+#define SMSC911X_EEPROM_SIZE   ((u32)128)
 #define USE_DEBUG              0
 
 /* This is the maximum number of packets to be received every
index 28e1ffb13db99df5b0537a7426b2af3c03980feb..c78a50586c1d86a0fffa9a59ab461a1996da8122 100644 (file)
@@ -2021,7 +2021,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        de->media_timer.data = (unsigned long) de;
 
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
 
        /* wake up device, assign resources */
        rc = pci_enable_device(pdev);
index a4c3f5708246e9038ac716c4b8e9b7b06abeb28e..acbdab3d66caa70081e30b87f41e5e82c7d88b33 100644 (file)
@@ -2050,12 +2050,16 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
 
        ugeth_vdbg("%s: IN", __func__);
 
+       /*
+        * Tell the kernel the link is down.
+        * Must be done before disabling the controller
+        * or deadlock may happen.
+        */
+       phy_stop(phydev);
+
        /* Disable the controller */
        ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
 
-       /* Tell the kernel the link is down */
-       phy_stop(phydev);
-
        /* Mask all interrupts */
        out_be32(ugeth->uccf->p_uccm, 0x00000000);
 
@@ -2065,9 +2069,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
        /* Disable Rx and Tx */
        clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
 
-       phy_disconnect(ugeth->phydev);
-       ugeth->phydev = NULL;
-
        ucc_geth_memclean(ugeth);
 }
 
@@ -3550,7 +3551,10 @@ static int ucc_geth_close(struct net_device *dev)
 
        napi_disable(&ugeth->napi);
 
+       cancel_work_sync(&ugeth->timeout_work);
        ucc_geth_stop(ugeth);
+       phy_disconnect(ugeth->phydev);
+       ugeth->phydev = NULL;
 
        free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
 
@@ -3579,8 +3583,12 @@ static void ucc_geth_timeout_work(struct work_struct *work)
                 * Must reset MAC *and* PHY. This is done by reopening
                 * the device.
                 */
-               ucc_geth_close(dev);
-               ucc_geth_open(dev);
+               netif_tx_stop_all_queues(dev);
+               ucc_geth_stop(ugeth);
+               ucc_geth_init_mac(ugeth);
+               /* Must start PHY here */
+               phy_start(ugeth->phydev);
+               netif_tx_start_all_queues(dev);
        }
 
        netif_tx_schedule_all(dev);
@@ -3594,7 +3602,6 @@ static void ucc_geth_timeout(struct net_device *dev)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
 
-       netif_carrier_off(dev);
        schedule_work(&ugeth->timeout_work);
 }
 
index ca7fc9df1ccf900533d56c35326b360316283af2..c04d49e31f814fe11d2f1b730dcba014afeb324c 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_VERSION         "22-Aug-2005"
 
@@ -1273,6 +1274,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        struct usb_device               *xdev;
        int                             status;
        const char                      *name;
+       struct usb_driver       *driver = to_usb_driver(udev->dev.driver);
+
+       /* usbnet already took usb runtime pm, so have to enable the feature
+        * for usb interface, otherwise usb_autopm_get_interface may return
+        * failure if USB_SUSPEND(RUNTIME_PM) is enabled.
+        */
+       if (!driver->supports_autosuspend) {
+               driver->supports_autosuspend = 1;
+               pm_runtime_enable(&udev->dev);
+       }
 
        name = udev->dev.driver->name;
        info = (struct driver_info *) prod->driver_info;
index bb6b67f6b0cc731df707cbfc06006a2c8c39b198..b6d402806ae67253d2c12ff902ea79d40be5fe87 100644 (file)
@@ -986,9 +986,15 @@ static int virtnet_probe(struct virtio_device *vdev)
                goto unregister;
        }
 
-       vi->status = VIRTIO_NET_S_LINK_UP;
-       virtnet_update_status(vi);
-       netif_carrier_on(dev);
+       /* Assume link up if device can't report link status,
+          otherwise get link status from config. */
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+               netif_carrier_off(dev);
+               virtnet_update_status(vi);
+       } else {
+               vi->status = VIRTIO_NET_S_LINK_UP;
+               netif_carrier_on(dev);
+       }
 
        pr_debug("virtnet: registered device %s\n", dev->name);
        return 0;
index a0471f2e1c7a0e8cadb92adb09aa06d3b0b7a1ef..48261b7252d0061e5932c16a98dc3c1caf6e6245 100644 (file)
@@ -410,6 +410,9 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
                        val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
                }
 
+               if (AR_SREV_9280(ah))
+                       val |= AR_WA_BIT22;
+
                if (AR_SREV_9285E_20(ah))
                        val |= AR_WA_BIT23;
 
index 9b8e7e3fcebdbed0471be6ad0e412ee628057b78..170d44a35ccbd2ca06886be2be2ed8c1cd5dcf25 100644 (file)
@@ -675,6 +675,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 }
 
 extern struct ieee80211_ops ath9k_ops;
+extern struct pm_qos_request_list ath9k_pm_qos_req;
 extern int modparam_nohwcrypt;
 extern int led_blink;
 
index 966b9496a9dd4b51cf5c1f850fc987ea4b6ffff2..195406db3bd899b28f96c7b8214428822c3735db 100644 (file)
@@ -37,7 +37,7 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
        int addr, eep_start_loc;
        eep_data = (u16 *)eep;
 
-       if (ah->hw_version.devid == 0x7015)
+       if (AR9287_HTC_DEVID(ah))
                eep_start_loc = AR9287_HTC_EEP_START_LOC;
        else
                eep_start_loc = AR9287_EEP_START_LOC;
index 6576f683dba06c24611160cd068060032bbd9bfd..dfb6560dab9205c7502cc0a546c3549635d696f2 100644 (file)
@@ -35,8 +35,14 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
        { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */
        { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */
        { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */
+       { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */
+       { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */
+       { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */
+       { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */
        { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
        { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */
+       { USB_DEVICE(0x040D, 0x3801) }, /* VIA */
+       { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */
        { },
 };
 
@@ -540,11 +546,11 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
                        return;
                }
 
-               usb_fill_int_urb(urb, hif_dev->udev,
+               usb_fill_bulk_urb(urb, hif_dev->udev,
                                 usb_rcvbulkpipe(hif_dev->udev,
                                                 USB_REG_IN_PIPE),
                                 nskb->data, MAX_REG_IN_BUF_SIZE,
-                                ath9k_hif_usb_reg_in_cb, nskb, 1);
+                                ath9k_hif_usb_reg_in_cb, nskb);
 
                ret = usb_submit_urb(urb, GFP_ATOMIC);
                if (ret) {
@@ -720,11 +726,11 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
        if (!skb)
                goto err;
 
-       usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev,
+       usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev,
                         usb_rcvbulkpipe(hif_dev->udev,
                                         USB_REG_IN_PIPE),
                         skb->data, MAX_REG_IN_BUF_SIZE,
-                        ath9k_hif_usb_reg_in_cb, skb, 1);
+                        ath9k_hif_usb_reg_in_cb, skb);
 
        if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
                goto err;
@@ -805,6 +811,8 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
        case 0x7010:
        case 0x7015:
        case 0x9018:
+       case 0xA704:
+       case 0x1200:
                firm_offset = AR7010_FIRMWARE_TEXT;
                break;
        default:
@@ -843,14 +851,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
                goto err_fw_req;
        }
 
-       /* Alloc URBs */
-       ret = ath9k_hif_usb_alloc_urbs(hif_dev);
-       if (ret) {
-               dev_err(&hif_dev->udev->dev,
-                       "ath9k_htc: Unable to allocate URBs\n");
-               goto err_urb;
-       }
-
        /* Download firmware */
        ret = ath9k_hif_usb_download_fw(hif_dev);
        if (ret) {
@@ -866,16 +866,22 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
         */
        for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) {
                endp = &alt->endpoint[idx].desc;
-               if (((endp->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
-                               == 0x04) &&
-                   ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               == USB_ENDPOINT_XFER_INT)) {
+               if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                               == USB_ENDPOINT_XFER_INT) {
                        endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
                        endp->bmAttributes |= USB_ENDPOINT_XFER_BULK;
                        endp->bInterval = 0;
                }
        }
 
+       /* Alloc URBs */
+       ret = ath9k_hif_usb_alloc_urbs(hif_dev);
+       if (ret) {
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Unable to allocate URBs\n");
+               goto err_urb;
+       }
+
        return 0;
 
 err_fw_download:
@@ -929,6 +935,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
        case 0x7010:
        case 0x7015:
        case 0x9018:
+       case 0xA704:
+       case 0x1200:
                if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
                        hif_dev->fw_name = FIRMWARE_AR7010_1_1;
                else
index 3d7b97f1b3aeebe5840c438b5ccf631de702d6c2..7c8a38d04561c26754147bea9e447724a9e8eb42 100644 (file)
@@ -249,6 +249,8 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
        case 0x7010:
        case 0x7015:
        case 0x9018:
+       case 0xA704:
+       case 0x1200:
                priv->htc->credits = 45;
                break;
        default:
index 3d19b5bc937f9c1c285e23645fcbf6a929037b21..29d80ca783933684b7c5c531cbb970ee7e006cda 100644 (file)
@@ -121,7 +121,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
                        tx_hdr.data_type = ATH9K_HTC_NORMAL;
                }
 
-               if (ieee80211_is_data(fc)) {
+               if (ieee80211_is_data_qos(fc)) {
                        qc = ieee80211_get_qos_ctl(hdr);
                        tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
                }
index cc13ee1178237da72617f92bf7b3a103c82e772b..6ebc68bca91f0a999614572b38f69452df49645d 100644 (file)
@@ -484,6 +484,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
                ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
                          "Failed allocating banks for "
                          "external radio\n");
+               ath9k_hw_rf_free_ext_banks(ah);
                return ecode;
        }
 
@@ -952,9 +953,12 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
                REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
                break;
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_MONITOR:
                REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
                break;
+       default:
+               if (ah->is_monitoring)
+                       REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+               break;
        }
 }
 
@@ -1634,7 +1638,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
 
        switch (ah->opmode) {
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_MONITOR:
                REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
                REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
                REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
@@ -1663,6 +1666,14 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
                        AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
                break;
        default:
+               if (ah->is_monitoring) {
+                       REG_WRITE(ah, AR_NEXT_TBTT_TIMER,
+                                       TU_TO_USEC(next_beacon));
+                       REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
+                       REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
+                       flags |= AR_TBTT_TIMER_EN;
+                       break;
+               }
                ath_print(ath9k_hw_common(ah), ATH_DBG_BEACON,
                          "%s: unsupported opmode: %d\n",
                          __func__, ah->opmode);
index d032939768b073aa80e672641f805ac416e1ce22..d47d1b4b6002f2650cba8c80401cd52089800cc6 100644 (file)
@@ -622,6 +622,7 @@ struct ath_hw {
 
        bool sw_mgmt_crypto;
        bool is_pciexpress;
+       bool is_monitoring;
        bool need_an_top2_fixup;
        u16 tx_trig_level;
 
index 95b41db0d86b5b945189ba2c6fd1034043c26811..92bc5c5f48768ac42ca4b1bd02690d9d38ebed80 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/pm_qos_params.h>
 
 #include "ath9k.h"
 
@@ -179,6 +180,8 @@ static const struct ath_ops ath9k_common_ops = {
        .write = ath9k_iowrite32,
 };
 
+struct pm_qos_request_list ath9k_pm_qos_req;
+
 /**************************/
 /*     Initialization     */
 /**************************/
@@ -756,6 +759,9 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
        ath_init_leds(sc);
        ath_start_rfkill_poll(sc);
 
+       pm_qos_add_request(&ath9k_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+                          PM_QOS_DEFAULT_VALUE);
+
        return 0;
 
 error_world:
@@ -824,6 +830,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
        }
 
        ieee80211_unregister_hw(hw);
+       pm_qos_remove_request(&ath9k_pm_qos_req);
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
        ath9k_deinit_softc(sc);
index b52f1cf8a603fe4e7f4a61af1ba40c15a9e0c352..25d3ef4c338e1eb45800b45fec112fc064c095af 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/nl80211.h>
+#include <linux/pm_qos_params.h>
 #include "ath9k.h"
 #include "btcoex.h"
 
@@ -93,11 +94,13 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        unsigned long flags;
+       enum ath9k_power_mode power_mode;
 
        spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if (++sc->ps_usecount != 1)
                goto unlock;
 
+       power_mode = sc->sc_ah->power_mode;
        ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 
        /*
@@ -105,10 +108,12 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
         * useful data. Better clear them now so that they don't mess up
         * survey data results.
         */
-       spin_lock(&common->cc_lock);
-       ath_hw_cycle_counters_update(common);
-       memset(&common->cc_survey, 0, sizeof(common->cc_survey));
-       spin_unlock(&common->cc_lock);
+       if (power_mode != ATH9K_PM_AWAKE) {
+               spin_lock(&common->cc_lock);
+               ath_hw_cycle_counters_update(common);
+               memset(&common->cc_survey, 0, sizeof(common->cc_survey));
+               spin_unlock(&common->cc_lock);
+       }
 
  unlock:
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -1217,6 +1222,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
                ah->imask |= ATH9K_INT_CST;
 
        sc->sc_flags &= ~SC_OP_INVALID;
+       sc->sc_ah->is_monitoring = false;
 
        /* Disable BMISS interrupt when we're not associated */
        ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
@@ -1238,6 +1244,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
                        ath9k_btcoex_timer_resume(sc);
        }
 
+       pm_qos_update_request(&ath9k_pm_qos_req, 55);
+
 mutex_unlock:
        mutex_unlock(&sc->mutex);
 
@@ -1415,6 +1423,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        sc->sc_flags |= SC_OP_INVALID;
 
+       pm_qos_update_request(&ath9k_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+
        mutex_unlock(&sc->mutex);
 
        ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
@@ -1493,8 +1503,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        ath9k_hw_set_interrupts(ah, ah->imask);
 
        if (vif->type == NL80211_IFTYPE_AP    ||
-           vif->type == NL80211_IFTYPE_ADHOC ||
-           vif->type == NL80211_IFTYPE_MONITOR) {
+           vif->type == NL80211_IFTYPE_ADHOC) {
                sc->sc_flags |= SC_OP_ANI_RUN;
                ath_start_ani(common);
        }
@@ -1644,8 +1653,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
                if (conf->flags & IEEE80211_CONF_MONITOR) {
                        ath_print(common, ATH_DBG_CONFIG,
-                                 "HW opmode set to Monitor mode\n");
-                       sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
+                                 "Monitor mode is enabled\n");
+                       sc->sc_ah->is_monitoring = true;
+               } else {
+                       ath_print(common, ATH_DBG_CONFIG,
+                                 "Monitor mode is disabled\n");
+                       sc->sc_ah->is_monitoring = false;
                }
        }
 
index fddb0129bb57c43efa1148401a3ebf1e80f38239..c76ea53c20ce7dbe41863c00930853a59ccc6cf8 100644 (file)
@@ -441,7 +441,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
         */
        if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) &&
             (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
-           (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR))
+           (sc->sc_ah->is_monitoring))
                rfilt |= ATH9K_RX_FILTER_PROM;
 
        if (sc->rx.rxfilter & FIF_CONTROL)
@@ -897,7 +897,7 @@ static bool ath9k_rx_accept(struct ath_common *common,
                 * decryption and MIC failures. For monitor mode,
                 * we also ignore the CRC error.
                 */
-               if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+               if (ah->is_monitoring) {
                        if (rx_stats->rs_status &
                            ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
                              ATH9K_RXERR_CRC))
index 42976b0a01c115692566fe0f7f416c5aa9949b9f..dddf579aacf1c391dfb3e9e73675de1a781760da 100644 (file)
 #define AR_WA_RESET_EN                  (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
 #define AR_WA_ANALOG_SHIFT              (1 << 20)
 #define AR_WA_POR_SHORT                 (1 << 21) /* PCI-E Phy reset control */
+#define AR_WA_BIT22                    (1 << 22)
 #define AR9285_WA_DEFAULT              0x004a050b
 #define AR9280_WA_DEFAULT              0x0040073b
 #define AR_WA_DEFAULT                  0x0000073f
 #define AR_DEVID_7010(_ah) \
        (((_ah)->hw_version.devid == 0x7010) || \
         ((_ah)->hw_version.devid == 0x7015) || \
-        ((_ah)->hw_version.devid == 0x9018))
+        ((_ah)->hw_version.devid == 0x9018) || \
+        ((_ah)->hw_version.devid == 0xA704) || \
+        ((_ah)->hw_version.devid == 0x1200))
+
+#define AR9287_HTC_DEVID(_ah) \
+       (((_ah)->hw_version.devid == 0x7015) || \
+        ((_ah)->hw_version.devid == 0x1200))
 
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
index d8607f4c144d80741f26eb133323aff5cebe936c..7504ed14c72575a7befb91b0c0d9dd2684660af9 100644 (file)
@@ -82,9 +82,11 @@ static struct usb_device_id carl9170_usb_ids[] = {
        { USB_DEVICE(0x07d1, 0x3c10) },
        /* D-Link DWA 160 A2 */
        { USB_DEVICE(0x07d1, 0x3a09) },
+       /* D-Link DWA 130 D */
+       { USB_DEVICE(0x07d1, 0x3a0f) },
        /* Netgear WNA1000 */
        { USB_DEVICE(0x0846, 0x9040) },
-       /* Netgear WNDA3100 */
+       /* Netgear WNDA3100 (v1) */
        { USB_DEVICE(0x0846, 0x9010) },
        /* Netgear WN111 v2 */
        { USB_DEVICE(0x0846, 0x9001), .driver_info = CARL9170_ONE_LED },
@@ -551,12 +553,12 @@ static int carl9170_usb_flush(struct ar9170 *ar)
                usb_free_urb(urb);
        }
 
-       ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, HZ);
+       ret = usb_wait_anchor_empty_timeout(&ar->tx_cmd, 1000);
        if (ret == 0)
                err = -ETIMEDOUT;
 
        /* lets wait a while until the tx - queues are dried out */
-       ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, HZ);
+       ret = usb_wait_anchor_empty_timeout(&ar->tx_anch, 1000);
        if (ret == 0)
                err = -ETIMEDOUT;
 
index 32dee2ce5d3177706f8bc7394794952a87389324..d5ef696298eed37db811f55e60c0b7f3c0ded6f6 100644 (file)
@@ -54,6 +54,7 @@
 
 #define DRV_DESCRIPTION "802.11 data/management/control stack"
 #define DRV_NAME        "libipw"
+#define DRV_PROCNAME   "ieee80211"
 #define DRV_VERSION    LIBIPW_VERSION
 #define DRV_COPYRIGHT   "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
 
@@ -293,16 +294,16 @@ static int __init libipw_init(void)
        struct proc_dir_entry *e;
 
        libipw_debug_level = debug;
-       libipw_proc = proc_mkdir("ieee80211", init_net.proc_net);
+       libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
        if (libipw_proc == NULL) {
-               LIBIPW_ERROR("Unable to create " DRV_NAME
+               LIBIPW_ERROR("Unable to create " DRV_PROCNAME
                                " proc directory\n");
                return -EIO;
        }
        e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
                        &debug_level_proc_fops);
        if (!e) {
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
                return -EIO;
        }
@@ -319,7 +320,7 @@ static void __exit libipw_exit(void)
 #ifdef CONFIG_LIBIPW_DEBUG
        if (libipw_proc) {
                remove_proc_entry("debug_level", libipw_proc);
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
        }
 #endif                         /* CONFIG_LIBIPW_DEBUG */
index 8f8c4b73f8b9667a245f764360058be740f38b03..7edf8c2fb8c7c6072294854281ba40f416f1423a 100644 (file)
@@ -4000,7 +4000,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * "the hard way", rather than using device's scan.
         */
        if (iwl3945_mod_params.disable_hw_scan) {
-               IWL_ERR(priv, "sw scan support is deprecated\n");
+               dev_printk(KERN_DEBUG, &(pdev->dev),
+                       "sw scan support is deprecated\n");
                iwl3945_hw_ops.hw_scan = NULL;
        }
 
index 5046a00050348cc03fa4d10a566144449542bf36..373930afc26b50f2d7cddeb9027b07f8e5ad7775 100644 (file)
@@ -700,8 +700,9 @@ static void lbs_scan_worker(struct work_struct *work)
 
        if (priv->scan_channel < priv->scan_req->n_channels) {
                cancel_delayed_work(&priv->scan_work);
-               queue_delayed_work(priv->work_thread, &priv->scan_work,
-                       msecs_to_jiffies(300));
+               if (!priv->stopping)
+                       queue_delayed_work(priv->work_thread, &priv->scan_work,
+                               msecs_to_jiffies(300));
        }
 
        /* This is the final data we are about to send */
index f062ed5839016c4752d3f30922e27c7aa6dca2f8..cb14c38caf3aac8dc5dfc03fe6d77b0cd40bd42c 100644 (file)
@@ -36,6 +36,7 @@ struct lbs_private {
        /* CFG80211 */
        struct wireless_dev *wdev;
        bool wiphy_registered;
+       bool stopping;
        struct cfg80211_scan_request *scan_req;
        u8 assoc_bss[ETH_ALEN];
        u8 disassoc_reason;
index 47ce5a6ba120e9b9d707c56e93a79d35c1b5a3ea..46b88b118c992c12764084233f8633a62a01a629 100644 (file)
@@ -104,6 +104,7 @@ static int lbs_dev_open(struct net_device *dev)
        lbs_deb_enter(LBS_DEB_NET);
 
        spin_lock_irq(&priv->driver_lock);
+       priv->stopping = false;
 
        if (priv->connect_status == LBS_CONNECTED)
                netif_carrier_on(dev);
@@ -131,10 +132,16 @@ static int lbs_eth_stop(struct net_device *dev)
        lbs_deb_enter(LBS_DEB_NET);
 
        spin_lock_irq(&priv->driver_lock);
+       priv->stopping = true;
        netif_stop_queue(dev);
        spin_unlock_irq(&priv->driver_lock);
 
        schedule_work(&priv->mcast_work);
+       cancel_delayed_work_sync(&priv->scan_work);
+       if (priv->scan_req) {
+               cfg80211_scan_done(priv->scan_req, false);
+               priv->scan_req = NULL;
+       }
 
        lbs_deb_leave(LBS_DEB_NET);
        return 0;
index a38a7bd25f1916431bcf607a89bf4a0c126d5f8a..b9aedf18a04682dea5de87abc363546fcb054cd4 100644 (file)
@@ -57,7 +57,6 @@
 #include <linux/fcntl.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/timer.h>
 
index eea1ef2f502bd3c926599b2308901277e35250ef..4396d4b9bfb9a68ed3c0d7b41a96a80963d30c9f 100644 (file)
@@ -221,9 +221,6 @@ config RT2X00_LIB_LEDS
        boolean
        default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
 
-comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00"
-       depends on RT2X00_LIB=y && LEDS_CLASS=m
-
 config RT2X00_LIB_DEBUGFS
        bool "Ralink debugfs support"
        depends on RT2X00_LIB && MAC80211_DEBUGFS
index cce00ed81f37908fd062d34a89ad3f8f49a5d4e3..af212c6a615840e7bf777fb931ff2770d490fb5d 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
index 5624db8c9ad0c511880ca16daf99f4dfb26c3769..003170ea2e394193bdcb7af4033a98bca9d46127 100644 (file)
@@ -64,17 +64,57 @@ void pci_bus_remove_resources(struct pci_bus *bus)
        }
 }
 
+static bool pci_bus_resource_better(struct resource *res1, bool pos1,
+                                   struct resource *res2, bool pos2)
+{
+       /* If exactly one is positive decode, always prefer that one */
+       if (pos1 != pos2)
+               return pos1 ? true : false;
+
+       /* Prefer the one that contains the highest address */
+       if (res1->end != res2->end)
+               return (res1->end > res2->end) ? true : false;
+
+       /* Otherwise, prefer the one with highest "center of gravity" */
+       if (res1->start != res2->start)
+               return (res1->start > res2->start) ? true : false;
+
+       /* Otherwise, choose one arbitrarily (but consistently) */
+       return (res1 > res2) ? true : false;
+}
+
+static bool pci_bus_resource_positive(struct pci_bus *bus, struct resource *res)
+{
+       struct pci_bus_resource *bus_res;
+
+       /*
+        * This relies on the fact that pci_bus.resource[] refers to P2P or
+        * CardBus bridge base/limit registers, which are always positively
+        * decoded.  The pci_bus.resources list contains host bridge or
+        * subtractively decoded resources.
+        */
+       list_for_each_entry(bus_res, &bus->resources, list) {
+               if (bus_res->res == res)
+                       return (bus_res->flags & PCI_SUBTRACTIVE_DECODE) ?
+                               false : true;
+       }
+       return true;
+}
+
 /*
- * Find the highest-address bus resource below the cursor "res".  If the
- * cursor is NULL, return the highest resource.
+ * Find the next-best bus resource after the cursor "res".  If the cursor is
+ * NULL, return the best resource.  "Best" means that we prefer positive
+ * decode regions over subtractive decode, then those at higher addresses.
  */
 static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
                                                   unsigned int type,
                                                   struct resource *res)
 {
+       bool res_pos, r_pos, prev_pos = false;
        struct resource *r, *prev = NULL;
        int i;
 
+       res_pos = pci_bus_resource_positive(bus, res);
        pci_bus_for_each_resource(bus, r, i) {
                if (!r)
                        continue;
@@ -82,26 +122,14 @@ static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus,
                if ((r->flags & IORESOURCE_TYPE_BITS) != type)
                        continue;
 
-               /* If this resource is at or past the cursor, skip it */
-               if (res) {
-                       if (r == res)
-                               continue;
-                       if (r->end > res->end)
-                               continue;
-                       if (r->end == res->end && r->start > res->start)
-                               continue;
+               r_pos = pci_bus_resource_positive(bus, r);
+               if (!res || pci_bus_resource_better(res, res_pos, r, r_pos)) {
+                       if (!prev || pci_bus_resource_better(r, r_pos,
+                                                            prev, prev_pos)) {
+                               prev = r;
+                               prev_pos = r_pos;
+                       }
                }
-
-               if (!prev)
-                       prev = r;
-
-               /*
-                * A small resource is higher than a large one that ends at
-                * the same address.
-                */
-               if (r->end > prev->end ||
-                   (r->end == prev->end && r->start > prev->start))
-                       prev = r;
        }
 
        return prev;
index 5becbdee4027019a5c584df5ff5fb3cc99b04cc3..2850e64dedae3e0cb9e258d113b75156aff891d3 100644 (file)
@@ -276,6 +276,12 @@ int __init ibmphp_access_ebda (void)
 
        for (;;) {
                offset = next_offset;
+
+               /* Make sure what we read is still in the mapped section */
+               if (WARN(offset > (ebda_sz * 1024 - 4),
+                        "ibmphp_ebda: next read is beyond ebda_sz\n"))
+                       break;
+
                next_offset = readw (io_mem + offset);  /* offset of next blk */
 
                offset += 2;
index b5a7d9bfcb24a70523a33793e60d217475fc9a91..63d5042f2079141a8740d77fae118d9c5bb707af 100644 (file)
@@ -705,17 +705,21 @@ void pci_remove_legacy_files(struct pci_bus *b)
 
 #ifdef HAVE_PCI_MMAP
 
-int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
+int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
+                 enum pci_mmap_api mmap_api)
 {
-       unsigned long nr, start, size;
+       unsigned long nr, start, size, pci_start;
 
+       if (pci_resource_len(pdev, resno) == 0)
+               return 0;
        nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
        start = vma->vm_pgoff;
        size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
-       if (start < size && size - start >= nr)
+       pci_start = (mmap_api == PCI_MMAP_PROCFS) ?
+                       pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0;
+       if (start >= pci_start && start < pci_start + size &&
+                       start + nr <= pci_start + size)
                return 1;
-       WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n",
-               current->comm, start, start+nr, pci_name(pdev), resno, size);
        return 0;
 }
 
@@ -745,8 +749,15 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
        if (i >= PCI_ROM_RESOURCE)
                return -ENODEV;
 
-       if (!pci_mmap_fits(pdev, i, vma))
+       if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) {
+               WARN(1, "process \"%s\" tried to map 0x%08lx bytes "
+                       "at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n",
+                       current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff,
+                       pci_name(pdev), i,
+                       (u64)pci_resource_start(pdev, i),
+                       (u64)pci_resource_len(pdev, i));
                return -EINVAL;
+       }
 
        /* pci_mmap_page_range() expects the same kind of entry as coming
         * from /proc/bus/pci/ which is a "user visible" value. If this is
index e98c8104297b6c25eb130b01af6c8f00f14008de..710c8a29be0d5b8028eafb239bde42ae5d5934b6 100644 (file)
@@ -1007,6 +1007,18 @@ static int __pci_enable_device_flags(struct pci_dev *dev,
        int err;
        int i, bars = 0;
 
+       /*
+        * Power state could be unknown at this point, either due to a fresh
+        * boot or a device removal call.  So get the current power state
+        * so that things like MSI message writing will behave as expected
+        * (e.g. if the device really is in D0 at enable time).
+        */
+       if (dev->pm_cap) {
+               u16 pmcsr;
+               pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+               dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+       }
+
        if (atomic_add_return(1, &dev->enable_cnt) > 1)
                return 0;               /* already enabled */
 
index f5c7c382765f4192345c94cbd4ca0204cc041ebd..7d33f6673868ff5b3254e136770dae4edc635faf 100644 (file)
@@ -22,8 +22,13 @@ extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
 #endif
 extern void pci_cleanup_rom(struct pci_dev *dev);
 #ifdef HAVE_PCI_MMAP
+enum pci_mmap_api {
+       PCI_MMAP_SYSFS, /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
+       PCI_MMAP_PROCFS /* mmap on /proc/bus/pci/<BDF> */
+};
 extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
-                        struct vm_area_struct *vma);
+                        struct vm_area_struct *vmai,
+                        enum pci_mmap_api mmap_api);
 #endif
 int pci_probe_reset_function(struct pci_dev *dev);
 
index 297b72c880a1f3a84fab6ed277fbabffc90f22ff..27911b55c2a52295a01bf834cbb9eacb3f9455c3 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/capability.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -257,7 +256,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
 
        /* Make sure the caller is mapping a real resource for this device */
        for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-               if (pci_mmap_fits(dev, i, vma))
+               if (pci_mmap_fits(dev, i, vma,  PCI_MMAP_PROCFS))
                        break;
        }
 
index a87c4985326ebb3f39533946ee31cb839f585cbe..3a5a6fcc0eada9305be0acd3e0a67e8348c85a62 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
-#include <xen/xenbus.h>
 #include <xen/interface/io/pciif.h>
 #include <asm/xen/pci.h>
 #include <linux/interrupt.h>
@@ -576,8 +575,9 @@ static pci_ers_result_t pcifront_common_process(int cmd,
 
        pcidev = pci_get_bus_and_slot(bus, devfn);
        if (!pcidev || !pcidev->driver) {
-               dev_err(&pcidev->dev,
-                       "device or driver is NULL\n");
+               dev_err(&pdev->xdev->dev, "device or AER driver is NULL\n");
+               if (pcidev)
+                       pci_dev_put(pcidev);
                return result;
        }
        pdrv = pcidev->driver;
index 8cbfa067171f8a1264dbc95b195928bd24833982..96c72e90b79c4c1ff26bcc0e754dbb1c34350017 100644 (file)
@@ -725,17 +725,17 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
 
        return 0;
 
- err_out_free_res2:
+err_out_free_res2:
        if (irq_mode == 1)
                free_irq(dev->irq, socket);
        else
                del_timer_sync(&socket->poll_timer);
- err_out_free_res:
+err_out_free_res:
        pci_release_regions(dev);
- err_out_disable:
+err_out_disable:
        pci_disable_device(dev);
 
- err_out_free_mem:
+err_out_free_mem:
        kfree(socket);
        return ret;
 }
index 41418d394c55bf2c31dab3a12f3b1bc0d2b42913..c8e84bdece386c501e4039fce9f983f1f6b246fa 100644 (file)
@@ -15,7 +15,7 @@
 struct pd6729_socket {
        int     number;
        int     card_irq;
-       unsigned long io_base;  /* base io address of the socket */
+       unsigned long io_base;  /* base io address of the socket */
        struct pcmcia_socket socket;
        struct timer_list poll_timer;
 };
index 0ea3b29440e6b394a5608f41f749610f62b45091..81af2b3bcc005ae90a77d349edd7212b093b29a1 100644 (file)
@@ -237,7 +237,7 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = {
 #ifdef CONFIG_SA1100_COLLIE
 #include "sa11xx_base.h"
 
-int __init pcmcia_collie_init(struct device *dev)
+int __devinit pcmcia_collie_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index fd013a1ef47abcdd5746f4fa7f9885670fc2a9cd..f1e882272ab0e7f2c2c83dce6e271ce04f12c911 100644 (file)
@@ -130,7 +130,7 @@ static struct pcmcia_low_level assabet_pcmcia_ops = {
        .socket_suspend         = assabet_pcmcia_socket_suspend,
 };
 
-int pcmcia_assabet_init(struct device *dev)
+int __devinit pcmcia_assabet_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index 9bf088b1727592b256c5bafcc3bb6188310d2e0c..30560df8c76b6893151ae1f22654492177bdb78f 100644 (file)
@@ -97,7 +97,7 @@ static struct pcmcia_low_level cerf_pcmcia_ops = {
        .socket_suspend         = cerf_pcmcia_socket_suspend,
 };
 
-int __init pcmcia_cerf_init(struct device *dev)
+int __devinit pcmcia_cerf_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index 945857f8c2843d6d258769f54629562395fc088a..6b228590b3fddb5bbd044acd561a029f99bb328d 100644 (file)
@@ -64,7 +64,7 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
 #endif
 };
 
-static int sa11x0_drv_pcmcia_probe(struct platform_device *dev)
+static int __devinit sa11x0_drv_pcmcia_probe(struct platform_device *dev)
 {
        int i, ret = -ENODEV;
 
index 56329ad575a90cdbb78c8d9720b6f1ccb1687359..edf8f00288987c539595ed5fa5522f8e0d196953 100644 (file)
@@ -219,7 +219,7 @@ struct pcmcia_low_level h3600_pcmcia_ops = {
        .socket_suspend         = h3600_pcmcia_socket_suspend,
 };
 
-int __init pcmcia_h3600_init(struct device *dev)
+int __devinit pcmcia_h3600_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index c4d51867a050fa09703b469424d10d3a604c4971..7ff1b43540b809b2a970638bdbf45dff292d0af3 100644 (file)
@@ -113,7 +113,7 @@ static struct pcmcia_low_level shannon_pcmcia_ops = {
        .socket_suspend         = shannon_pcmcia_socket_suspend,
 };
 
-int __init pcmcia_shannon_init(struct device *dev)
+int __devinit pcmcia_shannon_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index 05bd504e6f18a47ff43c24d7bbba27c185ebe822..c998f7aaadbcec38448896be62ece98d16061afa 100644 (file)
@@ -123,7 +123,7 @@ static struct pcmcia_low_level simpad_pcmcia_ops = {
        .socket_suspend         = simpad_pcmcia_socket_suspend,
 };
 
-int __init pcmcia_simpad_init(struct device *dev)
+int __devinit pcmcia_simpad_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index 689e3c02edb819e7c41190787d30d55e06de1131..3753fd0722e72383137d57e839b377721ad86c7a 100644 (file)
@@ -57,11 +57,16 @@ module_param(pc_debug, int, 0644);
 void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
                      int lvl, const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
        if (pc_debug > lvl) {
-               printk(KERN_DEBUG "skt%u: %s: ", skt->nr, func);
                va_start(args, fmt);
-               vprintk(fmt, args);
+
+               vaf.fmt = fmt;
+               vaf.va = &args;
+
+               printk(KERN_DEBUG "skt%u: %s: %pV", skt->nr, func, &vaf);
+
                va_end(args);
        }
 }
index e73ebefdf3e0930ba979b3a3a9b348dfe181d730..315b3112aca85ece5a804778c6632a972ad32c7d 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/isapnp.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
 extern struct pnp_protocol isapnp_protocol;
index 68cf0c99138a94517f3f2e9dae03de4149049092..7b5080c455690941a97294f03583b64e109927ce 100644 (file)
@@ -1159,11 +1159,11 @@ int __devinit rio_init_mports(void)
 
        list_for_each_entry(port, &rio_mports, node) {
                if (!request_mem_region(port->iores.start,
-                                       port->iores.end - port->iores.start,
+                                       resource_size(&port->iores),
                                        port->name)) {
                        printk(KERN_ERR
                               "RIO: Error requesting master port region 0x%016llx-0x%016llx\n",
-                              (u64)port->iores.start, (u64)port->iores.end - 1);
+                              (u64)port->iores.start, (u64)port->iores.end);
                        rc = -ENOMEM;
                        goto out;
                }
index 359d1e04626cb938784290a5700058a3115d7b34..f0d63892264410b23e19753885868cca81071eda 100644 (file)
@@ -35,7 +35,7 @@
 
 #ifdef CONFIG_SH_SECUREEDGE5410
 #include <asm/rtc.h>
-#include <mach/snapgear.h>
+#include <mach/secureedge5410.h>
 
 #define        RTC_RESET       0x1000
 #define        RTC_IODATA      0x0800
index 5efbd5990ff8dee1ea6431540405082303fd3119..06e41ed9323080475a5639eed3dde6b589c84fc1 100644 (file)
@@ -761,7 +761,7 @@ err_unmap:
        clk_put(rtc->clk);
        iounmap(rtc->regbase);
 err_badmap:
-       release_resource(rtc->res);
+       release_mem_region(rtc->res->start, rtc->regsize);
 err_badres:
        kfree(rtc);
 
@@ -786,7 +786,7 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
        }
 
        iounmap(rtc->regbase);
-       release_resource(rtc->res);
+       release_mem_region(rtc->res->start, rtc->regsize);
 
        clk_disable(rtc->clk);
        clk_put(rtc->clk);
index c71d89dba302cd1024ec3c167e5a168c390224c9..83b4615a3b62fc0faa3841dc6ded7844583b18e8 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/device.h>
 #include <linux/poll.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 
index eb28fb01a38ad86e23580b53acf81f6a7d719745..f6489eb7e976a8c0aa1851ebbb21901d689030c1 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 
 #include <asm/compat.h>
 #include <asm/ccwdev.h>
index 883e2db02bd3c8351e8195b5b45b12e84dd44fbf..e090a307fdeee341c66502d75ade8edf58f13afe 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/mtio.h>
-#include <linux/smp_lock.h>
 #include <linux/compat.h>
 
 #include <asm/uaccess.h>
index 6c408670e08d72336ecfe1e3298a6db285740787..b3a3e8e8656e6db1be5e3a50b63056c43f0897f6 100644 (file)
@@ -209,29 +209,79 @@ tape_state_set(struct tape_device *device, enum tape_state newstate)
        wake_up(&device->state_change_wq);
 }
 
+struct tape_med_state_work_data {
+       struct tape_device *device;
+       enum tape_medium_state state;
+       struct work_struct  work;
+};
+
+static void
+tape_med_state_work_handler(struct work_struct *work)
+{
+       static char env_state_loaded[] = "MEDIUM_STATE=LOADED";
+       static char env_state_unloaded[] = "MEDIUM_STATE=UNLOADED";
+       struct tape_med_state_work_data *p =
+               container_of(work, struct tape_med_state_work_data, work);
+       struct tape_device *device = p->device;
+       char *envp[] = { NULL, NULL };
+
+       switch (p->state) {
+       case MS_UNLOADED:
+               pr_info("%s: The tape cartridge has been successfully "
+                       "unloaded\n", dev_name(&device->cdev->dev));
+               envp[0] = env_state_unloaded;
+               kobject_uevent_env(&device->cdev->dev.kobj, KOBJ_CHANGE, envp);
+               break;
+       case MS_LOADED:
+               pr_info("%s: A tape cartridge has been mounted\n",
+                       dev_name(&device->cdev->dev));
+               envp[0] = env_state_loaded;
+               kobject_uevent_env(&device->cdev->dev.kobj, KOBJ_CHANGE, envp);
+               break;
+       default:
+               break;
+       }
+       tape_put_device(device);
+       kfree(p);
+}
+
+static void
+tape_med_state_work(struct tape_device *device, enum tape_medium_state state)
+{
+       struct tape_med_state_work_data *p;
+
+       p = kzalloc(sizeof(*p), GFP_ATOMIC);
+       if (p) {
+               INIT_WORK(&p->work, tape_med_state_work_handler);
+               p->device = tape_get_device(device);
+               p->state = state;
+               schedule_work(&p->work);
+       }
+}
+
 void
 tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
 {
-       if (device->medium_state == newstate)
+       enum tape_medium_state oldstate;
+
+       oldstate = device->medium_state;
+       if (oldstate == newstate)
                return;
+       device->medium_state = newstate;
        switch(newstate){
        case MS_UNLOADED:
                device->tape_generic_status |= GMT_DR_OPEN(~0);
-               if (device->medium_state == MS_LOADED)
-                       pr_info("%s: The tape cartridge has been successfully "
-                               "unloaded\n", dev_name(&device->cdev->dev));
+               if (oldstate == MS_LOADED)
+                       tape_med_state_work(device, MS_UNLOADED);
                break;
        case MS_LOADED:
                device->tape_generic_status &= ~GMT_DR_OPEN(~0);
-               if (device->medium_state == MS_UNLOADED)
-                       pr_info("%s: A tape cartridge has been mounted\n",
-                               dev_name(&device->cdev->dev));
+               if (oldstate == MS_UNLOADED)
+                       tape_med_state_work(device, MS_LOADED);
                break;
        default:
-               // print nothing
                break;
        }
-       device->medium_state = newstate;
        wake_up(&device->state_change_wq);
 }
 
index 9f661426e4a1e28494bbe3054ee412696e0a6ad1..c837d7419a6a974b55383be923e4e4939c00bb62 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/kmod.h>
 #include <linux/cdev.h>
 #include <linux/device.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 
 MODULE_AUTHOR
@@ -249,27 +248,25 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
        char cp_command[80];
        char cp_response[160];
        char *onoff, *qid_string;
+       int rc;
 
-       memset(cp_command, 0x00, sizeof(cp_command));
-       memset(cp_response, 0x00, sizeof(cp_response));
-
-        onoff = ((action == 1) ? "ON" : "OFF");
+       onoff = ((action == 1) ? "ON" : "OFF");
        qid_string = ((recording_class_AB == 1) ? " QID * " : "");
 
-        /*
+       /*
         * The recording commands needs to be called with option QID
         * for guests that have previlege classes A or B.
         * Purging has to be done as separate step, because recording
         * can't be switched on as long as records are on the queue.
         * Doing both at the same time doesn't work.
         */
-
-       if (purge) {
+       if (purge && (action == 1)) {
+               memset(cp_command, 0x00, sizeof(cp_command));
+               memset(cp_response, 0x00, sizeof(cp_response));
                snprintf(cp_command, sizeof(cp_command),
                         "RECORDING %s PURGE %s",
                         logptr->recording_name,
                         qid_string);
-
                cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
        }
 
@@ -279,19 +276,33 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
                logptr->recording_name,
                onoff,
                qid_string);
-
        cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
        /* The recording command will usually answer with 'Command complete'
         * on success, but when the specific service was never connected
         * before then there might be an additional informational message
         * 'HCPCRC8072I Recording entry not found' before the
-         * 'Command complete'. So I use strstr rather then the strncmp.
+        * 'Command complete'. So I use strstr rather then the strncmp.
         */
        if (strstr(cp_response,"Command complete"))
-               return 0;
+               rc = 0;
        else
-               return -EIO;
+               rc = -EIO;
+       /*
+        * If we turn recording off, we have to purge any remaining records
+        * afterwards, as a large number of queued records may impact z/VM
+        * performance.
+        */
+       if (purge && (action == 0)) {
+               memset(cp_command, 0x00, sizeof(cp_command));
+               memset(cp_response, 0x00, sizeof(cp_response));
+               snprintf(cp_command, sizeof(cp_command),
+                        "RECORDING %s PURGE %s",
+                        logptr->recording_name,
+                        qid_string);
+               cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
+       }
 
+       return rc;
 }
 
 
index 1de672f21037bd70f57e06b4abcd43a89b65a864..f7e4ae6bf15a5be647bdf4a0223a228880d368a5 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/cdev.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/cio.h>
index 2ff8a22d42574242eb0a07c1ab1d38f73cc81d6b..e8391b89eff4bbbcb41896b3232c05a4070d8917 100644 (file)
@@ -1455,7 +1455,16 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
                break;
        case IO_SCH_UNREG_ATTACH:
        case IO_SCH_UNREG:
-               if (cdev)
+               if (!cdev)
+                       break;
+               if (cdev->private->state == DEV_STATE_SENSE_ID) {
+                       /*
+                        * Note: delayed work triggered by this event
+                        * and repeated calls to sch_event are synchronized
+                        * by the above check for work_pending(cdev).
+                        */
+                       dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+               } else
                        ccw_device_set_notoper(cdev);
                break;
        case IO_SCH_NOP:
index f5221749d18069dcbb7f917b0bbd09ccadba8dcc..7fca9c10ffcfad9b0901e7ae53fcac9b06697d82 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
index 6be43eb126b40077ab4bc0298ef7179bea0c9496..f47a714538db187e209d82a2acda81a91d7fd0de 100644 (file)
@@ -440,7 +440,6 @@ struct qeth_qdio_out_q {
         * index of buffer to be filled by driver; state EMPTY or PACKING
         */
        int next_buf_to_fill;
-       int sync_iqdio_error;
        /*
         * number of buffers that are currently filled (PRIMED)
         * -> these buffers are hardware-owned
@@ -695,14 +694,6 @@ struct qeth_mc_mac {
        int is_vmac;
 };
 
-struct qeth_skb_data {
-       __u32 magic;
-       int count;
-};
-
-#define QETH_SKB_MAGIC 0x71657468
-#define QETH_SIGA_CC2_RETRIES 3
-
 struct qeth_rx {
        int b_count;
        int b_index;
index 764267062601b8812017f9552350b0ad6480ba23..e6b2df0e73f56a4b143365be8302875c600c49bc 100644 (file)
@@ -877,8 +877,8 @@ out:
        return;
 }
 
-static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
-                struct qeth_qdio_out_buffer *buf, unsigned int qeth_skip_skb)
+static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
+               struct qeth_qdio_out_buffer *buf)
 {
        int i;
        struct sk_buff *skb;
@@ -887,13 +887,11 @@ static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        if (buf->buffer->element[0].flags & 0x40)
                atomic_dec(&queue->set_pci_flags_count);
 
-       if (!qeth_skip_skb) {
+       skb = skb_dequeue(&buf->skb_list);
+       while (skb) {
+               atomic_dec(&skb->users);
+               dev_kfree_skb_any(skb);
                skb = skb_dequeue(&buf->skb_list);
-               while (skb) {
-                       atomic_dec(&skb->users);
-                       dev_kfree_skb_any(skb);
-                       skb = skb_dequeue(&buf->skb_list);
-               }
        }
        for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) {
                if (buf->buffer->element[i].addr && buf->is_header[i])
@@ -909,12 +907,6 @@ static void __qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
 }
 
-static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
-               struct qeth_qdio_out_buffer *buf)
-{
-       __qeth_clear_output_buffer(queue, buf, 0);
-}
-
 void qeth_clear_qdio_buffers(struct qeth_card *card)
 {
        int i, j;
@@ -2833,7 +2825,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                }
        }
 
-       queue->sync_iqdio_error = 0;
        queue->card->dev->trans_start = jiffies;
        if (queue->card->options.performance_stats) {
                queue->card->perf_stats.outbound_do_qdio_cnt++;
@@ -2849,10 +2840,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
                queue->card->perf_stats.outbound_do_qdio_time +=
                        qeth_get_micros() -
                        queue->card->perf_stats.outbound_do_qdio_start_time;
-       if (rc > 0) {
-               if (!(rc & QDIO_ERROR_SIGA_BUSY))
-                       queue->sync_iqdio_error = rc & 3;
-       }
        if (rc) {
                queue->card->stats.tx_errors += count;
                /* ignore temporary SIGA errors without busy condition */
@@ -2916,7 +2903,7 @@ void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue,
 {
        struct qeth_card *card = (struct qeth_card *)card_ptr;
 
-       if (card->dev)
+       if (card->dev && (card->dev->flags & IFF_UP))
                napi_schedule(&card->napi);
 }
 EXPORT_SYMBOL_GPL(qeth_qdio_start_poll);
@@ -2940,7 +2927,6 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
        struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue];
        struct qeth_qdio_out_buffer *buffer;
        int i;
-       unsigned qeth_send_err;
 
        QETH_CARD_TEXT(card, 6, "qdouhdl");
        if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
@@ -2956,9 +2942,8 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
        }
        for (i = first_element; i < (first_element + count); ++i) {
                buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
-               qeth_send_err = qeth_handle_send_error(card, buffer, qdio_error);
-               __qeth_clear_output_buffer(queue, buffer,
-                       (qeth_send_err == QETH_SEND_ERROR_RETRY) ? 1 : 0);
+               qeth_handle_send_error(card, buffer, qdio_error);
+               qeth_clear_output_buffer(queue, buffer);
        }
        atomic_sub(count, &queue->used_buffers);
        /* check if we need to do something on this outbound queue */
@@ -3183,10 +3168,7 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
                int offset, int hd_len)
 {
        struct qeth_qdio_out_buffer *buffer;
-       struct sk_buff *skb1;
-       struct qeth_skb_data *retry_ctrl;
        int index;
-       int rc;
 
        /* spin until we get the queue ... */
        while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
@@ -3205,25 +3187,6 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
        atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
        qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len);
        qeth_flush_buffers(queue, index, 1);
-       if (queue->sync_iqdio_error == 2) {
-               skb1 = skb_dequeue(&buffer->skb_list);
-               while (skb1) {
-                       atomic_dec(&skb1->users);
-                       skb1 = skb_dequeue(&buffer->skb_list);
-               }
-               retry_ctrl = (struct qeth_skb_data *) &skb->cb[16];
-               if (retry_ctrl->magic != QETH_SKB_MAGIC) {
-                       retry_ctrl->magic = QETH_SKB_MAGIC;
-                       retry_ctrl->count = 0;
-               }
-               if (retry_ctrl->count < QETH_SIGA_CC2_RETRIES) {
-                       retry_ctrl->count++;
-                       rc = dev_queue_xmit(skb);
-               } else {
-                       dev_kfree_skb_any(skb);
-                       QETH_CARD_TEXT(card, 2, "qrdrop");
-               }
-       }
        return 0;
 out:
        atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
index 50286d8707f305b981c1e56ffa02df7b3ce3b0d9..6bd2dbc4c31606d5019fb1e76d92ef88583a2140 100644 (file)
@@ -76,7 +76,7 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
        scpnt->scsi_done(scpnt);
 }
 
-static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
+static int zfcp_scsi_queuecommand_lck(struct scsi_cmnd *scpnt,
                                  void (*done) (struct scsi_cmnd *))
 {
        struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
@@ -127,6 +127,8 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
        return ret;
 }
 
+static DEF_SCSI_QCMD(zfcp_scsi_queuecommand)
+
 static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
 {
        struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
index fcf08b3f52c1f2ee6b514c0b88ad2985c4f814da..b7bd5b0cc7aa450e23ebe7f8b0ddc10814b82f05 100644 (file)
@@ -1765,7 +1765,7 @@ out:
 } /* End twa_scsi_eh_reset() */
 
 /* This is the main scsi queue function to handle scsi opcodes */
-static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        int request_id, retval;
        TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
@@ -1812,6 +1812,8 @@ out:
        return retval;
 } /* End twa_scsi_queue() */
 
+static DEF_SCSI_QCMD(twa_scsi_queue)
+
 /* This function hands scsi cdb's to the firmware */
 static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
 {
index 6a95d111d207269a920fc57c8ceee220ac5d42d8..13e39e1fdfe288b88e9aded1305e21240debc48e 100644 (file)
@@ -1501,7 +1501,7 @@ out:
 } /* End twl_scsi_eh_reset() */
 
 /* This is the main scsi queue function to handle scsi opcodes */
-static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        int request_id, retval;
        TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
@@ -1536,6 +1536,8 @@ out:
        return retval;
 } /* End twl_scsi_queue() */
 
+static DEF_SCSI_QCMD(twl_scsi_queue)
+
 /* This function tells the controller to shut down */
 static void __twl_shutdown(TW_Device_Extension *tw_dev)
 {
index b1125341f4c89431521f978ca850135603f2c779..7fe96ff60c581c324a4eaecbf79d8c2e083bf7f8 100644 (file)
@@ -1947,7 +1947,7 @@ static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int r
 } /* End tw_scsiop_test_unit_ready_complete() */
 
 /* This is the main scsi queue function to handle scsi opcodes */
-static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) 
+static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        unsigned char *command = SCpnt->cmnd;
        int request_id = 0;
@@ -2023,6 +2023,8 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
        return retval;
 } /* End tw_scsi_queue() */
 
+static DEF_SCSI_QCMD(tw_scsi_queue)
+
 /* This function is the interrupt service routine */
 static irqreturn_t tw_interrupt(int irq, void *dev_instance) 
 {
index 89fc1c8af86b8774000233247fce6c880187f910..f672491774eb61756c2a36f8af3a36496a7ea53c 100644 (file)
@@ -167,7 +167,7 @@ MODULE_LICENSE("GPL");
 #include "53c700_d.h"
 
 
-STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *);
 STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
 STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
 STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
@@ -1749,8 +1749,8 @@ NCR_700_intr(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
-STATIC int
-NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
+static int
+NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
 {
        struct NCR_700_Host_Parameters *hostdata = 
                (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
@@ -1904,6 +1904,8 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
        return 0;
 }
 
+STATIC DEF_SCSI_QCMD(NCR_700_queuecommand)
+
 STATIC int
 NCR_700_abort(struct scsi_cmnd * SCp)
 {
index fc0b4b81d5522ddaff339d3dc6187ce72a4c7d9a..f66c33b9ab41ac7333d99f3f3423ce497e47ae1d 100644 (file)
@@ -2807,7 +2807,7 @@ static int BusLogic_host_reset(struct scsi_cmnd * SCpnt)
   Outgoing Mailbox for execution by the associated Host Adapter.
 */
 
-static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
+static int BusLogic_QueueCommand_lck(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
 {
        struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata;
        struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id];
@@ -2994,6 +2994,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
        return 0;
 }
 
+static DEF_SCSI_QCMD(BusLogic_QueueCommand)
 
 #if 0
 /*
index 73f237a1ed94f6e81ca686ba58a280e54e7056be..649fcb31f26da8e9b5269443574aa82a3dc45fa8 100644 (file)
@@ -1319,7 +1319,7 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T Co
 */
 
 static const char *BusLogic_DriverInfo(struct Scsi_Host *);
-static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *));
+static int BusLogic_QueueCommand(struct Scsi_Host *h, struct scsi_cmnd *);
 static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *);
 static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
 static int BusLogic_SlaveConfigure(struct scsi_device *);
index 5d2f148889adc117f90f2d0650ad2d2aeda047a5..9a5629f94f95aba802857a6d5162db4745235c8a 100644 (file)
@@ -952,7 +952,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
  *     Locks: host lock taken by caller
  */
 
-static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) 
+static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
        struct Scsi_Host *instance = cmd->device->host;
        struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
@@ -1021,6 +1021,7 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(NCR5380_queue_command)
 
 /**
  *     NCR5380_main    -       NCR state machines
index bdc468c9e1d9d6de71ba091041096fd831512ee7..fd40a32b1f6f2d3690ac5d63c361cb9ece6a2120 100644 (file)
@@ -313,7 +313,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
 #endif
 static int NCR5380_abort(Scsi_Cmnd * cmd);
 static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
-static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
        char *buffer, char **start, off_t offset, int length, int inout);
 
index 6961f78742aedbc86de34d810891737eeece4ec9..c91888a0a23cacf61354f0a3f1fdd1f3a08caef2 100644 (file)
@@ -693,7 +693,7 @@ static void wait_intr(void)
 }
 #endif
 
-static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int NCR53c406a_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
        int i;
 
@@ -726,6 +726,8 @@ static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(NCR53c406a_queue)
+
 static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt)
 {
        DEB(printk("NCR53c406a_reset called\n"));
index dbbc601948e5328e4c9a0bbfeb18ee8ac7f7fd91..dc5ac6e528c4febb2b6dbdc51953a08cfe934938 100644 (file)
@@ -911,7 +911,7 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc
  *     queue the command down to the controller
  */
 
-static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+static int inia100_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
 {
        struct orc_scb *scb;
        struct orc_host *host;          /* Point to Host adapter control block */
@@ -930,6 +930,8 @@ static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd
        return 0;
 }
 
+static DEF_SCSI_QCMD(inia100_queue)
+
 /*****************************************************************************
  Function name  : inia100_abort
  Description    : Abort a queued command.
index 29c0ed1cf50753ba8b674c1193d97c1af4d31624..2c93d9496d62dae64b4c2aaf0b78e60edc61ba17 100644 (file)
@@ -248,7 +248,7 @@ static struct aac_driver_ident aac_drivers[] = {
  *     TODO: unify with aac_scsi_cmd().
  */
 
-static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int aac_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = cmd->device->host;
        struct aac_dev *dev = (struct aac_dev *)host->hostdata;
@@ -267,6 +267,8 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
        return (aac_scsi_cmd(cmd) ? FAILED : 0);
 }
 
+static DEF_SCSI_QCMD(aac_queuecommand)
+
 /**
  *     aac_info                -       Returns the host adapter name
  *     @shost:         Scsi host to report on
index 0ec3da6f3e12133823588e280fea24cc364cbe03..081c6de92bc5b5e060f3bf20eebbfa1e8b58c5c2 100644 (file)
@@ -9500,7 +9500,7 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
  * in the 'scp' result field.
  */
 static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+advansys_queuecommand_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *shost = scp->device->host;
        int asc_res, result = 0;
@@ -9525,6 +9525,8 @@ advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
        return result;
 }
 
+static DEF_SCSI_QCMD(advansys_queuecommand)
+
 static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
 {
        PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
index 8eab8587ff21b6c35bb31129fd62a30d8ddc9f06..c5169f01c1cdb8502e19111b8bfb175da0b1c585 100644 (file)
@@ -1056,7 +1056,7 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
  *  queue a command
  *
  */
-static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha152x_queue_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 #if 0
        if(*SCpnt->cmnd == REQUEST_SENSE) {
@@ -1070,6 +1070,8 @@ static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        return aha152x_internal_queue(SCpnt, NULL, 0, done);
 }
 
+static DEF_SCSI_QCMD(aha152x_queue)
+
 
 /*
  *  
index 4f785f254c1f7f7619f25f0beb4a966c4b733ec4..195823a51aab5292e6ec43183d0e0829b6d9ff93 100644 (file)
@@ -558,7 +558,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost)
        };
 }
 
-static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int aha1542_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
        unchar ahacmd = CMD_START_SCSI;
        unchar direction;
@@ -718,6 +718,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(aha1542_queuecommand)
+
 /* Initialize mailboxes */
 static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
 {
index 1db538552d56b59faaf5053a1e93fcd0dff1c167..b871d2b57f93235652d55761cc66617f2a52c291 100644 (file)
@@ -132,7 +132,7 @@ struct ccb {                        /* Command Control Block 5.3 */
 };
 
 static int aha1542_detect(struct scsi_host_template *);
-static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int aha1542_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
 static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
 static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
index 0107a4cc33319bfef8c8e22cb5dbde9e9a700fe8..d058f1ab82b5612c328bafeba1b48a89c311f2a1 100644 (file)
@@ -331,7 +331,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
-static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha1740_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
        unchar direction;
        unchar *cmd = (unchar *) SCpnt->cmnd;
@@ -503,6 +503,8 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(aha1740_queuecommand)
+
 /* Query the board for its irq_level and irq_type.  Nothing else matters
    in enhanced mode on an EISA bus. */
 
index 88ad8482ef59b6e33cbdfeafe2d1c962ee05be8b..25d066624476e3b60ac0119d803f75bdfe5d721b 100644 (file)
@@ -573,7 +573,7 @@ ahd_linux_info(struct Scsi_Host *host)
  * Queue an SCB to the controller.
  */
 static int
-ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
+ahd_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
 {
        struct   ahd_softc *ahd;
        struct   ahd_linux_device *dev = scsi_transport_device_data(cmd->device);
@@ -588,6 +588,8 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
        return rtn;
 }
 
+static DEF_SCSI_QCMD(ahd_linux_queue)
+
 static struct scsi_target **
 ahd_linux_target_in_softc(struct scsi_target *starget)
 {
index aeea7a61478e8bca16357299bf33dd5fdf2d2292..4a359bb307c6e38cc9e17cfc547968b6271b98d8 100644 (file)
@@ -528,7 +528,7 @@ ahc_linux_info(struct Scsi_Host *host)
  * Queue an SCB to the controller.
  */
 static int
-ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
+ahc_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
 {
        struct   ahc_softc *ahc;
        struct   ahc_linux_device *dev = scsi_transport_device_data(cmd->device);
@@ -548,6 +548,8 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
        return rtn;
 }
 
+static DEF_SCSI_QCMD(ahc_linux_queue)
+
 static inline struct scsi_target **
 ahc_linux_target_in_softc(struct scsi_target *starget)
 {
index aee73fafccc834d5922baf4f5322bfede654464b..4ff60a08df0f184c2c84ed32093669e006a39b59 100644 (file)
@@ -10234,7 +10234,7 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
  * Description:
  *   Queue a SCB to the controller.
  *-F*************************************************************************/
-static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+static int aic7xxx_queue_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
 {
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
@@ -10292,6 +10292,8 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
   return (0);
 }
 
+static DEF_SCSI_QCMD(aic7xxx_queue)
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_bus_device_reset
index 05a78e515a24101caa7dd6d9b4891cfe86312d3d..17e3df4f016f6590cc86aac3ccc586add42cb2c6 100644 (file)
@@ -85,8 +85,7 @@ static int arcmsr_abort(struct scsi_cmnd *);
 static int arcmsr_bus_reset(struct scsi_cmnd *);
 static int arcmsr_bios_param(struct scsi_device *sdev,
                struct block_device *bdev, sector_t capacity, int *info);
-static int arcmsr_queue_command(struct scsi_cmnd *cmd,
-                                       void (*done) (struct scsi_cmnd *));
+static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static int arcmsr_probe(struct pci_dev *pdev,
                                const struct pci_device_id *id);
 static void arcmsr_remove(struct pci_dev *pdev);
@@ -2081,7 +2080,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
        }
 }
 
-static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
        void (* done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = cmd->device->host;
@@ -2124,6 +2123,8 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(arcmsr_queue_command)
+
 static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
index 918ccf8187577f1954f33084d33a77210a53fa48..ec166726b3149d2a270ffc3f1a491262b8c4dcd5 100644 (file)
@@ -2511,7 +2511,7 @@ acornscsi_intr(int irq, void *dev_id)
  *           done - function called on completion, with pointer to command descriptor
  * Returns  : 0, or < 0 on error.
  */
-int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
+static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt,
                       void (*done)(struct scsi_cmnd *))
 {
     AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
@@ -2561,6 +2561,8 @@ int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
     return 0;
 }
 
+DEF_SCSI_QCMD(acornscsi_queuecmd)
+
 /*
  * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
  * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
index 9e71ac611146ab86432664af1c2a40c7d2070ea0..2b2ce21e227ea95200ec437f2d2a29f7d1cc356e 100644 (file)
@@ -2198,7 +2198,7 @@ no_command:
  * Returns: 0 on success, else error.
  * Notes: io_request_lock is held, interrupts are disabled.
  */
-int fas216_queue_command(struct scsi_cmnd *SCpnt,
+static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt,
                         void (*done)(struct scsi_cmnd *))
 {
        FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2240,6 +2240,8 @@ int fas216_queue_command(struct scsi_cmnd *SCpnt,
        return result;
 }
 
+DEF_SCSI_QCMD(fas216_queue_command)
+
 /**
  * fas216_internal_done - trigger restart of a waiting thread in fas216_noqueue_command
  * @SCpnt: Command to wake
@@ -2263,7 +2265,7 @@ static void fas216_internal_done(struct scsi_cmnd *SCpnt)
  * Returns: scsi result code.
  * Notes: io_request_lock is held, interrupts are disabled.
  */
-int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
+static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt,
                           void (*done)(struct scsi_cmnd *))
 {
        FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2277,7 +2279,7 @@ int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
        BUG_ON(info->scsi.irq != NO_IRQ);
 
        info->internal_done = 0;
-       fas216_queue_command(SCpnt, fas216_internal_done);
+       fas216_queue_command_lck(SCpnt, fas216_internal_done);
 
        /*
         * This wastes time, since we can't return until the command is
@@ -2310,6 +2312,8 @@ int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
        return 0;
 }
 
+DEF_SCSI_QCMD(fas216_noqueue_command)
+
 /*
  * Error handler timeout function.  Indicate that we timed out,
  * and wake up any error handler process so it can continue.
index b65f4cf0eec9929af885e1346ff004b16970984f..377cfb72cc66ade722b441f6842c1f0ed3d7fc3b 100644 (file)
@@ -331,23 +331,21 @@ extern int fas216_init (struct Scsi_Host *instance);
  */
 extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
 
-/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt)
  * Purpose : queue a command for adapter to process.
- * Params  : SCpnt - Command to queue
- *          done  - done function to call once command is complete
+ * Params  : h - host adapter
+ *        : SCpnt - Command to queue
  * Returns : 0 - success, else error
  */
-extern int fas216_queue_command(struct scsi_cmnd *,
-                               void (*done)(struct scsi_cmnd *));
+extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
 
-/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt)
  * Purpose : queue a command for adapter to process, and process it to completion.
- * Params  : SCpnt - Command to queue
- *          done  - done function to call once command is complete
+ * Params  : h - host adapter
+ *        : SCpnt - Command to queue
  * Returns : 0 - success, else error
  */
-extern int fas216_noqueue_command(struct scsi_cmnd *,
-                                 void (*done)(struct scsi_cmnd *));
+extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *)
 
 /* Function: irqreturn_t fas216_intr (FAS216_Info *info)
  * Purpose : handle interrupts from the interface to progress a command
index 158ebc3644d83f2188a1e0007950799db4246652..88b2928b4d3b76a18cf9d8354d8350dd9f5f745c 100644 (file)
@@ -910,7 +910,7 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
  *
  */
 
-static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
        SETUP_HOSTDATA(cmd->device->host);
        Scsi_Cmnd *tmp;
@@ -1022,6 +1022,8 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(NCR5380_queue_command)
+
 /*
  * Function : NCR5380_main (void)
  *
index ad7a23aef0ecf29536a21fe64d4f27874ddb6173..3e8658e2f154b82a0e5ad05e628d710f0c1c61e7 100644 (file)
@@ -572,23 +572,6 @@ static void falcon_get_lock(void)
 }
 
 
-/* This is the wrapper function for NCR5380_queue_command(). It just
- * tries to get the lock on the ST-DMA (see above) and then calls the
- * original function.
- */
-
-#if 0
-int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
-{
-       /* falcon_get_lock();
-        * ++guenther: moved to NCR5380_queue_command() to prevent
-        * race condition, see there for an explanation.
-        */
-       return NCR5380_queue_command(cmd, done);
-}
-#endif
-
-
 int __init atari_scsi_detect(struct scsi_host_template *host)
 {
        static int called = 0;
index ab5bdda6903e3f6f650fa63c203ab6401bcd71a4..76029d570beb8634c121c47f6a7eb5e906df9a14 100644 (file)
@@ -605,7 +605,7 @@ handled:
  *
  *     Queue a command to the ATP queue. Called with the host lock held.
  */
-static int atp870u_queuecommand(struct scsi_cmnd * req_p, 
+static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
                         void (*done) (struct scsi_cmnd *))
 {
        unsigned char c;
@@ -694,6 +694,8 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p,
        return 0;
 }
 
+static DEF_SCSI_QCMD(atp870u_queuecommand)
+
 /**
  *     send_s870       -       send a command to the controller
  *     @host: host
index 8daa716739d1bd6d2a6a4180c008161e7f148f27..8ca967dee66d4eac1b551c82ff5416454e0ffcb6 100644 (file)
@@ -30,8 +30,7 @@ DEFINE_IDR(bfad_im_port_index);
 struct scsi_transport_template *bfad_im_scsi_transport_template;
 struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
 static void bfad_im_itnim_work_handler(struct work_struct *work);
-static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
-                               void (*done)(struct scsi_cmnd *));
+static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd);
 static int bfad_im_slave_alloc(struct scsi_device *sdev);
 static void bfad_im_fc_rport_add(struct bfad_im_port_s  *im_port,
                                struct bfad_itnim_s *itnim);
@@ -1120,7 +1119,7 @@ bfad_im_itnim_work_handler(struct work_struct *work)
  * Scsi_Host template entry, queue a SCSI command to the BFAD.
  */
 static int
-bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 {
        struct bfad_im_port_s *im_port =
                (struct bfad_im_port_s *) cmnd->device->host->hostdata[0];
@@ -1187,6 +1186,8 @@ out_fail_cmd:
        return 0;
 }
 
+static DEF_SCSI_QCMD(bfad_im_queuecommand)
+
 void
 bfad_os_rport_online_wait(struct bfad_s *bfad)
 {
index 54f50b07dac7f36fe5950efb9bdaf34340d4bbed..8f1b5c8bf903bba0e32e398aeaf776915b42890a 100644 (file)
@@ -1080,7 +1080,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
  *        and is expected to be held on return.
  *
  **/
-static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct DeviceCtlBlk *dcb;
        struct ScsiReqBlk *srb;
@@ -1154,6 +1154,7 @@ complete:
        return 0;
 }
 
+static DEF_SCSI_QCMD(dc395x_queue_command)
 
 /*
  * Return the disk geometry for the given SCSI device.
index 23dec006338512a479e60b5e9d0c5281dde2beca..cffcb108ac9639b4fd0a8ea4b32d503206fae319 100644 (file)
@@ -423,7 +423,7 @@ static int adpt_slave_configure(struct scsi_device * device)
        return 0;
 }
 
-static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
 {
        adpt_hba* pHba = NULL;
        struct adpt_device* pDev = NULL;        /* dpt per device information */
@@ -491,6 +491,8 @@ static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
        return adpt_scsi_to_i2o(pHba, cmd, pDev);
 }
 
+static DEF_SCSI_QCMD(adpt_queue)
+
 static int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev,
                sector_t capacity, int geom[])
 {
index 337746d460438417281d25c3aa9aec863f3e002d..beded716f93f4cbf4e929e9a354bba46d4c18be2 100644 (file)
@@ -29,7 +29,7 @@
  */
 
 static int adpt_detect(struct scsi_host_template * sht);
-static int adpt_queue(struct scsi_cmnd * cmd, void (*cmdcomplete) (struct scsi_cmnd *));
+static int adpt_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd);
 static int adpt_abort(struct scsi_cmnd * cmd);
 static int adpt_reset(struct scsi_cmnd* cmd);
 static int adpt_release(struct Scsi_Host *host);
index 0b205f8c732682583b1d939a408066615b07fa22..cdc621204b667bb4dd317fd09b137afb6950c79b 100644 (file)
@@ -36,7 +36,7 @@ static int dtc_abort(Scsi_Cmnd *);
 static int dtc_biosparam(struct scsi_device *, struct block_device *,
                         sector_t, int*);
 static int dtc_detect(struct scsi_host_template *);
-static int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int dtc_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static int dtc_bus_reset(Scsi_Cmnd *);
 
 #ifndef CMD_PER_LUN
index d1c31378f6da9823b67e895ae7143578cfa110ee..53925ac178fd1b13fd11747ec2fefa8033f00fa7 100644 (file)
 
 static int eata2x_detect(struct scsi_host_template *);
 static int eata2x_release(struct Scsi_Host *);
-static int eata2x_queuecommand(struct scsi_cmnd *,
-                              void (*done) (struct scsi_cmnd *));
+static int eata2x_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static int eata2x_eh_abort(struct scsi_cmnd *);
 static int eata2x_eh_host_reset(struct scsi_cmnd *);
 static int eata2x_bios_param(struct scsi_device *, struct block_device *,
@@ -1758,7 +1757,7 @@ static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha)
 
 }
 
-static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
+static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
                               void (*done) (struct scsi_cmnd *))
 {
        struct Scsi_Host *shost = SCpnt->device->host;
@@ -1843,6 +1842,8 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
        return 0;
 }
 
+static DEF_SCSI_QCMD(eata2x_queuecommand)
+
 static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
 {
        struct Scsi_Host *shost = SCarg->device->host;
index 60886c19065e290a4475822d183aa92c8dc4de0c..4a9641e69f54853860e9f6b82999c0955fcb00e4 100644 (file)
@@ -335,7 +335,7 @@ static inline unsigned int eata_pio_send_command(unsigned long base, unsigned ch
        return 0;
 }
 
-static int eata_pio_queue(struct scsi_cmnd *cmd,
+static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *))
 {
        unsigned int x, y;
@@ -438,6 +438,8 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(eata_pio_queue)
+
 static int eata_pio_abort(struct scsi_cmnd *cmd)
 {
        unsigned int loop = 100;
index e2bc779f86c1d4c7be559eb018904ac3d58ff0a6..57558523c1b8cd67ba8e83aacf8691eba8205928 100644 (file)
@@ -916,7 +916,7 @@ static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent)
        scsi_track_queue_full(dev, lp->num_tagged - 1);
 }
 
-static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct scsi_device *dev = cmd->device;
        struct esp *esp = shost_priv(dev->host);
@@ -941,6 +941,8 @@ static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
        return 0;
 }
 
+static DEF_SCSI_QCMD(esp_queuecommand)
+
 static int esp_check_gross_error(struct esp *esp)
 {
        if (esp->sreg & ESP_STAT_SPAM) {
index 2ad95aa8f58536a664a4c7d2114c4505d27355fe..a2c6135d337edab43838a94ee9c9ffc1061b216a 100644 (file)
@@ -1072,7 +1072,7 @@ static int fd_mcs_release(struct Scsi_Host *shpnt)
        return 0;
 }
 
-static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int fd_mcs_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
        struct Scsi_Host *shpnt = SCpnt->device->host;
 
@@ -1122,6 +1122,8 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(fd_mcs_queue)
+
 #if DEBUG_ABORT || DEBUG_RESET
 static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
 {
index e296bcc57d5c8920a2b90cf9a0858cac91e60d07..69b7aa54f43fc2e6d943512d35dcb4b2e6de9c2a 100644 (file)
@@ -1419,7 +1419,7 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
    return IRQ_HANDLED;
 }
 
-static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
+static int fdomain_16x0_queue_lck(struct scsi_cmnd *SCpnt,
                void (*done)(struct scsi_cmnd *))
 {
    if (in_command) {
@@ -1469,6 +1469,8 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
    return 0;
 }
 
+static DEF_SCSI_QCMD(fdomain_16x0_queue)
+
 #if DEBUG_ABORT
 static void print_info(struct scsi_cmnd *SCpnt)
 {
index cbb20b13b2288957ad39781e774bcd8891245da5..92f185081e622657bdb279850caf979200eb63b9 100644 (file)
@@ -246,7 +246,7 @@ void fnic_set_port_id(struct fc_lport *, u32, struct fc_frame *);
 void fnic_update_mac(struct fc_lport *, u8 *new);
 void fnic_update_mac_locked(struct fnic *, u8 *new);
 
-int fnic_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 int fnic_abort_cmd(struct scsi_cmnd *);
 int fnic_device_reset(struct scsi_cmnd *);
 int fnic_host_reset(struct scsi_cmnd *);
index 198cbab3e8941e0016720463e1279e9992ec193f..22d02404d15f6ce1a86a2b2fbccb852d8fd21003 100644 (file)
@@ -349,7 +349,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
  * Routine to send a scsi cdb
  * Called with host_lock held and interrupts disabled.
  */
-int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
        struct fc_lport *lp;
        struct fc_rport *rport;
@@ -457,6 +457,8 @@ out:
        return ret;
 }
 
+DEF_SCSI_QCMD(fnic_queuecommand)
+
 /*
  * fnic_fcpio_fw_reset_cmpl_handler
  * Routine to handle fw reset completion
index 921764c9ab2478334eaca4919fef8d4a4263dae3..1bcdb7beb77b37c08a6508318857e4f92363f0a9 100644 (file)
@@ -46,7 +46,7 @@
 static int generic_NCR5380_abort(Scsi_Cmnd *);
 static int generic_NCR5380_detect(struct scsi_host_template *);
 static int generic_NCR5380_release_resources(struct Scsi_Host *);
-static int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int generic_NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
 static const char* generic_NCR5380_info(struct Scsi_Host *);
 
index 841101846b88fe98e55a6c601b013ef9119cdf4a..76365700e2d537497dd3d844fc04c6699e92ac6b 100644 (file)
@@ -185,7 +185,7 @@ static long gdth_unlocked_ioctl(struct file *filep, unsigned int cmd,
                                unsigned long arg);
 
 static void gdth_flush(gdth_ha_str *ha);
-static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
+static int gdth_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
                                struct gdth_cmndinfo *cmndinfo);
 static void gdth_scsi_done(struct scsi_cmnd *scp);
@@ -4004,7 +4004,7 @@ static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,se
 }
 
 
-static int gdth_queuecommand(struct scsi_cmnd *scp,
+static int gdth_queuecommand_lck(struct scsi_cmnd *scp,
                                void (*done)(struct scsi_cmnd *))
 {
     gdth_ha_str *ha = shost_priv(scp->device->host);
@@ -4022,6 +4022,8 @@ static int gdth_queuecommand(struct scsi_cmnd *scp,
     return __gdth_queuecommand(ha, scp, cmndinfo);
 }
 
+static DEF_SCSI_QCMD(gdth_queuecommand)
+
 static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
                                struct gdth_cmndinfo *cmndinfo)
 {
index c5d0606ad0974edab8c0326f4fadff905413c171..b2fb2b2a6e700e86d7de265503b70cb48830d994 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/compat.h>
 #include <linux/blktrace_api.h>
 #include <linux/uaccess.h>
@@ -143,8 +142,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
        void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
        int cmd_type);
 
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
-               void (*done)(struct scsi_cmnd *));
+static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static void hpsa_scan_start(struct Scsi_Host *);
 static int hpsa_scan_finished(struct Scsi_Host *sh,
        unsigned long elapsed_time);
@@ -1926,7 +1924,7 @@ sglist_finished:
 }
 
 
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
+static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
        void (*done)(struct scsi_cmnd *))
 {
        struct ctlr_info *h;
@@ -2020,6 +2018,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+
 static void hpsa_scan_start(struct Scsi_Host *sh)
 {
        struct ctlr_info *h = shost_to_hba(sh);
index 0729f150b33aa038aa690f3122ae03dbd9115a5b..10b65556937b0478885ab5f528ab6098e61a1663 100644 (file)
@@ -751,7 +751,7 @@ static void hptiop_post_req_mv(struct hptiop_hba *hba,
                MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
 }
 
-static int hptiop_queuecommand(struct scsi_cmnd *scp,
+static int hptiop_queuecommand_lck(struct scsi_cmnd *scp,
                                void (*done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = scp->device->host;
@@ -819,6 +819,8 @@ cmd_done:
        return 0;
 }
 
+static DEF_SCSI_QCMD(hptiop_queuecommand)
+
 static const char *hptiop_info(struct Scsi_Host *host)
 {
        return driver_name_long;
index 9a4b69d4f4eb0d80c47117963cecbef3b2a1ebc2..67fc8ffd52e68eeb2bfe311d04d6bc2052895f74 100644 (file)
@@ -39,7 +39,7 @@
 #include <scsi/scsi_host.h>
 
 /* Common forward declarations for all Linux-versions: */
-static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_queuecommand (struct Scsi_Host *, struct scsi_cmnd *);
 static int ibmmca_abort (Scsi_Cmnd *);
 static int ibmmca_host_reset (Scsi_Cmnd *);
 static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
@@ -1691,7 +1691,7 @@ static int __devexit ibmmca_remove(struct device *dev)
 }
 
 /* The following routine is the SCSI command queue for the midlevel driver */
-static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int ibmmca_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
        unsigned int ldn;
        unsigned int scsi_cmd;
@@ -1996,6 +1996,8 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(ibmmca_queuecommand)
+
 static int __ibmmca_abort(Scsi_Cmnd * cmd)
 {
        /* Abort does not work, as the adapter never generates an interrupt on
index 00d08b25425fdf2faea0a1e3bd063167943291fc..57cad7e20caaad0f5bfe4d47e721d494d1ef826d 100644 (file)
@@ -1606,7 +1606,7 @@ static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost)
  * Returns:
  *     0 on success / other on failure
  **/
-static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
+static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd,
                               void (*done) (struct scsi_cmnd *))
 {
        struct ibmvfc_host *vhost = shost_priv(cmnd->device->host);
@@ -1672,6 +1672,8 @@ static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(ibmvfc_queuecommand)
+
 /**
  * ibmvfc_sync_completion - Signal that a synchronous command has completed
  * @evt:       ibmvfc event struct
index 67f78a470f5f091c6775fb17f37c1fd00293e1ac..041958453e2a6e6fc39bc4b727d1c44c904a5f9e 100644 (file)
@@ -713,7 +713,7 @@ static inline u16 lun_from_dev(struct scsi_device *dev)
  * @cmd:       struct scsi_cmnd to be executed
  * @done:      Callback function to be called when cmd is completed
 */
-static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
+static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
                                 void (*done) (struct scsi_cmnd *))
 {
        struct srp_cmd *srp_cmd;
@@ -766,6 +766,8 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
        return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
 }
 
+static DEF_SCSI_QCMD(ibmvscsi_queuecommand)
+
 /* ------------------------------------------------------------
  * Routines for driver initialization
  */
index 4734ab0b3ff6ab9297352d532bf5aeb530757fe8..99aa0e5699bc9369eb144fc2c144b4082ce15348 100644 (file)
@@ -926,7 +926,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
        return 0;
 }
 
-static int imm_queuecommand(struct scsi_cmnd *cmd,
+static int imm_queuecommand_lck(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *))
 {
        imm_struct *dev = imm_dev(cmd->device->host);
@@ -949,6 +949,8 @@ static int imm_queuecommand(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(imm_queuecommand)
+
 /*
  * Apparently the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
index 52bdc6df6b92b5363b234b31edc81566bad646ab..6568aab745a0014944f619465bf0fc7bc6429d32 100644 (file)
@@ -334,7 +334,7 @@ static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
 
 static void in2000_execute(struct Scsi_Host *instance);
 
-static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
        struct Scsi_Host *instance;
        struct IN2000_hostdata *hostdata;
@@ -431,6 +431,8 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
            return 0;
 }
 
+static DEF_SCSI_QCMD(in2000_queuecommand)
+
 
 
 /*
index 0fb8b06b8392cfbbf45ddbef8d291df21ca5414a..5821e1fbce084c9dfe2cf6f9975441245144b9cc 100644 (file)
@@ -396,7 +396,7 @@ struct IN2000_hostdata {
                                                           flags)
 
 static int in2000_detect(struct scsi_host_template *) in2000__INIT;
-static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int in2000_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static int in2000_abort(Scsi_Cmnd *);
 static void in2000_setup(char *, int *) in2000__INIT;
 static int in2000_biosparam(struct scsi_device *, struct block_device *,
index 108797761b95c2692fe942148a963c2ef51516ea..9627d062e16b3e819c11db4b5865f2f7a4cb8d85 100644 (file)
@@ -2639,7 +2639,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
  *     will cause the mid layer to call us again later with the command)
  */
 
-static int i91u_queuecommand(struct scsi_cmnd *cmd,
+static int i91u_queuecommand_lck(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *))
 {
        struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
@@ -2656,6 +2656,8 @@ static int i91u_queuecommand(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(i91u_queuecommand)
+
 /**
  *     i91u_bus_reset          -       reset the SCSI bus
  *     @cmnd: Command block we want to trigger the reset for
index fa60d7df44bed7154adf9aa784cecc937db64d23..5bbaee597e8857cbb2c09e66f06a278f2fb46353 100644 (file)
@@ -5709,7 +5709,7 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
  *     SCSI_MLQUEUE_DEVICE_BUSY if device is busy
  *     SCSI_MLQUEUE_HOST_BUSY if host is busy
  **/
-static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
+static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
                            void (*done) (struct scsi_cmnd *))
 {
        struct ipr_ioa_cfg *ioa_cfg;
@@ -5792,6 +5792,8 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(ipr_queuecommand)
+
 /**
  * ipr_ioctl - IOCTL handler
  * @sdev:      scsi device struct
index f83a116955f2f1c6409acfae27d2e91719d42276..b2511acd39bd3feeb7f87e6f956ffae6b8e73780 100644 (file)
@@ -232,7 +232,7 @@ static int ips_detect(struct scsi_host_template *);
 static int ips_release(struct Scsi_Host *);
 static int ips_eh_abort(struct scsi_cmnd *);
 static int ips_eh_reset(struct scsi_cmnd *);
-static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
+static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *);
 static const char *ips_info(struct Scsi_Host *);
 static irqreturn_t do_ipsintr(int, void *);
 static int ips_hainit(ips_ha_t *);
@@ -1046,7 +1046,7 @@ static int ips_eh_reset(struct scsi_cmnd *SC)
 /*    Linux obtains io_request_lock before calling this function            */
 /*                                                                          */
 /****************************************************************************/
-static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
+static int ips_queue_lck(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
 {
        ips_ha_t *ha;
        ips_passthru_t *pt;
@@ -1137,6 +1137,8 @@ static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
        return (0);
 }
 
+static DEF_SCSI_QCMD(ips_queue)
+
 /****************************************************************************/
 /*                                                                          */
 /* Routine Name: ips_biosparam                                              */
index e340373b509b6528ea0602d410eb902c3b233321..2924363d142bc4affc6422de1272e73a70957486 100644 (file)
@@ -1753,7 +1753,7 @@ static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport)
  * This is the i/o strategy routine, called by the SCSI layer. This routine
  * is called with the host_lock held.
  */
-int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
+static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
 {
        struct fc_lport *lport;
        struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
@@ -1851,6 +1851,8 @@ out:
        spin_lock_irq(lport->host->host_lock);
        return rc;
 }
+
+DEF_SCSI_QCMD(fc_queuecommand)
 EXPORT_SYMBOL(fc_queuecommand);
 
 /**
index 633e09036357828b87e1df84dacec85beda24492..c15fde808c33e98ea1b48398afaf951e19eedeaa 100644 (file)
@@ -1599,7 +1599,7 @@ enum {
        FAILURE_SESSION_NOT_READY,
 };
 
-int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+static int iscsi_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
        struct iscsi_cls_session *cls_session;
        struct Scsi_Host *host;
@@ -1736,6 +1736,8 @@ fault:
        spin_lock(host->host_lock);
        return 0;
 }
+
+DEF_SCSI_QCMD(iscsi_queuecommand)
 EXPORT_SYMBOL_GPL(iscsi_queuecommand);
 
 int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
index 55f09e92ab5918fd5019cacaded186d2cd1b1c55..29251fabecc65b50643a295bf3ca87c422f920d6 100644 (file)
@@ -189,7 +189,7 @@ int sas_queue_up(struct sas_task *task)
  * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
  * call us without holding an IRQ spinlock...
  */
-int sas_queuecommand(struct scsi_cmnd *cmd,
+static int sas_queuecommand_lck(struct scsi_cmnd *cmd,
                     void (*scsi_done)(struct scsi_cmnd *))
        __releases(host->host_lock)
        __acquires(dev->sata_dev.ap->lock)
@@ -254,6 +254,8 @@ out:
        return res;
 }
 
+DEF_SCSI_QCMD(sas_queuecommand)
+
 static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
 {
        struct sas_task *task = TO_SAS_TASK(cmd);
index f64b65a770b8df3b3f0a3ba47decc0512a8df0a7..581837b3c71a9369c12f31d3b547f555bfca576d 100644 (file)
@@ -2899,7 +2899,7 @@ void lpfc_poll_timeout(unsigned long ptr)
  *   SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily.
  **/
 static int
-lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 {
        struct Scsi_Host  *shost = cmnd->device->host;
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
@@ -3060,6 +3060,8 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(lpfc_queuecommand)
+
 /**
  * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point
  * @cmnd: Pointer to scsi_cmnd data structure.
index 3ddb4dc62d5d5eed49ecc1a1228ddbdfbecd1f47..6c42dff0f4d30d77e68dbfc445e961bfb55a786a 100644 (file)
@@ -66,7 +66,7 @@ static void cmd_done(struct fsc_state *, int result);
 static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
 
 
-static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int mac53c94_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct fsc_state *state;
 
@@ -99,6 +99,8 @@ static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *
        return 0;
 }
 
+static DEF_SCSI_QCMD(mac53c94_queue)
+
 static int mac53c94_host_reset(struct scsi_cmnd *cmd)
 {
        struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
index 7ceb5cf12c6be3be77ccba93e4a1d550a9d80800..9aa048525eb2544b8159a9495f1a604695a79d26 100644 (file)
@@ -366,7 +366,7 @@ mega_runpendq(adapter_t *adapter)
  * The command queuing entry point for the mid-layer.
  */
 static int
-megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
+megaraid_queue_lck(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
 {
        adapter_t       *adapter;
        scb_t   *scb;
@@ -409,6 +409,8 @@ megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
        return busy;
 }
 
+static DEF_SCSI_QCMD(megaraid_queue)
+
 /**
  * mega_allocate_scb()
  * @adapter - pointer to our soft state
@@ -4456,7 +4458,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
 
        scb->idx = CMDID_INT_CMDS;
 
-       megaraid_queue(scmd, mega_internal_done);
+       megaraid_queue_lck(scmd, mega_internal_done);
 
        wait_for_completion(&adapter->int_waitq);
 
index 2b4a048cadf1b31d41a0659e1be55acb96815cd9..f5644745e24e1fe4980188d062d179753a5b024f 100644 (file)
@@ -987,7 +987,7 @@ static int mega_query_adapter(adapter_t *);
 static int issue_scb(adapter_t *, scb_t *);
 static int mega_setup_mailbox(adapter_t *);
 
-static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *);
 static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
 static void __mega_runpendq(adapter_t *);
 static int issue_scb_block(adapter_t *, u_char *);
index a7810a106b37aed653e5183c192e60d1758d30bb..5708cb27d0783df3525fa1789dd10859a647f921 100644 (file)
@@ -113,8 +113,7 @@ static int megaraid_mbox_fire_sync_cmd(adapter_t *);
 static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
 static void megaraid_mbox_setup_device_map(adapter_t *);
 
-static int megaraid_queue_command(struct scsi_cmnd *,
-               void (*)(struct scsi_cmnd *));
+static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *);
 static void megaraid_mbox_runpendq(adapter_t *, scb_t *);
 static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
@@ -1484,7 +1483,7 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb)
  * Queue entry point for mailbox based controllers.
  */
 static int
-megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+megaraid_queue_command_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
 {
        adapter_t       *adapter;
        scb_t           *scb;
@@ -1513,6 +1512,8 @@ megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
        return if_busy;
 }
 
+static DEF_SCSI_QCMD(megaraid_queue_command)
+
 /**
  * megaraid_mbox_build_cmd - transform the mid-layer scsi commands
  * @adapter    : controller's soft state
index eb29d508513148653fb492df24cee9ab0b14cb17..7451bc096a015db4ff38a42725387dabf3b0a58e 100644 (file)
@@ -1334,7 +1334,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
  * @done:                      Callback entry point
  */
 static int
-megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
 {
        u32 frame_count;
        struct megasas_cmd *cmd;
@@ -1417,6 +1417,8 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(megasas_queue_command)
+
 static struct megasas_instance *megasas_lookup_instance(u16 host_no)
 {
        int i;
index 1f784fde25109b53ef86f2b79fd975ed5cc2bf38..197aa1b3f0f31f111b7980310d05aa948880eb7c 100644 (file)
@@ -1627,7 +1627,7 @@ static void cmd_complete(struct mesh_state *ms)
  * Called by midlayer with host locked to queue a new
  * request
  */
-static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int mesh_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct mesh_state *ms;
 
@@ -1648,6 +1648,8 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(mesh_queue)
+
 /*
  * Called to handle interrupts, either call by the interrupt
  * handler (do_mesh_interrupt) or by other functions in
index 16e99b6863549ed0495cc283c884d9a162d34c01..1a96a00418a4faed68a77519a49d1bf81e02f6b2 100644 (file)
@@ -3315,7 +3315,7 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
  * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
  */
 static int
-_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
+_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
        struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -3441,6 +3441,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
        return SCSI_MLQUEUE_HOST_BUSY;
 }
 
+static DEF_SCSI_QCMD(_scsih_qcmd)
+
 /**
  * _scsih_normalize_sense - normalize descriptor and fixed format sense data
  * @sense_buffer: sense data returned by target
index d013a2aa2fd54aac8e6d251f4aa2267ebe669922..46cc3825638d63fe50c6bd104214489b59c472ef 100644 (file)
@@ -8029,7 +8029,7 @@ static int ncr53c8xx_slave_configure(struct scsi_device *device)
        return 0;
 }
 
-static int ncr53c8xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+static int ncr53c8xx_queue_command_lck (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
      struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
      unsigned long flags;
@@ -8068,6 +8068,8 @@ printk("ncr53c8xx : command successfully queued\n");
      return sts;
 }
 
+static DEF_SCSI_QCMD(ncr53c8xx_queue_command)
+
 irqreturn_t ncr53c8xx_intr(int irq, void *dev_id)
 {
      unsigned long flags;
index 4c1e545452009c957baed7fa590018d93b4a3bfe..6b8b021400f848d9770684e4c1a5aebe4d2374e6 100644 (file)
@@ -196,8 +196,7 @@ static void __exit    exit_nsp32  (void);
 static int         nsp32_proc_info   (struct Scsi_Host *, char *, char **, off_t, int, int);
 
 static int         nsp32_detect      (struct pci_dev *pdev);
-static int         nsp32_queuecommand(struct scsi_cmnd *,
-               void (*done)(struct scsi_cmnd *));
+static int         nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static const char *nsp32_info        (struct Scsi_Host *);
 static int         nsp32_release     (struct Scsi_Host *);
 
@@ -909,7 +908,7 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
        return TRUE;
 }
 
-static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
        nsp32_target *target;
@@ -1050,6 +1049,8 @@ static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
        return 0;
 }
 
+static DEF_SCSI_QCMD(nsp32_queuecommand)
+
 /* initialize asic */
 static int nsp32hw_init(nsp32_hw_data *data)
 {
index 8dc5b1a5f5da7ebacdbedbdbc9a8b5b9a135d42b..a04281cace2e318e8c1896f7d30b818e41e24000 100644 (file)
@@ -118,7 +118,7 @@ static int pas16_abort(Scsi_Cmnd *);
 static int pas16_biosparam(struct scsi_device *, struct block_device *,
                           sector_t, int*);
 static int pas16_detect(struct scsi_host_template *);
-static int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int pas16_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static int pas16_bus_reset(Scsi_Cmnd *);
 
 #ifndef CMD_PER_LUN
index 9326c2c148803a6d1933faa0d183b6fad26be460..be3f33d31a99dc3e359190e233ae91b48e2066fe 100644 (file)
@@ -184,7 +184,7 @@ static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
        SCpnt->scsi_done(SCpnt);
 }
 
-static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt,
                            void (*done)(struct scsi_cmnd *))
 {
 #ifdef NSP_DEBUG
@@ -264,6 +264,8 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
        return 0;
 }
 
+static DEF_SCSI_QCMD(nsp_queuecommand)
+
 /*
  * setup PIO FIFO transfer mode and enable/disable to data out
  */
index d68c9f267c5edc1aa285762d523e9ea58055bd29..7fc9a9d0a448b6a01c42461758ef118f5190ed93 100644 (file)
@@ -299,8 +299,7 @@ static        int        nsp_proc_info  (
                                         off_t   offset,
                                         int     length,
                                         int     inout);
-static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
-                           void (* done)(struct scsi_cmnd *SCpnt));
+static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
 
 /* Error handler */
 /*static int nsp_eh_abort       (struct scsi_cmnd *SCpnt);*/
index 0ae27cb5cd6f30334d6e2dd19bae9c187729733d..8552296edaa1e8062504e4b8ee63d46cc19694e2 100644 (file)
@@ -547,7 +547,7 @@ SYM53C500_info(struct Scsi_Host *SChost)
 }
 
 static int 
-SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+SYM53C500_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        int i;
        int port_base = SCpnt->device->host->io_port;
@@ -583,6 +583,8 @@ SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(SYM53C500_queue)
+
 static int 
 SYM53C500_host_reset(struct scsi_cmnd *SCpnt)
 {
index 8e38ca8cd1016461e9642d4032d579feb6fac6fc..7f064f9ca828d3ac1db449d352104899f31b84e8 100644 (file)
@@ -50,7 +50,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <scsi/libsas.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/sas_ata.h>
index cf89091e4c3d3befec59b89425792dcad23e2a87..5e76a624cb08a843d194e7102900dfac77c2aae4 100644 (file)
@@ -3478,7 +3478,7 @@ static int pmcraid_copy_sglist(
  *       SCSI_MLQUEUE_DEVICE_BUSY if device is busy
  *       SCSI_MLQUEUE_HOST_BUSY if host is busy
  */
-static int pmcraid_queuecommand(
+static int pmcraid_queuecommand_lck(
        struct scsi_cmnd *scsi_cmd,
        void (*done) (struct scsi_cmnd *)
 )
@@ -3584,6 +3584,8 @@ static int pmcraid_queuecommand(
        return rc;
 }
 
+static DEF_SCSI_QCMD(pmcraid_queuecommand)
+
 /**
  * pmcraid_open -char node "open" entry, allowed only users with admin access
  */
index 7bc2d796e4037712dd1113fe1e94d81f09782b85..d164c9639361c773fb41717509608587cb2ab9a6 100644 (file)
@@ -798,7 +798,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
        return 0;
 }
 
-static int ppa_queuecommand(struct scsi_cmnd *cmd,
+static int ppa_queuecommand_lck(struct scsi_cmnd *cmd,
                void (*done) (struct scsi_cmnd *))
 {
        ppa_struct *dev = ppa_dev(cmd->device->host);
@@ -821,6 +821,8 @@ static int ppa_queuecommand(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(ppa_queuecommand)
+
 /*
  * Apparently the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
index 92ffbb5104980dc98bde7d839dce1cd6548d385d..cd178b9e40cdde6d0266d103974357028a3e3807 100644 (file)
@@ -211,7 +211,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev,
        return 0;
 }
 
-static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd,
                               void (*done)(struct scsi_cmnd *))
 {
        struct ps3rom_private *priv = shost_priv(cmd->device->host);
@@ -260,6 +260,8 @@ static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(ps3rom_queuecommand)
+
 static int decode_lv1_status(u64 status, unsigned char *sense_key,
                             unsigned char *asc, unsigned char *ascq)
 {
index b8166ecfd0e35f17894a077679d5f5d2a29701cf..5dec684bf0103d5cb9fd244d5b3a706ab1109720 100644 (file)
@@ -727,7 +727,7 @@ qla1280_info(struct Scsi_Host *host)
  * context which is a big NO! NO!.
  **************************************************************************/
 static int
-qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+qla1280_queuecommand_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = cmd->device->host;
        struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
@@ -756,6 +756,8 @@ qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
        return status;
 }
 
+static DEF_SCSI_QCMD(qla1280_queuecommand)
+
 enum action {
        ABORT_COMMAND,
        DEVICE_RESET,
index 1830e6e973155684234710e129e564f82176ce2d..1644eabaafeb58cb3130dccdb97b489bcd0c708e 100644 (file)
@@ -179,8 +179,7 @@ static int qla2xxx_slave_alloc(struct scsi_device *);
 static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
 static void qla2xxx_scan_start(struct Scsi_Host *);
 static void qla2xxx_slave_destroy(struct scsi_device *);
-static int qla2xxx_queuecommand(struct scsi_cmnd *cmd,
-               void (*fn)(struct scsi_cmnd *));
+static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static int qla2xxx_eh_abort(struct scsi_cmnd *);
 static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
 static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
@@ -535,7 +534,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
 }
 
 static int
-qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
@@ -609,6 +608,8 @@ qc24_fail_command:
        return 0;
 }
 
+static DEF_SCSI_QCMD(qla2xxx_queuecommand)
+
 
 /*
  * qla2x00_eh_wait_on_command
index f4cd846abf6dcf77dc7d6bd7a855437ba6a1868f..0d48fb4d1044480d8743ed355019891d1d03e907 100644 (file)
@@ -79,8 +79,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
 /*
  * SCSI host template entry points
  */
-static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
-                               void (*done) (struct scsi_cmnd *));
+static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
 static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
 static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
@@ -464,7 +463,7 @@ void qla4xxx_srb_compl(struct kref *ref)
  * completion handling).   Unfortunely, it sometimes calls the scheduler
  * in interrupt context which is a big NO! NO!.
  **/
-static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+static int qla4xxx_queuecommand_lck(struct scsi_cmnd *cmd,
                                void (*done)(struct scsi_cmnd *))
 {
        struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
@@ -538,6 +537,8 @@ qc_fail_command:
        return 0;
 }
 
+static DEF_SCSI_QCMD(qla4xxx_queuecommand)
+
 /**
  * qla4xxx_mem_free - frees memory allocated to adapter
  * @ha: Pointer to host adapter structure.
index 1ad51552d6b188aba1e206d5dc8e2a2ae96622a9..c3a9151ca823cb64651390e940794262d9b7d989 100644 (file)
@@ -439,7 +439,7 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
  *     Queued command
  */
 
-int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
+static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd,
                              void (*done) (struct scsi_cmnd *))
 {
        struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
@@ -459,6 +459,8 @@ int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
        return 0;
 }
 
+DEF_SCSI_QCMD(qlogicfas408_queuecommand)
+
 /* 
  *     Return bios parameters 
  */
index 260626427a328f21ba57c40f86f05003e0b50ea2..2f6c0a166200fdea89aba2d8aee31281718a6be1 100644 (file)
@@ -103,8 +103,7 @@ struct qlogicfas408_priv {
 #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
 
 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id);
-int qlogicfas408_queuecommand(struct scsi_cmnd * cmd,
-                             void (*done) (struct scsi_cmnd *));
+int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd);
 int qlogicfas408_biosparam(struct scsi_device * disk,
                           struct block_device *dev,
                           sector_t capacity, int ip[]);
index f8c561cf751e46aa62e841a5e1d35920c3f6ecf1..664c9572d0c9a44b2540a05857c8710596d8b6c1 100644 (file)
@@ -1003,7 +1003,7 @@ static int qlogicpti_slave_configure(struct scsi_device *sdev)
  *
  * "This code must fly." -davem
  */
-static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
+static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = Cmnd->device->host;
        struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
@@ -1052,6 +1052,8 @@ toss_command:
        return 1;
 }
 
+static DEF_SCSI_QCMD(qlogicpti_queuecommand)
+
 static int qlogicpti_return_status(struct Status_Entry *sts, int id)
 {
        int host_status = DID_ERROR;
index 348fba0a8976467fa9724411699b918a9cd8b0ea..2aeb2e9c4d3bc708d5c12c7a117b021ffc160409 100644 (file)
@@ -634,12 +634,13 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
  * Description: a serial number identifies a request for error recovery
  * and debugging purposes.  Protected by the Host_Lock of host.
  */
-static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 {
        cmd->serial_number = host->cmd_serial_number++;
        if (cmd->serial_number == 0) 
                cmd->serial_number = host->cmd_serial_number++;
 }
+EXPORT_SYMBOL(scsi_cmd_get_serial);
 
 /**
  * scsi_dispatch_command - Dispatch a command to the low-level driver.
@@ -651,7 +652,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
 int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 {
        struct Scsi_Host *host = cmd->device->host;
-       unsigned long flags = 0;
        unsigned long timeout;
        int rtn = 0;
 
@@ -737,23 +737,15 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
                goto out;
        }
 
-       spin_lock_irqsave(host->host_lock, flags);
-       /*
-        * AK: unlikely race here: for some reason the timer could
-        * expire before the serial number is set up below.
-        *
-        * TODO: kill serial or move to blk layer
-        */
-       scsi_cmd_get_serial(host, cmd); 
-
        if (unlikely(host->shost_state == SHOST_DEL)) {
                cmd->result = (DID_NO_CONNECT << 16);
                scsi_done(cmd);
        } else {
                trace_scsi_dispatch_cmd_start(cmd);
-               rtn = host->hostt->queuecommand(cmd, scsi_done);
+               cmd->scsi_done = scsi_done;
+               rtn = host->hostt->queuecommand(host, cmd);
        }
-       spin_unlock_irqrestore(host->host_lock, flags);
+
        if (rtn) {
                trace_scsi_dispatch_cmd_error(cmd, rtn);
                if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
index 2c36bae3bd4b7ea5c45f2c1c623d671e152a5bd3..2f1f9b079b1067fb078b74c471134bba9a7f55bb 100644 (file)
@@ -3538,7 +3538,7 @@ static void sdebug_remove_adapter(void)
 }
 
 static
-int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
+int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
 {
        unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
        int len, k;
@@ -3884,6 +3884,8 @@ write:
                             (delay_override ? 0 : scsi_debug_delay));
 }
 
+static DEF_SCSI_QCMD(scsi_debug_queuecommand)
+
 static struct scsi_host_template sdebug_driver_template = {
        .proc_info =            scsi_debug_proc_info,
        .proc_name =            sdebug_proc_name,
index 1de30eb83bb097664056209ec6d06a470385b76d..824b8fc03ce52f087dd3ca4d0fdadab15dfcac17 100644 (file)
@@ -320,19 +320,11 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                                    "changed. The Linux SCSI layer does not "
                                    "automatically adjust these parameters.\n");
 
-               if (scmd->request->cmd_flags & REQ_HARDBARRIER)
-                       /*
-                        * barrier requests should always retry on UA
-                        * otherwise block will get a spurious error
-                        */
-                       return NEEDS_RETRY;
-               else
-                       /*
-                        * for normal (non barrier) commands, pass the
-                        * UA upwards for a determination in the
-                        * completion functions
-                        */
-                       return SUCCESS;
+               /*
+                * Pass the UA upwards for a determination in the completion
+                * functions.
+                */
+               return SUCCESS;
 
                /* these three are not supported */
        case COPY_ABORTED:
@@ -781,17 +773,15 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
        struct Scsi_Host *shost = sdev->host;
        DECLARE_COMPLETION_ONSTACK(done);
        unsigned long timeleft;
-       unsigned long flags;
        struct scsi_eh_save ses;
        int rtn;
 
        scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
        shost->eh_action = &done;
 
-       spin_lock_irqsave(shost->host_lock, flags);
        scsi_log_send(scmd);
-       shost->hostt->queuecommand(scmd, scsi_eh_done);
-       spin_unlock_irqrestore(shost->host_lock, flags);
+       scmd->scsi_done = scsi_eh_done;
+       shost->hostt->queuecommand(shost, scmd);
 
        timeleft = wait_for_completion_timeout(&done, timeout);
 
index b9ab3a590e4b4fd891865a1f9d3d5f3cb55d9dc5..956496182c805d8dd7f0aa58cc3ddb7c12c91b8b 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/string_helpers.h>
 #include <linux/async.h>
index 9c73dbda3bbb8d3137e8adaed717b61d83cf6551..606215e54b8896f38deeb51603a29f8e12cd5e40 100644 (file)
@@ -572,7 +572,7 @@ stex_slave_destroy(struct scsi_device *sdev)
 }
 
 static int
-stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct st_hba *hba;
        struct Scsi_Host *host;
@@ -698,6 +698,8 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(stex_queuecommand)
+
 static void stex_scsi_done(struct st_ccb *ccb)
 {
        struct scsi_cmnd *cmd = ccb->cmd;
index 713620ed70d96ef4a8f6111a689a118d2a6f962d..4f0e5485ffde4bf0b859a3786191861f83e0a62f 100644 (file)
@@ -908,7 +908,7 @@ static int NCR5380_init (struct Scsi_Host *instance, int flags)
  */
 
 /* Only make static if a wrapper function is used */
-static int NCR5380_queue_command(struct scsi_cmnd *cmd,
+static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
                                 void (*done)(struct scsi_cmnd *))
 {
     SETUP_HOSTDATA(cmd->device->host);
@@ -1019,6 +1019,8 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
     return 0;
 }
 
+static DEF_SCSI_QCMD(NCR5380_queue_command)
+
 /*
  * Function : NCR5380_main (void) 
  *
index b29a9d661ca41740b7e7a9693f4a04fb806ec64a..bcefd8458e653f086bf6387f6c80dbd82d0c3322 100644 (file)
@@ -51,8 +51,7 @@ static int sun3scsi_abort(struct scsi_cmnd *);
 static int sun3scsi_detect (struct scsi_host_template *);
 static const char *sun3scsi_info (struct Scsi_Host *);
 static int sun3scsi_bus_reset(struct scsi_cmnd *);
-static int sun3scsi_queue_command(struct scsi_cmnd *,
-                                 void (*done)(struct scsi_cmnd *));
+static int sun3scsi_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static int sun3scsi_release (struct Scsi_Host *);
 
 #ifndef CMD_PER_LUN
index e5c369bb568f5d9ae5fd23b8bb8423c1be9c6ba1..190107ae120b5241d02864d94e6420cb826a3785 100644 (file)
@@ -734,7 +734,7 @@ const char *sym53c416_info(struct Scsi_Host *SChost)
        return info;
 }
 
-int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int sym53c416_queuecommand_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
        int base;
        unsigned long flags = 0;
@@ -761,6 +761,8 @@ int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        return 0;
 }
 
+DEF_SCSI_QCMD(sym53c416_queuecommand)
+
 static int sym53c416_host_reset(Scsi_Cmnd *SCpnt)
 {
        int base;
index 77860d0748ffc4d7c1eca48167f146427186524e..387de5d80a704373a3cbeeea42bbfb5d9ac08046 100644 (file)
@@ -25,7 +25,7 @@
 static int sym53c416_detect(struct scsi_host_template *);
 static const char *sym53c416_info(struct Scsi_Host *);
 static int sym53c416_release(struct Scsi_Host *);
-static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static int sym53c416_host_reset(Scsi_Cmnd *);
 static int sym53c416_bios_param(struct scsi_device *, struct block_device *,
                sector_t, int *);
index 8b955b534a36f7ce836967b49978b2deb7bd8d64..6b97ded9d45de641770335a851d29761b9c9e66a 100644 (file)
@@ -505,7 +505,7 @@ void sym_log_bus_error(struct Scsi_Host *shost)
  * queuecommand method.  Entered with the host adapter lock held and
  * interrupts disabled.
  */
-static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
+static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd,
                                        void (*done)(struct scsi_cmnd *))
 {
        struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
@@ -536,6 +536,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(sym53c8xx_queue_command)
+
 /*
  *  Linux entry point of the interrupt handler.
  */
index 76a069b7ac0bbd7ef2ae26a61a4c612b4f67b340..ada1115079c9e6890b00108e83f70f15061058a0 100644 (file)
@@ -96,8 +96,7 @@ static int t128_abort(struct scsi_cmnd *);
 static int t128_biosparam(struct scsi_device *, struct block_device *,
                          sector_t, int*);
 static int t128_detect(struct scsi_host_template *);
-static int t128_queue_command(struct scsi_cmnd *,
-                             void (*done)(struct scsi_cmnd *));
+static int t128_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
 static int t128_bus_reset(struct scsi_cmnd *);
 
 #ifndef CMD_PER_LUN
index 27866b0adfebd4901dbb1a38a4ebc752ecfd3d70..a124a28f2ccbf27f3e89981cc60eb57f0a305fc0 100644 (file)
@@ -1883,7 +1883,7 @@ dc390_ScsiRstDetect( struct dc390_acb* pACB )
     return;
 }
 
-static int DC390_queuecommand(struct scsi_cmnd *cmd,
+static int DC390_queuecommand_lck(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *))
 {
        struct scsi_device *sdev = cmd->device;
@@ -1944,6 +1944,8 @@ static int DC390_queuecommand(struct scsi_cmnd *cmd,
        return SCSI_MLQUEUE_DEVICE_BUSY;
 }
 
+static DEF_SCSI_QCMD(DC390_queuecommand)
+
 static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
 {
     struct pci_dev *pdev;
index 5d9fdeeb2315cdd5e9958bf24ea56cd3669fca47..edfc5da8be4c05aa5bc729c7ee47fca531bf797f 100644 (file)
 
 static int u14_34f_detect(struct scsi_host_template *);
 static int u14_34f_release(struct Scsi_Host *);
-static int u14_34f_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+static int u14_34f_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static int u14_34f_eh_abort(struct scsi_cmnd *);
 static int u14_34f_eh_host_reset(struct scsi_cmnd *);
 static int u14_34f_bios_param(struct scsi_device *, struct block_device *,
@@ -1248,7 +1248,7 @@ static void scsi_to_dev_dir(unsigned int i, unsigned int j) {
 
 }
 
-static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
+static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
    unsigned int i, j, k;
    struct mscp *cpp;
 
@@ -1329,6 +1329,8 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
    return 0;
 }
 
+static DEF_SCSI_QCMD(u14_34f_queuecommand)
+
 static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
    unsigned int i, j;
 
index 27aa40f3980e56114ddb53847bda968a9e5d1a66..0571ef9639cbc15b6d5ace0384c03a895900ff7d 100644 (file)
@@ -700,7 +700,7 @@ static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
        mscp->transfer_data_length = transfer_length;
 }
 
-static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
+static int ultrastor_queuecommand_lck(struct scsi_cmnd *SCpnt,
                                void (*done) (struct scsi_cmnd *))
 {
     struct mscp *my_mscp;
@@ -825,6 +825,8 @@ retry:
     return 0;
 }
 
+static DEF_SCSI_QCMD(ultrastor_queuecommand)
+
 /* This code must deal with 2 cases:
 
    1. The command has not been written to the OGM.  In this case, set
index a692905f95f76c3d3935ddfbd9b6f38daa60c788..165c18b5cf5f70a96801d181376a60c55c761c85 100644 (file)
@@ -15,8 +15,7 @@
 
 static int ultrastor_detect(struct scsi_host_template *);
 static const char *ultrastor_info(struct Scsi_Host *shpnt);
-static int ultrastor_queuecommand(struct scsi_cmnd *,
-                               void (*done)(struct scsi_cmnd *));
+static int ultrastor_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 static int ultrastor_abort(struct scsi_cmnd *);
 static int ultrastor_host_reset(struct scsi_cmnd *);
 static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
index 26894459c37fe375076464330ef7809345b57408..a18996d244664588ac1f7d2ea07cca0be3e29e7d 100644 (file)
@@ -690,7 +690,7 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
        return 0;
 }
 
-static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
        struct Scsi_Host *host = cmd->device->host;
        struct pvscsi_adapter *adapter = shost_priv(host);
@@ -719,6 +719,8 @@ static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(pvscsi_queue)
+
 static int pvscsi_abort(struct scsi_cmnd *cmd)
 {
        struct pvscsi_adapter *adapter = shost_priv(cmd->device->host);
index b701bf2cc1873fb579b64d923f0950ce36d92c60..5f697e0bd0095c97f1c21326bc6c073a8fc61d40 100644 (file)
@@ -371,8 +371,8 @@ calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast,
        msg[1] = offset;
 }
 
-int
-wd33c93_queuecommand(struct scsi_cmnd *cmd,
+static int
+wd33c93_queuecommand_lck(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *))
 {
        struct WD33C93_hostdata *hostdata;
@@ -468,6 +468,8 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
        return 0;
 }
 
+DEF_SCSI_QCMD(wd33c93_queuecommand)
+
 /*
  * This routine attempts to start a scsi command. If the host_card is
  * already connected, we give up immediately. Otherwise, look through
index 1ed5f3bf388eeea541ac6a097c3103d69528a5c8..3b463d7304dca635cf3f4360c7aa6d9430127f63 100644 (file)
@@ -343,8 +343,7 @@ struct WD33C93_hostdata {
 void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs,
          dma_setup_t setup, dma_stop_t stop, int clock_freq);
 int wd33c93_abort (struct scsi_cmnd *cmd);
-int wd33c93_queuecommand (struct scsi_cmnd *cmd,
-               void (*done)(struct scsi_cmnd *));
+int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd);
 void wd33c93_intr (struct Scsi_Host *instance);
 int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 int wd33c93_host_reset (struct scsi_cmnd *);
index 333580bf37c5a7d6cbccf6587d55ad7a2b3b3b2b..db451ae0a36811427165b9d0431d3b38d356ec8e 100644 (file)
@@ -1082,7 +1082,7 @@ static irqreturn_t wd7000_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
+static int wd7000_queuecommand_lck(struct scsi_cmnd *SCpnt,
                void (*done)(struct scsi_cmnd *))
 {
        Scb *scb;
@@ -1139,6 +1139,8 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
        return 0;
 }
 
+static DEF_SCSI_QCMD(wd7000_queuecommand)
+
 static int wd7000_diagnostics(Adapter * host, int code)
 {
        static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
index 53be4d35a0aa171dde05ca5628d53a2b422443c7..842e3b2a02b1ceb35ecdf45ee172cd35d116a82c 100644 (file)
@@ -2285,6 +2285,8 @@ static struct pciserial_board pci_boards[] __devinitdata = {
 
 static const struct pci_device_id softmodem_blacklist[] = {
        { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
+       { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
+       { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
 };
 
 /*
@@ -2863,6 +2865,9 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
                0, 0,
                pbn_b0_4_1152000 },
+       {       PCI_VENDOR_ID_OXSEMI, 0x9505,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
 
                /*
                 * The below card is a little controversial since it is the
index a9eff2b18eab25ed0fb797f3e0a97be8e2b913c0..19cac9f610fd9aa154a976b44410f5bf8187f94f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
+#include <linux/dma-mapping.h>
 
 #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
        defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
 #include <asm/gpio.h>
 #include <mach/bfin_serial_5xx.h>
 
-#ifdef CONFIG_SERIAL_BFIN_DMA
-#include <linux/dma-mapping.h>
+#include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/cacheflush.h>
-#endif
 
 #ifdef CONFIG_SERIAL_BFIN_MODULE
 # undef CONFIG_EARLY_PRINTK
@@ -360,7 +359,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
                UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                uart->port.icount.tx++;
-               SSYNC();
        }
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -688,6 +686,13 @@ static int bfin_serial_startup(struct uart_port *port)
 
 # ifdef CONFIG_BF54x
        {
+               /*
+                * UART2 and UART3 on BF548 share interrupt PINs and DMA
+                * controllers with SPORT2 and SPORT3. UART rx and tx
+                * interrupts are generated in PIO mode only when configure
+                * their peripheral mapping registers properly, which means
+                * request corresponding DMA channels in PIO mode as well.
+                */
                unsigned uart_dma_ch_rx, uart_dma_ch_tx;
 
                switch (uart->port.irq) {
@@ -734,8 +739,7 @@ static int bfin_serial_startup(struct uart_port *port)
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
                        IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
                        uart->cts_pin = -1;
-                       pr_info("Unable to attach BlackFin UART CTS interrupt.\
-                                So, disable it.\n");
+                       pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
                }
        }
        if (uart->rts_pin >= 0) {
@@ -747,8 +751,7 @@ static int bfin_serial_startup(struct uart_port *port)
        if (request_irq(uart->status_irq,
                bfin_serial_mctrl_cts_int,
                IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
-               pr_info("Unable to attach BlackFin UART Modem \
-                       Status interrupt.\n");
+               pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
        }
 
        /* CTS RTS PINs are negative assertive. */
@@ -846,6 +849,8 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
        if (termios->c_cflag & CMSPAR)
                lcr |= STP;
 
+       spin_lock_irqsave(&uart->port.lock, flags);
+
        port->read_status_mask = OE;
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= (FE | PE);
@@ -875,8 +880,6 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
        if (termios->c_line != N_IRDA)
                quot -= ANOMALY_05000230;
 
-       spin_lock_irqsave(&uart->port.lock, flags);
-
        UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
 
        /* Disable UART */
@@ -1321,6 +1324,14 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
        struct bfin_serial_port *uart;
        struct ktermios t;
 
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+       /*
+        * If we are using early serial, don't let the normal console rewind
+        * log buffer, since that causes things to be printed multiple times
+        */
+       bfin_serial_console.flags &= ~CON_PRINTBUFFER;
+#endif
+
        if (port == -1 || port >= nr_active_ports)
                port = 0;
        bfin_serial_init_ports();
index fa62578fcd20f572dbd391b614e47f246250b978..bcc31f2140ac7528811d607fd0e3e1f1f6cd66d4 100644 (file)
@@ -18,7 +18,6 @@ static char *serial_version = "$Revision: 1.25 $";
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
index d4b711c9a416c79bbfd242a248a51d3589eb2a15..3374618300af87c16ac3ef6a674e9cb650e62f8c 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/vt_kern.h>
+#include <linux/input.h>
 
 #define MAX_CONFIG_LEN         40
 
@@ -37,6 +38,61 @@ static struct tty_driver     *kgdb_tty_driver;
 static int                     kgdb_tty_line;
 
 #ifdef CONFIG_KDB_KEYBOARD
+static int kgdboc_reset_connect(struct input_handler *handler,
+                               struct input_dev *dev,
+                               const struct input_device_id *id)
+{
+       input_reset_device(dev);
+
+       /* Retrun an error - we do not want to bind, just to reset */
+       return -ENODEV;
+}
+
+static void kgdboc_reset_disconnect(struct input_handle *handle)
+{
+       /* We do not expect anyone to actually bind to us */
+       BUG();
+}
+
+static const struct input_device_id kgdboc_reset_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+       },
+       { }
+};
+
+static struct input_handler kgdboc_reset_handler = {
+       .connect        = kgdboc_reset_connect,
+       .disconnect     = kgdboc_reset_disconnect,
+       .name           = "kgdboc_reset",
+       .id_table       = kgdboc_reset_ids,
+};
+
+static DEFINE_MUTEX(kgdboc_reset_mutex);
+
+static void kgdboc_restore_input_helper(struct work_struct *dummy)
+{
+       /*
+        * We need to take a mutex to prevent several instances of
+        * this work running on different CPUs so they don't try
+        * to register again already registered handler.
+        */
+       mutex_lock(&kgdboc_reset_mutex);
+
+       if (input_register_handler(&kgdboc_reset_handler) == 0)
+               input_unregister_handler(&kgdboc_reset_handler);
+
+       mutex_unlock(&kgdboc_reset_mutex);
+}
+
+static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+
+static void kgdboc_restore_input(void)
+{
+       schedule_work(&kgdboc_restore_input_work);
+}
+
 static int kgdboc_register_kbd(char **cptr)
 {
        if (strncmp(*cptr, "kbd", 3) == 0) {
@@ -64,10 +120,12 @@ static void kgdboc_unregister_kbd(void)
                        i--;
                }
        }
+       flush_work_sync(&kgdboc_restore_input_work);
 }
 #else /* ! CONFIG_KDB_KEYBOARD */
 #define kgdboc_register_kbd(x) 0
 #define kgdboc_unregister_kbd()
+#define kgdboc_restore_input()
 #endif /* ! CONFIG_KDB_KEYBOARD */
 
 static int kgdboc_option_setup(char *opt)
@@ -231,6 +289,7 @@ static void kgdboc_post_exp_handler(void)
                dbg_restore_graphics = 0;
                con_debug_leave();
        }
+       kgdboc_restore_input();
 }
 
 static struct kgdb_io kgdboc_io_ops = {
index c4ea14670d4486fc142df31d806c528d2752c238..9ffa5bee44ab17b852f9bbaa5b9a5a8f3853286d 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/console.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
 #include <linux/serial_core.h>
index fd0d1b98901c2a0c13cc925e078139be079d1f43..cb12a8e1466b3d8cfe2ad13833d150eaaca90bc3 100644 (file)
@@ -90,8 +90,8 @@ struct clk_rate_round_data {
 static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
 {
        unsigned long rate_error, rate_error_prev = ~0UL;
-       unsigned long rate_best_fit = rounder->rate;
        unsigned long highest, lowest, freq;
+       long rate_best_fit = -ENOENT;
        int i;
 
        highest = 0;
@@ -146,7 +146,7 @@ long clk_rate_table_round(struct clk *clk,
        };
 
        if (clk->nr_freqs < 1)
-               return 0;
+               return -ENOSYS;
 
        return clk_rate_round_helper(&table_round);
 }
@@ -541,6 +541,98 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_round_rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max)
+{
+       struct cpufreq_frequency_table *freq, *best = NULL;
+       unsigned long error = ULONG_MAX, freq_high, freq_low, div;
+       struct clk *parent = clk_get_parent(clk);
+
+       if (!parent) {
+               *parent_freq = 0;
+               *best_freq = clk_round_rate(clk, target);
+               return abs(target - *best_freq);
+       }
+
+       for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
+            freq++) {
+               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               if (unlikely(freq->frequency / target <= div_min - 1)) {
+                       unsigned long freq_max;
+
+                       freq_max = (freq->frequency + div_min / 2) / div_min;
+                       if (error > target - freq_max) {
+                               error = target - freq_max;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_max;
+                       }
+
+                       pr_debug("too low freq %u, error %lu\n", freq->frequency,
+                                target - freq_max);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               if (unlikely(freq->frequency / target >= div_max)) {
+                       unsigned long freq_min;
+
+                       freq_min = (freq->frequency + div_max / 2) / div_max;
+                       if (error > freq_min - target) {
+                               error = freq_min - target;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_min;
+                       }
+
+                       pr_debug("too high freq %u, error %lu\n", freq->frequency,
+                                freq_min - target);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               div = freq->frequency / target;
+               freq_high = freq->frequency / div;
+               freq_low = freq->frequency / (div + 1);
+
+               if (freq_high - target < error) {
+                       error = freq_high - target;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_high;
+               }
+
+               if (target - freq_low < error) {
+                       error = target - freq_low;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_low;
+               }
+
+               pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
+                        freq->frequency, div, freq_high, div + 1, freq_low,
+                        *best_freq, best->frequency);
+
+               if (!error)
+                       break;
+       }
+
+       if (parent_freq)
+               *parent_freq = best->frequency;
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(clk_round_parent);
+
 #ifdef CONFIG_PM
 static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
 {
index 873a99ff8f64a454a505d1838be751dad20ae181..e5e9e6735f7d62e3d585505de7be4fe379fbbd40 100644 (file)
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
         * Register the IRQ position with the global IRQ map, then insert
         * it in to the radix tree.
         */
-       irq_reserve_irqs(irq, 1);
+       irq_reserve_irq(irq);
 
        raw_spin_lock_irqsave(&intc_big_lock, flags);
        radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
index 4187cce20ffdc9cd0997b276e2f5e8dc020e2519..a3677c9dfe36e3fa6ebcac37bee81af58d9ece5c 100644 (file)
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
        int i;
 
        for (i = 0; i < nr_vecs; i++)
-               irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
+               irq_reserve_irq(evt2irq(vectors[i].vect));
 }
index e5bf5d3c698e2f15a1ea16f31a4dad38312e6c08..4e0ff7181164c34eb603cd1b03e7633e34f681b3 100644 (file)
@@ -215,7 +215,7 @@ restart:
                entry = radix_tree_deref_slot((void **)entries[i]);
                if (unlikely(!entry))
                        continue;
-               if (unlikely(entry == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(entry))
                        goto restart;
 
                irq = create_irq();
index ae2cdf48b74c76d09808554e7b30a761fece63e8..8a5caa30b85f30afb0502c379064bcd2b8d44b89 100644 (file)
@@ -102,7 +102,7 @@ config AR600x_BT_RESET_PIN
 
 config ATH6KL_CFG80211
        bool "CFG80211 support"
-       depends on ATH6K_LEGACY
+       depends on ATH6K_LEGACY && CFG80211
        help
        Enables support for CFG80211 APIs. The default option is to use WEXT. Even with this option enabled, WEXT is not explicitly disabled and the onus of not exercising WEXT lies on the application(s) running in the user space.
 
index 22c6c6659f5b5f9a004ed25ae4543e01c200380b..ee8b47746a155ece0fbc559803a40ecb71e6f21b 100644 (file)
@@ -285,9 +285,9 @@ A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_I
     do {
         
             /* check if host supports scatter requests and it meets our requirements */
-        if (device->func->card->host->max_hw_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+        if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
-                    device->func->card->host->max_hw_segs, MAX_SCATTER_ENTRIES_PER_REQ));
+                    device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
             status = A_ENOTSUP;
             break;    
         }
index c5a6d6c1673502b0ae4c8543a7dfd0fd9a04ac32..a659f7047373efcca83a010b05dbd999546b6566 100644 (file)
@@ -1126,7 +1126,7 @@ ar6000_transfer_bin_file(AR_SOFTC_T *ar, AR6K_BIN_FILE file, A_UINT32 address, A
         if ((board_ext_address) && (fw_entry->size == (board_data_size + board_ext_data_size))) {
             A_UINT32 param;
 
-            status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (A_UCHAR *)(((A_UINT32)fw_entry->data) + board_data_size), board_ext_data_size);
+            status = BMIWriteMemory(ar->arHifDevice, board_ext_address, (A_UCHAR *)(fw_entry->data + board_data_size), board_ext_data_size);
 
             if (status != A_OK) {
                 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI operation failed: %d\n", __LINE__));
@@ -3030,7 +3030,8 @@ ar6000_data_tx(struct sk_buff *skb, struct net_device *dev)
         A_UINT8 csumDest=0;
         A_UINT8 csum=skb->ip_summed;
         if(csumOffload && (csum==CHECKSUM_PARTIAL)){
-            csumStart=skb->csum_start-(skb->network_header-skb->head)+sizeof(ATH_LLC_SNAP_HDR);
+            csumStart = (skb->head + skb->csum_start - skb_network_header(skb) +
+                        sizeof(ATH_LLC_SNAP_HDR));
             csumDest=skb->csum_offset+csumStart;
         }
 #endif
index c94ad29eeb4dcdb13a70b5b3bdba73a0345221e4..7269d0a1d61852e5319fba93538caf4aabb14873 100644 (file)
@@ -808,7 +808,7 @@ ar6k_cfg80211_scanComplete_event(AR_SOFTC_T *ar, A_STATUS status)
 
 static int
 ar6k_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
-                      A_UINT8 key_index, const A_UINT8 *mac_addr,
+                      A_UINT8 key_index, bool pairwise, const A_UINT8 *mac_addr,
                       struct key_params *params)
 {
     AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(ndev);
@@ -901,7 +901,7 @@ ar6k_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 
 static int
 ar6k_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
-                      A_UINT8 key_index, const A_UINT8 *mac_addr)
+                      A_UINT8 key_index, bool pairwise, const A_UINT8 *mac_addr)
 {
     AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(ndev);
 
@@ -936,7 +936,8 @@ ar6k_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
 
 static int
 ar6k_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
-                      A_UINT8 key_index, const A_UINT8 *mac_addr, void *cookie,
+                      A_UINT8 key_index, bool pairwise, const A_UINT8 *mac_addr,
+                      void *cookie,
                       void (*callback)(void *cookie, struct key_params*))
 {
     AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(ndev);
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
index 80cfa866958504692a45b2c6aaf29e936dc97d72..b68a7e5173be9279b44fbe5ce4f574b847c832b3 100644 (file)
@@ -165,7 +165,7 @@ static void update_mac_addresses(struct batman_if *batman_if)
               batman_if->net_dev->dev_addr, ETH_ALEN);
 }
 
-static void check_known_mac_addr(uint8_t *addr)
+static void check_known_mac_addr(struct net_device *net_dev)
 {
        struct batman_if *batman_if;
 
@@ -175,11 +175,16 @@ static void check_known_mac_addr(uint8_t *addr)
                    (batman_if->if_status != IF_TO_BE_ACTIVATED))
                        continue;
 
-               if (!compare_orig(batman_if->net_dev->dev_addr, addr))
+               if (batman_if->net_dev == net_dev)
+                       continue;
+
+               if (!compare_orig(batman_if->net_dev->dev_addr,
+                                 net_dev->dev_addr))
                        continue;
 
                pr_warning("The newly added mac address (%pM) already exists "
-                          "on: %s\n", addr, batman_if->net_dev->name);
+                          "on: %s\n", net_dev->dev_addr,
+                          batman_if->net_dev->name);
                pr_warning("It is strongly recommended to keep mac addresses "
                           "unique to avoid problems!\n");
        }
@@ -430,7 +435,7 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev)
        atomic_set(&batman_if->refcnt, 0);
        hardif_hold(batman_if);
 
-       check_known_mac_addr(batman_if->net_dev->dev_addr);
+       check_known_mac_addr(batman_if->net_dev);
 
        spin_lock(&if_list_lock);
        list_add_tail_rcu(&batman_if->list, &if_list);
@@ -515,7 +520,7 @@ static int hard_if_event(struct notifier_block *this,
                        goto out;
                }
 
-               check_known_mac_addr(batman_if->net_dev->dev_addr);
+               check_known_mac_addr(batman_if->net_dev);
                update_mac_addresses(batman_if);
 
                bat_priv = netdev_priv(batman_if->soft_iface);
index 90102631330b883ad1f3df3bc45f3494b7f06d91..657b69e6b9573595e80fb42e9c69849ac701d7c6 100644 (file)
@@ -1000,10 +1000,10 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
 
 /* find a suitable router for this originator, and use
  * bonding if possible. */
-struct neigh_node *find_router(struct orig_node *orig_node,
+struct neigh_node *find_router(struct bat_priv *bat_priv,
+                              struct orig_node *orig_node,
                               struct batman_if *recv_if)
 {
-       struct bat_priv *bat_priv;
        struct orig_node *primary_orig_node;
        struct orig_node *router_orig;
        struct neigh_node *router, *first_candidate, *best_router;
@@ -1019,13 +1019,9 @@ struct neigh_node *find_router(struct orig_node *orig_node,
        /* without bonding, the first node should
         * always choose the default router. */
 
-       if (!recv_if)
-               return orig_node->router;
-
-       bat_priv = netdev_priv(recv_if->soft_iface);
        bonding_enabled = atomic_read(&bat_priv->bonding_enabled);
 
-       if (!bonding_enabled)
+       if ((!recv_if) && (!bonding_enabled))
                return orig_node->router;
 
        router_orig = orig_node->router->orig_node;
@@ -1154,7 +1150,7 @@ static int route_unicast_packet(struct sk_buff *skb,
        orig_node = ((struct orig_node *)
                     hash_find(bat_priv->orig_hash, unicast_packet->dest));
 
-       router = find_router(orig_node, recv_if);
+       router = find_router(bat_priv, orig_node, recv_if);
 
        if (!router) {
                spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
index 06ea99df37064fd30c2d04d19ce60337d70f9455..92674c8d9c030c96b7da1bf39ee2c31eeae33688 100644 (file)
@@ -38,8 +38,8 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if);
 int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if);
 int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if);
 int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
-struct neigh_node *find_router(struct orig_node *orig_node,
-               struct batman_if *recv_if);
+struct neigh_node *find_router(struct bat_priv *bat_priv,
+               struct orig_node *orig_node, struct batman_if *recv_if);
 void update_bonding_candidates(struct bat_priv *bat_priv,
                               struct orig_node *orig_node);
 
index 0dac50d69c03c13b0dec25f95c93dae2f93ddd45..0459413ff67ff73a06f822038385d1005dee11b5 100644 (file)
@@ -224,7 +224,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
        if (!orig_node)
                orig_node = transtable_search(bat_priv, ethhdr->h_dest);
 
-       router = find_router(orig_node, NULL);
+       router = find_router(bat_priv, orig_node, NULL);
 
        if (!router)
                goto unlock;
index 77fdfe24d9990df393df9cc85b5ac95f27feb61f..fead9c56162e1f629648ca1a8d94aca0887e8cc1 100644 (file)
@@ -1001,13 +1001,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                }
 #endif
                case IOCTL_BE_BUCKET_SIZE:
-                       Adapter->BEBucketSize = *(PULONG)arg;
-                       Status = STATUS_SUCCESS;
+                       Status = 0;
+                       if (get_user(Adapter->BEBucketSize, (unsigned long __user *)arg))
+                               Status = -EFAULT;
                        break;
 
                case IOCTL_RTPS_BUCKET_SIZE:
-                       Adapter->rtPSBucketSize = *(PULONG)arg;
-                       Status = STATUS_SUCCESS;
+                       Status = 0;
+                       if (get_user(Adapter->rtPSBucketSize, (unsigned long __user *)arg))
+                               Status = -EFAULT;
                        break;
                case IOCTL_CHIP_RESET:
            {
@@ -1028,11 +1030,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                case IOCTL_QOS_THRESHOLD:
                {
                        USHORT uiLoopIndex;
-                       for(uiLoopIndex = 0 ; uiLoopIndex < NO_OF_QUEUES ; uiLoopIndex++)
-                       {
-                               Adapter->PackInfo[uiLoopIndex].uiThreshold = *(PULONG)arg;
+
+                       Status = 0;
+                       for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) {
+                               if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold,
+                                               (unsigned long __user *)arg)) {
+                                       Status = -EFAULT;
+                                       break;
+                               }
                        }
-                       Status = STATUS_SUCCESS;
                        break;
                }
 
@@ -1093,7 +1099,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                }
                case IOCTL_BCM_GET_CURRENT_STATUS:
                {
-                       LINK_STATE *plink_state = NULL;
+                       LINK_STATE plink_state;
+
                        /* Copy Ioctl Buffer structure */
                        if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                        {
@@ -1101,13 +1108,19 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Status = -EFAULT;
                                break;
                        }
-                       plink_state = (LINK_STATE*)arg;
-                       plink_state->bIdleMode = (UCHAR)Adapter->IdleMode;
-                       plink_state->bShutdownMode = Adapter->bShutStatus;
-                       plink_state->ucLinkStatus = (UCHAR)Adapter->LinkStatus;
-                       if(copy_to_user(IoBuffer.OutputBuffer,
-                               (PUCHAR)plink_state, (UINT)IoBuffer.OutputLength))
-                       {
+                       if (IoBuffer.OutputLength != sizeof(plink_state)) {
+                               Status = -EINVAL;
+                               break;
+                       }
+
+                       if (copy_from_user(&plink_state, (void __user *)arg, sizeof(plink_state))) {
+                               Status = -EFAULT;
+                               break;
+                       }
+                       plink_state.bIdleMode = (UCHAR)Adapter->IdleMode;
+                       plink_state.bShutdownMode = Adapter->bShutStatus;
+                       plink_state.ucLinkStatus = (UCHAR)Adapter->LinkStatus;
+                       if (copy_to_user(IoBuffer.OutputBuffer, &plink_state, IoBuffer.OutputLength)) {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n");
                                Status = -EFAULT;
                                break;
@@ -1331,7 +1344,9 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy From User space failed. status :%d", Status);
                                                return -EFAULT;
                                        }
-                                       uiSectorSize = *((PUINT)(IoBuffer.InputBuffer)); /* FIXME: unchecked __user access */
+                                       if (get_user(uiSectorSize, (unsigned int __user *)IoBuffer.InputBuffer))
+                                               return -EFAULT;
+
                                        if((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE))
                                        {
 
index c3ba9bb9b11678695f16f3448ba16961c2fa84d2..c8f1cf1b440963280241229906452d227b3e9ad4 100644 (file)
@@ -90,5 +90,5 @@ Contact Info:
 =============
 Brett Rudley   brudley@broadcom.com
 Henry Ptasinski henryp@broadcom.com
-Nohee Ko       noheek@broadcom.com
+Dowan Kim      dowan@broadcom.com
 
index 8803d300b5311b307d7112f0cbc649e7d55a89e4..dbf904184899884c825dab5e1e290c962e5dad25 100644 (file)
@@ -45,5 +45,5 @@ Contact
 =====
 Brett Rudley <brudley@broadcom.com>
 Henry Ptasinski <henryp@broadcom.com>
-Nohee Ko <noheek@broadcom.com>
+Dowan Kim <dowan@broadcom.com>
 
index bbbe7c5f7492573508d5027b03cd1df9a187b561..9335f02029aa3351b3360ea624188cc6a589883a 100644 (file)
@@ -2222,8 +2222,6 @@ int dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
        ASSERT(net);
 
        ASSERT(!net->netdev_ops);
-       net->netdev_ops = &dhd_ops_virt;
-
        net->netdev_ops = &dhd_ops_pri;
 
        /*
index 3f29488d9c7279c6ba79ad604d6fbb22b9a59a5a..ea0825238d53fd847be7dd6351da1011d26e9b8c 100644 (file)
@@ -95,12 +95,12 @@ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
                                            struct net_device *dev,
                                            u8 key_idx);
 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
-                                u8 key_idx, const u8 *mac_addr,
+                                u8 key_idx, bool pairwise, const u8 *mac_addr,
                                 struct key_params *params);
 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
-                                u8 key_idx, const u8 *mac_addr);
+                                u8 key_idx, bool pairwise, const u8 *mac_addr);
 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
-                                u8 key_idx, const u8 *mac_addr,
+                                u8 key_idx, bool pairwise, const u8 *mac_addr,
                                 void *cookie, void (*callback) (void *cookie,
                                                                 struct
                                                                 key_params *
@@ -1615,7 +1615,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
 
 static s32
 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
-                   u8 key_idx, const u8 *mac_addr,
+                   u8 key_idx, bool pairwise, const u8 *mac_addr,
                    struct key_params *params)
 {
        struct wl_wsec_key key;
@@ -1700,7 +1700,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 
 static s32
 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
-                   u8 key_idx, const u8 *mac_addr)
+                   u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
        struct wl_wsec_key key;
        s32 err = 0;
@@ -1756,7 +1756,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 
 static s32
 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
-                   u8 key_idx, const u8 *mac_addr, void *cookie,
+                   u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
                    void (*callback) (void *cookie, struct key_params * params))
 {
        struct key_params params;
index 933ae4c8cb9a6467b63f2d576e2b008b86c95ae8..0e740b8dafc3781d8ac9afb55a6c8ffb0b596d40 100644 (file)
@@ -3184,13 +3184,9 @@ static int cpia_open(struct file *file)
                goto oops;
        }
 
-       err = -EINTR;
-       if(signal_pending(current))
-               goto oops;
-
        /* Set ownership of /proc/cpia/videoX to current user */
        if(cam->proc_entry)
-               cam->proc_entry->uid = current_uid();
+               cam->proc_entry->uid = current_euid();
 
        /* set mark for loading first frame uncompressed */
        cam->first_frame = 1;
index f3c827eb0abe066bac548b0173cd86b01fb251d8..25961c23dc0f4dc3068e8d79eb9eaf7d749c5782 100644 (file)
@@ -77,7 +77,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/kref.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/uaccess.h>
 
index 87a6487531c2262e95357fac2987bc62a5d18e96..20d509836d9e24b9ef7e67ac185caeb1c960a993 100644 (file)
@@ -286,7 +286,6 @@ int ft1000_CreateDevice(struct ft1000_device *dev)
     pid = kernel_thread (exec_mknod, (void *)info, 0);
 
     // initialize application information
-    info->appcnt = 0;
 
 //    if (ft1000_flarion_cnt == 0) {
 //
index 702a478d554203c663d1bdbb0b7f0a450f7f3620..a99e900ec4c9faf8f5f96aa815cc3af5d01766c1 100644 (file)
@@ -211,9 +211,6 @@ static void heartbeat_onchannelcallback(void *context)
                DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
                           recvlen, requestid);
 
-               icmsghdrp = (struct icmsg_hdr *)&buf[
-                       sizeof(struct vmbuspipe_hdr)];
-
                icmsghdrp = (struct icmsg_hdr *)&buf[
                                sizeof(struct vmbuspipe_hdr)];
 
index 41d9acf4cd6119c1d52254df01faaf793e47e622..6f8d67d0d64fd20b77b515b696d9e92c485ed5e4 100644 (file)
@@ -72,8 +72,7 @@ struct storvsc_driver_context {
 
 /* Static decl */
 static int storvsc_probe(struct device *dev);
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
-                               void (*done)(struct scsi_cmnd *));
+static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
 static int storvsc_device_alloc(struct scsi_device *);
 static int storvsc_device_configure(struct scsi_device *);
 static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
@@ -595,7 +594,7 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
 /*
  * storvsc_queuecommand - Initiate command processing
  */
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
+static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
                                void (*done)(struct scsi_cmnd *))
 {
        int ret;
@@ -783,6 +782,8 @@ retry_request:
        return ret;
 }
 
+static DEF_SCSI_QCMD(storvsc_queuecommand)
+
 static int storvsc_merge_bvec(struct request_queue *q,
                              struct bvec_merge_data *bmd, struct bio_vec *bvec)
 {
index 463e5cba8307fd5694b4e48e81d6f37533ba231d..991440015e9263e415a9449eb9fa7f34dae07f41 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/uaccess.h>
 #include <linux/firmware.h>
 #include <linux/ioctl.h>
-#include <linux/smp_lock.h>
 #ifdef CONFIG_MRST_RAR_HANDLER
 #include <linux/rar_register.h>
 #include "../../../drivers/staging/memrar/memrar.h"
@@ -244,12 +243,12 @@ static int intel_sst_mmap_play_capture(u32 str_id,
        int retval, i;
        struct stream_info *stream;
        struct snd_sst_mmap_buff_entry *buf_entry;
+       struct snd_sst_mmap_buff_entry *tmp_buf;
 
        pr_debug("sst:called for str_id %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return -EINVAL;
-       BUG_ON(!mmap_buf);
 
        stream = &sst_drv_ctx->streams[str_id];
        if (stream->mmapped != true)
@@ -262,14 +261,24 @@ static int intel_sst_mmap_play_capture(u32 str_id,
        stream->curr_bytes = 0;
        stream->cumm_bytes = 0;
 
+       tmp_buf = kcalloc(mmap_buf->entries, sizeof(*tmp_buf), GFP_KERNEL);
+       if (!tmp_buf)
+               return -ENOMEM;
+       if (copy_from_user(tmp_buf, (void __user *)mmap_buf->buff,
+                       mmap_buf->entries * sizeof(*tmp_buf))) {
+               retval = -EFAULT;
+               goto out_free;
+       }
+
        pr_debug("sst:new buffers count %d status %d\n",
                        mmap_buf->entries, stream->status);
-       buf_entry = mmap_buf->buff;
+       buf_entry = tmp_buf;
        for (i = 0; i < mmap_buf->entries; i++) {
-               BUG_ON(!buf_entry);
                bufs = kzalloc(sizeof(*bufs), GFP_KERNEL);
-               if (!bufs)
-                       return -ENOMEM;
+               if (!bufs) {
+                       retval = -ENOMEM;
+                       goto out_free;
+               }
                bufs->size = buf_entry->size;
                bufs->offset = buf_entry->offset;
                bufs->addr = sst_drv_ctx->mmap_mem;
@@ -293,13 +302,15 @@ static int intel_sst_mmap_play_capture(u32 str_id,
                        if (sst_play_frame(str_id) < 0) {
                                pr_warn("sst: play frames fail\n");
                                mutex_unlock(&stream->lock);
-                               return -EIO;
+                               retval = -EIO;
+                               goto out_free;
                        }
                } else if (stream->ops == STREAM_OPS_CAPTURE) {
                        if (sst_capture_frame(str_id) < 0) {
                                pr_warn("sst: capture frame fail\n");
                                mutex_unlock(&stream->lock);
-                               return -EIO;
+                               retval = -EIO;
+                               goto out_free;
                        }
                }
        }
@@ -314,6 +325,9 @@ static int intel_sst_mmap_play_capture(u32 str_id,
        if (retval >= 0)
                retval = stream->cumm_bytes;
        pr_debug("sst:end of play/rec ioctl bytes = %d!!\n", retval);
+
+out_free:
+       kfree(tmp_buf);
        return retval;
 }
 
@@ -377,7 +391,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
 {
        struct sst_stream_bufs *stream_bufs;
        unsigned long index, mmap_len;
-       unsigned char *bufp;
+       unsigned char __user *bufp;
        unsigned long size, copied_size;
        int retval = 0, add_to_list = 0;
        static int sent_offset;
@@ -512,9 +526,7 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
                        /* copy to user */
                        list_for_each_entry_safe(entry, _entry,
                                                copy_to_list, node) {
-                               if (copy_to_user((void *)
-                                            iovec[entry->iov_index].iov_base +
-                                            entry->iov_offset,
+                               if (copy_to_user(iovec[entry->iov_index].iov_base + entry->iov_offset,
                                             kbufs->addr + entry->offset,
                                             entry->size)) {
                                        /* Clean up the list and return error */
@@ -590,7 +602,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
                        buf, (int) count, (int) stream->status);
 
        stream->buf_type = SST_BUF_USER_STATIC;
-       iovec.iov_base = (void *)buf;
+       iovec.iov_base = buf;
        iovec.iov_len  = count;
        nr_segs = 1;
 
@@ -838,7 +850,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
 
        case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
-               struct snd_sst_params *str_param = (struct snd_sst_params *)arg;
+               struct snd_sst_params str_param;
 
                pr_debug("sst: IOCTL_SET_PARAMS recieved!\n");
                if (minor != STREAM_MODULE) {
@@ -846,17 +858,25 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        break;
                }
 
+               if (copy_from_user(&str_param, (void __user *)arg,
+                               sizeof(str_param))) {
+                       retval = -EFAULT;
+                       break;
+               }
+
                if (!str_id) {
 
-                       retval = sst_get_stream(str_param);
+                       retval = sst_get_stream(&str_param);
                        if (retval > 0) {
                                struct stream_info *str_info;
+                               char __user *dest;
+
                                sst_drv_ctx->stream_cnt++;
                                data->str_id = retval;
                                str_info = &sst_drv_ctx->streams[retval];
                                str_info->src = SST_DRV;
-                               retval = copy_to_user(&str_param->stream_id,
-                                               &retval, sizeof(__u32));
+                               dest = (char __user *)arg + offsetof(struct snd_sst_params, stream_id);
+                               retval = copy_to_user(dest, &retval, sizeof(__u32));
                                if (retval)
                                        retval = -EFAULT;
                        } else {
@@ -866,16 +886,14 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                } else {
                        pr_debug("sst: SET_STREAM_PARAMS recieved!\n");
                        /* allocated set params only */
-                       retval = sst_set_stream_param(str_id, str_param);
+                       retval = sst_set_stream_param(str_id, &str_param);
                        /* Block the call for reply */
                        if (!retval) {
                                int sfreq = 0, word_size = 0, num_channel = 0;
-                               sfreq = str_param->sparams.uc.pcm_params.sfreq;
-                               word_size = str_param->sparams.
-                                               uc.pcm_params.pcm_wd_sz;
-                               num_channel = str_param->
-                                       sparams.uc.pcm_params.num_chan;
-                               if (str_param->ops == STREAM_OPS_CAPTURE) {
+                               sfreq = str_param.sparams.uc.pcm_params.sfreq;
+                               word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz;
+                               num_channel = str_param.sparams.uc.pcm_params.num_chan;
+                               if (str_param.ops == STREAM_OPS_CAPTURE) {
                                        sst_drv_ctx->scard_ops->\
                                        set_pcm_audio_params(sfreq,
                                                word_size, num_channel);
@@ -885,41 +903,39 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
        }
        case _IOC_NR(SNDRV_SST_SET_VOL): {
-               struct snd_sst_vol *set_vol;
-               struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
+               struct snd_sst_vol set_vol;
+
+               if (copy_from_user(&set_vol, (void __user *)arg,
+                               sizeof(set_vol))) {
+                       pr_debug("sst: copy failed\n");
+                       retval = -EFAULT;
+                       break;
+               }
                pr_debug("sst: SET_VOLUME recieved for %d!\n",
-                               rec_vol->stream_id);
-               if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
+                               set_vol.stream_id);
+               if (minor == STREAM_MODULE && set_vol.stream_id == 0) {
                        pr_debug("sst: invalid operation!\n");
                        retval = -EPERM;
                        break;
                }
-               set_vol = kzalloc(sizeof(*set_vol), GFP_ATOMIC);
-               if (!set_vol) {
-                       pr_debug("sst: mem allocation failed\n");
-                       retval = -ENOMEM;
-                       break;
-               }
-               if (copy_from_user(set_vol, rec_vol, sizeof(*set_vol))) {
-                       pr_debug("sst: copy failed\n");
-                       retval = -EFAULT;
-                       break;
-               }
-               retval = sst_set_vol(set_vol);
-               kfree(set_vol);
+               retval = sst_set_vol(&set_vol);
                break;
        }
        case _IOC_NR(SNDRV_SST_GET_VOL): {
-               struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
                struct snd_sst_vol get_vol;
+
+               if (copy_from_user(&get_vol, (void __user *)arg,
+                               sizeof(get_vol))) {
+                       retval = -EFAULT;
+                       break;
+               }
                pr_debug("sst: IOCTL_GET_VOLUME recieved for stream = %d!\n",
-                               rec_vol->stream_id);
-               if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
+                               get_vol.stream_id);
+               if (minor == STREAM_MODULE && get_vol.stream_id == 0) {
                        pr_debug("sst: invalid operation!\n");
                        retval = -EPERM;
                        break;
                }
-               get_vol.stream_id = rec_vol->stream_id;
                retval = sst_get_vol(&get_vol);
                if (retval) {
                        retval = -EIO;
@@ -928,7 +944,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                pr_debug("sst: id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
                                get_vol.stream_id, get_vol.volume,
                                get_vol.ramp_duration, get_vol.ramp_type);
-               if (copy_to_user((struct snd_sst_vol *)arg,
+               if (copy_to_user((struct snd_sst_vol __user *)arg,
                                &get_vol, sizeof(get_vol))) {
                        retval = -EFAULT;
                        break;
@@ -938,25 +954,20 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        }
 
        case _IOC_NR(SNDRV_SST_MUTE): {
-               struct snd_sst_mute *set_mute;
-               struct snd_sst_vol *rec_mute = (struct snd_sst_vol *)arg;
-               pr_debug("sst: SNDRV_SST_SET_VOLUME recieved for %d!\n",
-                       rec_mute->stream_id);
-               if (minor == STREAM_MODULE && rec_mute->stream_id == 0) {
-                       retval = -EPERM;
-                       break;
-               }
-               set_mute = kzalloc(sizeof(*set_mute), GFP_ATOMIC);
-               if (!set_mute) {
-                       retval = -ENOMEM;
+               struct snd_sst_mute set_mute;
+
+               if (copy_from_user(&set_mute, (void __user *)arg,
+                               sizeof(set_mute))) {
+                       retval = -EFAULT;
                        break;
                }
-               if (copy_from_user(set_mute, rec_mute, sizeof(*set_mute))) {
-                       retval = -EFAULT;
+               pr_debug("sst: SNDRV_SST_SET_VOLUME recieved for %d!\n",
+                       set_mute.stream_id);
+               if (minor == STREAM_MODULE && set_mute.stream_id == 0) {
+                       retval = -EPERM;
                        break;
                }
-               retval = sst_set_mute(set_mute);
-               kfree(set_mute);
+               retval = sst_set_mute(&set_mute);
                break;
        }
        case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): {
@@ -973,7 +984,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        retval = -EIO;
                        break;
                }
-               if (copy_to_user((struct snd_sst_get_stream_params *)arg,
+               if (copy_to_user((struct snd_sst_get_stream_params __user *)arg,
                                        &get_params, sizeof(get_params))) {
                        retval = -EFAULT;
                        break;
@@ -983,16 +994,22 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        }
 
        case _IOC_NR(SNDRV_SST_MMAP_PLAY):
-       case _IOC_NR(SNDRV_SST_MMAP_CAPTURE):
+       case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): {
+               struct snd_sst_mmap_buffs mmap_buf;
+
                pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
                }
-               retval = intel_sst_mmap_play_capture(str_id,
-                               (struct snd_sst_mmap_buffs *)arg);
+               if (copy_from_user(&mmap_buf, (void __user *)arg,
+                               sizeof(mmap_buf))) {
+                       retval = -EFAULT;
+                       break;
+               }
+               retval = intel_sst_mmap_play_capture(str_id, &mmap_buf);
                break;
-
+       }
        case _IOC_NR(SNDRV_SST_STREAM_DROP):
                pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n");
                if (minor != STREAM_MODULE) {
@@ -1003,7 +1020,6 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
 
        case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): {
-               unsigned long long *ms = (unsigned long long *)arg;
                struct snd_sst_tstamp tstamp = {0};
                unsigned long long time, freq, mod;
 
@@ -1013,14 +1029,14 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        break;
                }
                memcpy_fromio(&tstamp,
-                       ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
-                       +(str_id * sizeof(tstamp))),
+                       sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
                        sizeof(tstamp));
                time = tstamp.samples_rendered;
                freq = (unsigned long long) tstamp.sampling_frequency;
                time = time * 1000; /* converting it to ms */
                mod = do_div(time, freq);
-               if (copy_to_user(ms, &time, sizeof(*ms)))
+               if (copy_to_user((void __user *)arg, &time,
+                               sizeof(unsigned long long)))
                        retval = -EFAULT;
                break;
        }
@@ -1065,92 +1081,118 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        }
 
        case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
-               struct snd_sst_target_device *target_device;
+               struct snd_sst_target_device target_device;
 
                pr_debug("sst: SET_TARGET_DEVICE recieved!\n");
-               target_device = (struct snd_sst_target_device *)arg;
-               BUG_ON(!target_device);
+               if (copy_from_user(&target_device, (void __user *)arg,
+                               sizeof(target_device))) {
+                       retval = -EFAULT;
+                       break;
+               }
                if (minor != AM_MODULE) {
                        retval = -EBADRQC;
                        break;
                }
-               retval = sst_target_device_select(target_device);
+               retval = sst_target_device_select(&target_device);
                break;
        }
 
        case _IOC_NR(SNDRV_SST_DRIVER_INFO): {
-               struct snd_sst_driver_info *info =
-                       (struct snd_sst_driver_info *)arg;
+               struct snd_sst_driver_info info;
 
                pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n");
-               info->version = SST_VERSION_NUM;
+               info.version = SST_VERSION_NUM;
                /* hard coding, shud get sumhow later */
-               info->active_pcm_streams = sst_drv_ctx->stream_cnt -
+               info.active_pcm_streams = sst_drv_ctx->stream_cnt -
                                                sst_drv_ctx->encoded_cnt;
-               info->active_enc_streams = sst_drv_ctx->encoded_cnt;
-               info->max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
-               info->max_enc_streams = MAX_ENC_STREAM;
-               info->buf_per_stream = sst_drv_ctx->mmap_len;
+               info.active_enc_streams = sst_drv_ctx->encoded_cnt;
+               info.max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM;
+               info.max_enc_streams = MAX_ENC_STREAM;
+               info.buf_per_stream = sst_drv_ctx->mmap_len;
+               if (copy_to_user((void __user *)arg, &info,
+                               sizeof(info)))
+                       retval = -EFAULT;
                break;
        }
 
        case _IOC_NR(SNDRV_SST_STREAM_DECODE): {
-               struct snd_sst_dbufs *param =
-                               (struct snd_sst_dbufs *)arg, dbufs_local;
-               int i;
+               struct snd_sst_dbufs param;
+               struct snd_sst_dbufs dbufs_local;
                struct snd_sst_buffs ibufs, obufs;
-               struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
-                               obuf_temp[param->obufs->entries];
+               struct snd_sst_buff_entry *ibuf_tmp, *obuf_tmp;
+               char __user *dest;
 
                pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
                }
-               if (!param) {
-                       retval = -EINVAL;
+               if (copy_from_user(&param, (void __user *)arg,
+                               sizeof(param))) {
+                       retval = -EFAULT;
                        break;
                }
 
-               dbufs_local.input_bytes_consumed = param->input_bytes_consumed;
+               dbufs_local.input_bytes_consumed = param.input_bytes_consumed;
                dbufs_local.output_bytes_produced =
-                                       param->output_bytes_produced;
-               dbufs_local.ibufs = &ibufs;
-               dbufs_local.obufs = &obufs;
-               dbufs_local.ibufs->entries = param->ibufs->entries;
-               dbufs_local.ibufs->type = param->ibufs->type;
-               dbufs_local.obufs->entries = param->obufs->entries;
-               dbufs_local.obufs->type = param->obufs->type;
-
-               dbufs_local.ibufs->buff_entry = ibuf_temp;
-               for (i = 0; i < dbufs_local.ibufs->entries; i++) {
-                       ibuf_temp[i].buffer =
-                               param->ibufs->buff_entry[i].buffer;
-                       ibuf_temp[i].size =
-                               param->ibufs->buff_entry[i].size;
+                                       param.output_bytes_produced;
+
+               if (copy_from_user(&ibufs, (void __user *)param.ibufs, sizeof(ibufs))) {
+                       retval = -EFAULT;
+                       break;
+               }
+               if (copy_from_user(&obufs, (void __user *)param.obufs, sizeof(obufs))) {
+                       retval = -EFAULT;
+                       break;
                }
-               dbufs_local.obufs->buff_entry = obuf_temp;
-               for (i = 0; i < dbufs_local.obufs->entries; i++) {
-                       obuf_temp[i].buffer =
-                               param->obufs->buff_entry[i].buffer;
-                       obuf_temp[i].size =
-                               param->obufs->buff_entry[i].size;
+
+               ibuf_tmp = kcalloc(ibufs.entries, sizeof(*ibuf_tmp), GFP_KERNEL);
+               obuf_tmp = kcalloc(obufs.entries, sizeof(*obuf_tmp), GFP_KERNEL);
+               if (!ibuf_tmp || !obuf_tmp) {
+                       retval = -ENOMEM;
+                       goto free_iobufs;
+               }
+
+               if (copy_from_user(ibuf_tmp, (void __user *)ibufs.buff_entry,
+                               ibufs.entries * sizeof(*ibuf_tmp))) {
+                       retval = -EFAULT;
+                       goto free_iobufs;
                }
+               ibufs.buff_entry = ibuf_tmp;
+               dbufs_local.ibufs = &ibufs;
+
+               if (copy_from_user(obuf_tmp, (void __user *)obufs.buff_entry,
+                               obufs.entries * sizeof(*obuf_tmp))) {
+                       retval = -EFAULT;
+                       goto free_iobufs;
+               }
+               obufs.buff_entry = obuf_tmp;
+               dbufs_local.obufs = &obufs;
+
                retval = sst_decode(str_id, &dbufs_local);
-               if (retval)
-                       retval =  -EAGAIN;
-               if (copy_to_user(&param->input_bytes_consumed,
+               if (retval) {
+                       retval = -EAGAIN;
+                       goto free_iobufs;
+               }
+
+               dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
+               if (copy_to_user(dest,
                                &dbufs_local.input_bytes_consumed,
                                sizeof(unsigned long long))) {
-                       retval =  -EFAULT;
-                       break;
+                       retval = -EFAULT;
+                       goto free_iobufs;
                }
-               if (copy_to_user(&param->output_bytes_produced,
+
+               dest = (char __user *)arg + offsetof(struct snd_sst_dbufs, input_bytes_consumed);
+               if (copy_to_user(dest,
                                &dbufs_local.output_bytes_produced,
                                sizeof(unsigned long long))) {
-                       retval =  -EFAULT;
-                       break;
+                       retval = -EFAULT;
+                       goto free_iobufs;
                }
+free_iobufs:
+               kfree(ibuf_tmp);
+               kfree(obuf_tmp);
                break;
        }
 
@@ -1164,7 +1206,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
 
        case _IOC_NR(SNDRV_SST_STREAM_BYTES_DECODED): {
-               unsigned long long *bytes = (unsigned long long *)arg;
+               unsigned long long __user *bytes = (unsigned long long __user *)arg;
                struct snd_sst_tstamp tstamp = {0};
 
                pr_debug("sst: STREAM_BYTES_DECODED recieved!\n");
@@ -1173,8 +1215,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        break;
                }
                memcpy_fromio(&tstamp,
-                       ((void *)(sst_drv_ctx->mailbox + SST_TIME_STAMP)
-                       +(str_id * sizeof(tstamp))),
+                       sst_drv_ctx->mailbox + SST_TIME_STAMP + str_id * sizeof(tstamp),
                        sizeof(tstamp));
                if (copy_to_user(bytes, &tstamp.bytes_processed,
                                sizeof(*bytes)))
@@ -1197,7 +1238,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        kfree(fw_info);
                        break;
                }
-               if (copy_to_user((struct snd_sst_dbufs *)arg,
+               if (copy_to_user((struct snd_sst_dbufs __user *)arg,
                                fw_info, sizeof(*fw_info))) {
                        kfree(fw_info);
                        retval = -EFAULT;
index 73a98c851e4adfa70de483f61b4bc05bc40e6e9d..bf0ead78bfae4e967c2c9ed7abefe01116a17b0a 100644 (file)
@@ -231,8 +231,8 @@ struct stream_info {
        spinlock_t          pcm_lock;
        bool                    mmapped;
        unsigned int            sg_index; /*  current buf Index  */
-       unsigned char           *cur_ptr; /*  Current static bufs  */
-       struct snd_sst_buf_entry *buf_entry;
+       unsigned char __user    *cur_ptr; /*  Current static bufs  */
+       struct snd_sst_buf_entry __user *buf_entry;
        struct sst_block        data_blk; /* stream ops block */
        struct sst_block        ctrl_blk; /* stream control cmd block */
        enum snd_sst_buf_type   buf_type;
index 1934805844f21247239e047e4093f4e47d634680..978bf87ff13d50ff3659b8168874f2fc1a01947a 100644 (file)
@@ -22,7 +22,7 @@ int ENE_InitMedia(struct us_data *us)
        int     result;
        BYTE    MiscReg03 = 0;
 
-       printk("--- Initial Nedia ---\n");
+       printk("--- Init Media ---\n");
        result = ENE_Read_BYTE(us, REG_CARD_STATUS, &MiscReg03);
        if (result != USB_STOR_XFER_GOOD)
        {
@@ -64,7 +64,7 @@ int ENE_Read_BYTE(struct us_data *us, WORD index, void *buf)
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
        int result;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x01;
        bcb->Flags                      = 0x80;
@@ -92,7 +92,7 @@ int ENE_SDInit(struct us_data *us)
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->Flags = 0x80;
        bcb->CDB[0] = 0xF2;
@@ -112,7 +112,7 @@ int ENE_SDInit(struct us_data *us)
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -161,7 +161,7 @@ int ENE_MSInit(struct us_data *us)
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -219,7 +219,7 @@ int ENE_SMInit(struct us_data *us)
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -341,7 +341,7 @@ int ENE_LoadBinCode(struct us_data *us, BYTE flag)
                break;
        }
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x800;
        bcb->Flags =0x00;
@@ -433,7 +433,7 @@ int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length)
 
        //printk("transport --- ENE_Read_Data\n");
        // set up the command wrapper
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = length;
        bcb->Flags =0x80;
@@ -470,7 +470,7 @@ int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length)
 
        //printk("transport --- ENE_Write_Data\n");
        // set up the command wrapper
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = length;
        bcb->Flags =0x00;
index d4340a9da87dcde456856b8cc3cb18914237ea26..9a3fdb4e4fe46ecaddb48e46c468a6f69f247a64 100644 (file)
@@ -15,7 +15,7 @@ int MS_ReaderCopyBlock(struct us_data *us, WORD oldphy, WORD newphy, WORD PhyBlo
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200*len;
        bcb->Flags                      = 0x00;
@@ -53,7 +53,7 @@ int MS_ReaderReadPage(struct us_data *us, DWORD PhyBlockAddr, BYTE PageNum, PDWO
                return USB_STOR_TRANSPORT_ERROR;
 
        // Read Page Data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -69,7 +69,7 @@ int MS_ReaderReadPage(struct us_data *us, DWORD PhyBlockAddr, BYTE PageNum, PDWO
                return USB_STOR_TRANSPORT_ERROR;
 
        // Read Extra Data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x4;
        bcb->Flags                      = 0x80;
@@ -108,7 +108,7 @@ int MS_ReaderEraseBlock(struct us_data *us, DWORD PhyBlockAddr)
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -673,7 +673,7 @@ int MS_LibReadExtraBlock(struct us_data *us, DWORD PhyBlock, BYTE PageNum, BYTE
        //printk("MS_LibReadExtraBlock --- PhyBlock = %x, PageNum = %x, blen = %x\n", PhyBlock, PageNum, blen);
 
        // Read Extra Data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x4 * blen;
        bcb->Flags                      = 0x80;
@@ -700,7 +700,7 @@ int MS_LibReadExtra(struct us_data *us, DWORD PhyBlock, BYTE PageNum, MS_LibType
        BYTE    ExtBuf[4];
 
        //printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum);
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x4;
        bcb->Flags                      = 0x80;
@@ -807,7 +807,7 @@ int MS_LibOverwriteExtra(struct us_data *us, DWORD PhyBlockAddr, BYTE PageNum, B
        if (result != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_ERROR;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x4;
        bcb->Flags                      = 0x80;
index ad0c5c629935013f10b6b919e018806f2ba0ff3d..cb92d25acee07094ebd0653d40e07584fac79860 100644 (file)
@@ -145,7 +145,7 @@ int MS_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
                }
 
                // set up the command wrapper
-               memset(bcb, 0, sizeof(bcb));
+               memset(bcb, 0, sizeof(struct bulk_cb_wrap));
                bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
                bcb->DataTransferLength = blenByte;
                bcb->Flags  = 0x80;
@@ -193,7 +193,7 @@ int MS_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
                        blkno  = phyblk * 0x20 + PageNum;
 
                        // set up the command wrapper
-                       memset(bcb, 0, sizeof(bcb));
+                       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
                        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
                        bcb->DataTransferLength = 0x200 * len;
                        bcb->Flags  = 0x80;
@@ -250,7 +250,7 @@ int MS_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
                }
 
                // set up the command wrapper
-               memset(bcb, 0, sizeof(bcb));
+               memset(bcb, 0, sizeof(struct bulk_cb_wrap));
                bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
                bcb->DataTransferLength = blenByte;
                bcb->Flags  = 0x00;
index a2671404f7ac244c39f51c44303fae0df16fceaf..da4f42af3838eb209e7545128b74d0aaedcebe7b 100644 (file)
@@ -87,7 +87,7 @@ static int slave_configure(struct scsi_device *sdev)
 
 /* This is always called with scsi_lock(host) held */
 //----- queuecommand() ---------------------
-static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
+static int queuecommand_lck(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
 {
        struct us_data *us = host_to_us(srb->device->host);
 
@@ -117,6 +117,8 @@ static int queuecommand(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
        return 0;
 }
 
+static DEF_SCSI_QCMD(queuecommand)
+
 /***********************************************************************
  * Error handling functions
  ***********************************************************************/
index 6c332f850ebe2a647545d30712fd79d103ef3e72..d646507a361135f975b6e36b6fbd70014a0f40eb 100644 (file)
@@ -152,7 +152,7 @@ int SD_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
                bnByte = bn;
                
        // set up the command wrapper
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = blenByte;
        bcb->Flags  = 0x80;
@@ -192,7 +192,7 @@ int SD_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
                bnByte = bn;
 
        // set up the command wrapper
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = blenByte;
        bcb->Flags  = 0x00;
index 844b65988636a05e29335c88a64ac3dd8bc2584c..1b52535a388f534ea6307a50026306799f410c08 100644 (file)
@@ -266,7 +266,7 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf,BYTE *redundant)
        addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
 
        // Read sect data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -281,7 +281,7 @@ int Ssfdc_D_ReadSect(struct us_data *us, BYTE *buf,BYTE *redundant)
                return USB_STOR_TRANSPORT_ERROR;
 
        // Read redundant
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x10;
        bcb->Flags                      = 0x80;
@@ -319,7 +319,7 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,BYTE *redundant)
        addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
 
        // Read sect data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200*count;
        bcb->Flags                      = 0x80;
@@ -334,7 +334,7 @@ int Ssfdc_D_ReadBlock(struct us_data *us, WORD count, BYTE *buf,BYTE *redundant)
                return USB_STOR_TRANSPORT_ERROR;
 
        // Read redundant
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x10;
        bcb->Flags                      = 0x80;
@@ -536,7 +536,7 @@ int Ssfdc_D_CopyBlock(struct us_data *us, WORD count, BYTE *buf,BYTE *redundant)
        WriteAddr = WriteAddr*(WORD)Ssfdc.MaxSectors;
 
        // Write sect data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200*count;
        bcb->Flags                      = 0x00;
@@ -754,7 +754,7 @@ int Ssfdc_D_WriteSectForCopy(struct us_data *us, BYTE *buf, BYTE *redundant)
        addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
 
        // Write sect data
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x00;
@@ -791,7 +791,7 @@ int Ssfdc_D_EraseBlock(struct us_data *us)
        addr=(WORD)Media.Zone*Ssfdc.MaxBlocks+Media.PhyBlock;
        addr=addr*(WORD)Ssfdc.MaxSectors;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x200;
        bcb->Flags                      = 0x80;
@@ -827,7 +827,7 @@ int Ssfdc_D_ReadRedtData(struct us_data *us, BYTE *redundant)
        addr = (WORD)Media.Zone*Ssfdc.MaxBlocks+Media.PhyBlock;
        addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x10;
        bcb->Flags                      = 0x80;
@@ -870,7 +870,7 @@ int Ssfdc_D_WriteRedtData(struct us_data *us, BYTE *redundant)
        addr = (WORD)Media.Zone*Ssfdc.MaxBlocks+Media.PhyBlock;
        addr = addr*(WORD)Ssfdc.MaxSectors+Media.Sector;
 
-       memset(bcb, 0, sizeof(bcb));
+       memset(bcb, 0, sizeof(struct bulk_cb_wrap));
        bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
        bcb->DataTransferLength = 0x10;
        bcb->Flags                      = 0x80;
index fd98df643ab0d999655b26c68ea4d844ee44729f..111160cce4419e7e77b80f3cd3d439b8646f7898 100644 (file)
@@ -40,7 +40,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
        us->current_urb->error_count = 0;
        us->current_urb->status = 0;
 
-//     us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
+       us->current_urb->transfer_flags = 0;
        if (us->current_urb->transfer_buffer == us->iobuf)
                us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        us->current_urb->transfer_dma = us->iobuf_dma;
index 75aa7a36307d8f23940bd1ae2e6ee91f49bb80cf..4ca45ec7fd84ef088e3258450e135fb7ccaacc72 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/console.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <linux/i2c-id.h>
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/interrupt.h>
@@ -733,7 +732,6 @@ static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id)
  edev:
        platform_device_unregister(dcon_device);
        dcon_device = NULL;
-       i2c_set_clientdata(client, NULL);
  eirq:
        free_irq(DCON_IRQ, &dcon_driver);
  einit:
@@ -757,8 +755,6 @@ static int dcon_remove(struct i2c_client *client)
                platform_device_unregister(dcon_device);
        cancel_work_sync(&dcon_work);
 
-       i2c_set_clientdata(client, NULL);
-
        return 0;
 }
 
index 1d159ff82fd203e3d7be0313c522bf7946c209e3..a99879bada4279a5843ff3d3409b908f6c8f8a0b 100644 (file)
@@ -330,8 +330,6 @@ void construct_mic_iv(unsigned char *mic_iv,
        for (i = 8; i < 14; i++)
                mic_iv[i] = pn_vector[13 - i];  /* mic_iv[8:13] = PN[5:0] */
 #endif
-       i = (payload_length / 256);
-       i = (payload_length % 256);
        mic_iv[14] = (unsigned char)(payload_length / 256);
        mic_iv[15] = (unsigned char)(payload_length % 256);
 
index ebf9074a90838367fc7dde6aac3cba0fe6a3e131..ddacfc6c486179274394b330153c901dfc7c63b7 100644 (file)
@@ -65,6 +65,7 @@ struct usb_device_id rtusb_usb_id[] = {
        {USB_DEVICE(0x14B2, 0x3C07)},   /* AL */
        {USB_DEVICE(0x050D, 0x8053)},   /* Belkin */
        {USB_DEVICE(0x050D, 0x825B)},   /* Belkin */
+       {USB_DEVICE(0x050D, 0x935A)},   /* Belkin F6D4050 v1 */
        {USB_DEVICE(0x050D, 0x935B)},   /* Belkin F6D4050 v2 */
        {USB_DEVICE(0x14B2, 0x3C23)},   /* Airlink */
        {USB_DEVICE(0x14B2, 0x3C27)},   /* Airlink */
index a202194b5cbb15de11f3e58e739b0c9fb2630c53..b1786dcac24566dbffb6ab57a677be9f8de5a0c3 100644 (file)
@@ -5829,6 +5829,9 @@ static void rtl8192_rx(struct net_device *dev)
                     }
                 }
 
+               pci_unmap_single(priv->pdev, *((dma_addr_t *) skb->cb),
+                       priv->rxbuffersize, PCI_DMA_FROMDEVICE);
+
                 skb = new_skb;
                 priv->rx_buf[priv->rx_idx] = skb;
                 *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE);
index d1674cd282dcd7deb370cca6b75c8f0f69b3ed73..831d81e0e429b81924a53f8cad76aebd02d8be4d 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kref.h>
-#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/usb.h>
index bbf3d9c4abb03aa6dc4b17f9e3f0d123cc7306d7..097e82bc7a6315d92bd0c158bca8a10340f6c22c 100644 (file)
@@ -766,7 +766,7 @@ static int solo_enc_open(struct file *file)
                                    &solo_enc->lock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct videobuf_buffer), fh);
+                                   sizeof(struct videobuf_buffer), fh, NULL);
 
        spin_unlock(&solo_enc->lock);
 
index 9731fa02b5e80702c380e42dfd57c996dad03a3e..6ffd21de837d8bf5161d6654206ce918439cc78f 100644 (file)
@@ -437,7 +437,7 @@ static int solo_v4l2_open(struct file *file)
                                    &solo_dev->pdev->dev, &fh->slock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    SOLO_DISP_PIX_FIELD,
-                                   sizeof(struct videobuf_buffer), fh);
+                                   sizeof(struct videobuf_buffer), fh, NULL);
 
        return 0;
 }
index b7b60d5e866023d461a8661a2fa278330ff8a5de..a2db956edd54db0f81979bd038bcfc5d348a7232 100644 (file)
@@ -1,5 +1,4 @@
 #include <linux/console.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/wait.h>
 
index 92e8911418962d19796e6dadf7db52d43ea745b7..02f0fc504cf5ef13595ad67b7668c28a54534ce7 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_STRADIS
         tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
-        depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
+        depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS && BKL
         help
           Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
           driver for PCI.  There is a product page at
index a057824e7ebc25ac5e2b5102d002804a79c983d2..807dd7eb748f5e84bfafa9efaf0e2a4dc2118a81 100644 (file)
@@ -1286,6 +1286,7 @@ static long saa_ioctl(struct file *file,
        case VIDIOCGCAP:
                {
                        struct video_capability b;
+                       memset(&b, 0, sizeof(b));
                        strcpy(b.name, saa->video_dev.name);
                        b.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
                                VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
@@ -1416,6 +1417,7 @@ static long saa_ioctl(struct file *file,
        case VIDIOCGWIN:
                {
                        struct video_window vw;
+                       memset(&vw, 0, sizeof(vw));
                        vw.x = saa->win.x;
                        vw.y = saa->win.y;
                        vw.width = saa->win.width;
@@ -1448,6 +1450,7 @@ static long saa_ioctl(struct file *file,
        case VIDIOCGFBUF:
                {
                        struct video_buffer v;
+                       memset(&v, 0, sizeof(v));
                        v.base = (void *)saa->win.vidadr;
                        v.height = saa->win.sheight;
                        v.width = saa->win.swidth;
@@ -1492,6 +1495,7 @@ static long saa_ioctl(struct file *file,
        case VIDIOCGAUDIO:
                {
                        struct video_audio v;
+                       memset(&v, 0, sizeof(v));
                        v = saa->audio_dev;
                        v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
                        v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
@@ -1534,6 +1538,7 @@ static long saa_ioctl(struct file *file,
        case VIDIOCGUNIT:
                {
                        struct video_unit vu;
+                       memset(&vu, 0, sizeof(vu));
                        vu.video = saa->video_dev.minor;
                        vu.vbi = VIDEO_NO_UNIT;
                        vu.radio = VIDEO_NO_UNIT;
@@ -1888,6 +1893,7 @@ static int saa_open(struct file *file)
 
        saa->user++;
        if (saa->user > 1) {
+               saa->user--;
                unlock_kernel();
                return 0;       /* device open already, don't reset */
        }
@@ -2000,10 +2006,13 @@ static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
        if (retval < 0) {
                dev_err(&pdev->dev, "%d: error in registering video device!\n",
                        num);
-               goto errio;
+               goto errirq;
        }
 
        return 0;
+
+errirq:
+       free_irq(saa->irq, saa);
 errio:
        iounmap(saa->saa7146_mem);
 err:
index ff64d464143c3cf5253c9fc09f10baa7945f2b07..93de4f2e8bf89defcd6e83e00c2cbe1cd93b8dd4 100644 (file)
@@ -6,7 +6,6 @@ menuconfig TIDSPBRIDGE
        tristate "DSP Bridge driver"
        depends on ARCH_OMAP3
        select OMAP_MBOX_FWK
-       select OMAP_IOMMU
        help
          DSP/BIOS Bridge is designed for platforms that contain a GPP and
          one or more attached DSPs.  The GPP is considered the master or
index 50decc2935c5d575acb8feb24c3bfa55b79376aa..41c644c3318f46fe632173d12f50aad2af8ea4f1 100644 (file)
@@ -2,18 +2,19 @@ obj-$(CONFIG_TIDSPBRIDGE)     += bridgedriver.o
 
 libgen = gen/gb.o gen/gs.o gen/gh.o gen/uuidutil.o
 libcore = core/chnl_sm.o core/msg_sm.o core/io_sm.o core/tiomap3430.o \
-               core/tiomap3430_pwr.o core/tiomap_io.o core/dsp-mmu.o \
+               core/tiomap3430_pwr.o core/tiomap_io.o \
                core/ue_deh.o core/wdt.o core/dsp-clock.o core/sync.o
 libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/dspapi.o \
-               pmgr/cmm.o pmgr/dbll.o
+               pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o
 librmgr = rmgr/dbdcd.o rmgr/disp.o rmgr/drv.o rmgr/mgr.o rmgr/node.o \
                rmgr/proc.o rmgr/pwr.o rmgr/rmm.o rmgr/strm.o rmgr/dspdrv.o \
                rmgr/nldr.o rmgr/drv_interface.o
 libdload = dynload/cload.o dynload/getsection.o dynload/reloc.o \
                 dynload/tramp.o
+libhw = hw/hw_mmu.o
 
 bridgedriver-y := $(libgen) $(libservices) $(libcore) $(libpmgr) $(librmgr) \
-                       $(libdload)
+                       $(libdload) $(libhw)
 
 #Machine dependent
 ccflags-y += -D_TI_ -D_DB_TIOMAP -DTMS32060 \
index 8ae263387a878a4dadc6d6ca72305597f30b6520..16723cd34831348613a09b8cf7a855292ca752db 100644 (file)
@@ -27,8 +27,9 @@
 struct deh_mgr {
        struct bridge_dev_context *hbridge_context;     /* Bridge context. */
        struct ntfy_object *ntfy_obj;   /* NTFY object */
-};
 
-int mmu_fault_isr(struct iommu *mmu);
+       /* MMU Fault DPC */
+       struct tasklet_struct dpc_tasklet;
+};
 
 #endif /* _DEH_ */
index e0a801c1cb98db8ca20681c446293ecdbd3c1780..1c1f157e167a645b4f630ba4ac41d9f9943fff61 100644 (file)
@@ -23,8 +23,8 @@
 #include <plat/clockdomain.h>
 #include <mach-omap2/prm-regbits-34xx.h>
 #include <mach-omap2/cm-regbits-34xx.h>
-#include <dspbridge/dsp-mmu.h>
 #include <dspbridge/devdefs.h>
+#include <hw_defs.h>
 #include <dspbridge/dspioctl.h>        /* for bridge_ioctl_extproc defn */
 #include <dspbridge/sync.h>
 #include <dspbridge/clk.h>
@@ -306,18 +306,6 @@ static const struct bpwr_clk_t bpwr_clks[] = {
 
 #define CLEAR_BIT_INDEX(reg, index)   (reg &= ~(1 << (index)))
 
-struct shm_segs {
-       u32 seg0_da;
-       u32 seg0_pa;
-       u32 seg0_va;
-       u32 seg0_size;
-       u32 seg1_da;
-       u32 seg1_pa;
-       u32 seg1_va;
-       u32 seg1_size;
-};
-
-
 /* This Bridge driver's device context: */
 struct bridge_dev_context {
        struct dev_object *hdev_obj;    /* Handle to Bridge device object. */
@@ -328,6 +316,7 @@ struct bridge_dev_context {
         */
        u32 dw_dsp_ext_base_addr;       /* See the comment above */
        u32 dw_api_reg_base;    /* API mem map'd registers */
+       void __iomem *dw_dsp_mmu_base;  /* DSP MMU Mapped registers */
        u32 dw_api_clk_base;    /* CLK Registers */
        u32 dw_dsp_clk_m2_base; /* DSP Clock Module m2 */
        u32 dw_public_rhea;     /* Pub Rhea */
@@ -339,8 +328,7 @@ struct bridge_dev_context {
        u32 dw_internal_size;   /* Internal memory size */
 
        struct omap_mbox *mbox;         /* Mail box handle */
-       struct iommu *dsp_mmu;      /* iommu for iva2 handler */
-       struct shm_segs sh_s;
+
        struct cfg_hostres *resources;  /* Host Resources */
 
        /*
@@ -353,6 +341,7 @@ struct bridge_dev_context {
 
        /* TC Settings */
        bool tc_word_swap_on;   /* Traffic Controller Word Swap */
+       struct pg_table_attrs *pt_attrs;
        u32 dsp_per_clks;
 };
 
diff --git a/drivers/staging/tidspbridge/core/dsp-mmu.c b/drivers/staging/tidspbridge/core/dsp-mmu.c
deleted file mode 100644 (file)
index 983c95a..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * dsp-mmu.c
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * DSP iommu.
- *
- * Copyright (C) 2010 Texas Instruments, Inc.
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include <dspbridge/host_os.h>
-#include <plat/dmtimer.h>
-#include <dspbridge/dbdefs.h>
-#include <dspbridge/dev.h>
-#include <dspbridge/io_sm.h>
-#include <dspbridge/dspdeh.h>
-#include "_tiomap.h"
-
-#include <dspbridge/dsp-mmu.h>
-
-#define MMU_CNTL_TWL_EN                (1 << 2)
-
-static struct tasklet_struct mmu_tasklet;
-
-#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
-static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
-{
-       void *dummy_addr;
-       u32 fa, tmp;
-       struct iotlb_entry e;
-       struct iommu *mmu = dev_context->dsp_mmu;
-       dummy_addr = (void *)__get_free_page(GFP_ATOMIC);
-
-       /*
-        * Before acking the MMU fault, let's make sure MMU can only
-        * access entry #0. Then add a new entry so that the DSP OS
-        * can continue in order to dump the stack.
-        */
-       tmp = iommu_read_reg(mmu, MMU_CNTL);
-       tmp &= ~MMU_CNTL_TWL_EN;
-       iommu_write_reg(mmu, tmp, MMU_CNTL);
-       fa = iommu_read_reg(mmu, MMU_FAULT_AD);
-       e.da = fa & PAGE_MASK;
-       e.pa = virt_to_phys(dummy_addr);
-       e.valid = 1;
-       e.prsvd = 1;
-       e.pgsz = IOVMF_PGSZ_4K & MMU_CAM_PGSZ_MASK;
-       e.endian = MMU_RAM_ENDIAN_LITTLE;
-       e.elsz = MMU_RAM_ELSZ_32;
-       e.mixed = 0;
-
-       load_iotlb_entry(mmu, &e);
-
-       dsp_clk_enable(DSP_CLK_GPT8);
-
-       dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
-
-       /* Clear MMU interrupt */
-       tmp = iommu_read_reg(mmu, MMU_IRQSTATUS);
-       iommu_write_reg(mmu, tmp, MMU_IRQSTATUS);
-
-       dump_dsp_stack(dev_context);
-       dsp_clk_disable(DSP_CLK_GPT8);
-
-       iopgtable_clear_entry(mmu, fa);
-       free_page((unsigned long)dummy_addr);
-}
-#endif
-
-
-static void fault_tasklet(unsigned long data)
-{
-       struct iommu *mmu = (struct iommu *)data;
-       struct bridge_dev_context *dev_ctx;
-       struct deh_mgr *dm;
-       u32 fa;
-       dev_get_deh_mgr(dev_get_first(), &dm);
-       dev_get_bridge_context(dev_get_first(), &dev_ctx);
-
-       if (!dm || !dev_ctx)
-               return;
-
-       fa = iommu_read_reg(mmu, MMU_FAULT_AD);
-
-#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
-       print_dsp_trace_buffer(dev_ctx);
-       dump_dl_modules(dev_ctx);
-       mmu_fault_print_stack(dev_ctx);
-#endif
-
-       bridge_deh_notify(dm, DSP_MMUFAULT, fa);
-}
-
-/*
- *  ======== mmu_fault_isr ========
- *      ISR to be triggered by a DSP MMU fault interrupt.
- */
-static int mmu_fault_callback(struct iommu *mmu)
-{
-       if (!mmu)
-               return -EPERM;
-
-       iommu_write_reg(mmu, 0, MMU_IRQENABLE);
-       tasklet_schedule(&mmu_tasklet);
-       return 0;
-}
-
-/**
- * dsp_mmu_init() - initialize dsp_mmu module and returns a handle
- *
- * This function initialize dsp mmu module and returns a struct iommu
- * handle to use it for dsp maps.
- *
- */
-struct iommu *dsp_mmu_init()
-{
-       struct iommu *mmu;
-
-       mmu = iommu_get("iva2");
-
-       if (!IS_ERR(mmu)) {
-               tasklet_init(&mmu_tasklet, fault_tasklet, (unsigned long)mmu);
-               mmu->isr = mmu_fault_callback;
-       }
-
-       return mmu;
-}
-
-/**
- * dsp_mmu_exit() - destroy dsp mmu module
- * @mmu:       Pointer to iommu handle.
- *
- * This function destroys dsp mmu module.
- *
- */
-void dsp_mmu_exit(struct iommu *mmu)
-{
-       if (mmu)
-               iommu_put(mmu);
-       tasklet_kill(&mmu_tasklet);
-}
-
-/**
- * user_va2_pa() - get physical address from userspace address.
- * @mm:                mm_struct Pointer of the process.
- * @address:   Virtual user space address.
- *
- */
-static u32 user_va2_pa(struct mm_struct *mm, u32 address)
-{
-       pgd_t *pgd;
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-
-       pgd = pgd_offset(mm, address);
-       if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
-               pmd = pmd_offset(pgd, address);
-               if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
-                       ptep = pte_offset_map(pmd, address);
-                       if (ptep) {
-                               pte = *ptep;
-                               if (pte_present(pte))
-                                       return pte & PAGE_MASK;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/**
- * get_io_pages() - pin and get pages of io user's buffer.
- * @mm:                mm_struct Pointer of the process.
- * @uva:               Virtual user space address.
- * @pages      Pages to be pined.
- * @usr_pgs    struct page array pointer where the user pages will be stored
- *
- */
-static int get_io_pages(struct mm_struct *mm, u32 uva, unsigned pages,
-                                               struct page **usr_pgs)
-{
-       u32 pa;
-       int i;
-       struct page *pg;
-
-       for (i = 0; i < pages; i++) {
-               pa = user_va2_pa(mm, uva);
-
-               if (!pfn_valid(__phys_to_pfn(pa)))
-                       break;
-
-               pg = phys_to_page(pa);
-               usr_pgs[i] = pg;
-               get_page(pg);
-       }
-       return i;
-}
-
-/**
- * user_to_dsp_map() - maps user to dsp virtual address
- * @mmu:       Pointer to iommu handle.
- * @uva:               Virtual user space address.
- * @da         DSP address
- * @size               Buffer size to map.
- * @usr_pgs    struct page array pointer where the user pages will be stored
- *
- * This function maps a user space buffer into DSP virtual address.
- *
- */
-u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
-                               struct page **usr_pgs)
-{
-       int res, w;
-       unsigned pages;
-       int i;
-       struct vm_area_struct *vma;
-       struct mm_struct *mm = current->mm;
-       struct sg_table *sgt;
-       struct scatterlist *sg;
-
-       if (!size || !usr_pgs)
-               return -EINVAL;
-
-       pages = size / PG_SIZE4K;
-
-       down_read(&mm->mmap_sem);
-       vma = find_vma(mm, uva);
-       while (vma && (uva + size > vma->vm_end))
-               vma = find_vma(mm, vma->vm_end + 1);
-
-       if (!vma) {
-               pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
-                                               __func__, uva, size);
-               up_read(&mm->mmap_sem);
-               return -EINVAL;
-       }
-       if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
-               w = 1;
-
-       if (vma->vm_flags & VM_IO)
-               i = get_io_pages(mm, uva, pages, usr_pgs);
-       else
-               i = get_user_pages(current, mm, uva, pages, w, 1,
-                                                       usr_pgs, NULL);
-       up_read(&mm->mmap_sem);
-
-       if (i < 0)
-               return i;
-
-       if (i < pages) {
-               res = -EFAULT;
-               goto err_pages;
-       }
-
-       sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
-       if (!sgt) {
-               res = -ENOMEM;
-               goto err_pages;
-       }
-
-       res = sg_alloc_table(sgt, pages, GFP_KERNEL);
-
-       if (res < 0)
-               goto err_sg;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i)
-               sg_set_page(sg, usr_pgs[i], PAGE_SIZE, 0);
-
-       da = iommu_vmap(mmu, da, sgt, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
-
-       if (!IS_ERR_VALUE(da))
-               return da;
-       res = (int)da;
-
-       sg_free_table(sgt);
-err_sg:
-       kfree(sgt);
-       i = pages;
-err_pages:
-       while (i--)
-               put_page(usr_pgs[i]);
-       return res;
-}
-
-/**
- * user_to_dsp_unmap() - unmaps DSP virtual buffer.
- * @mmu:       Pointer to iommu handle.
- * @da         DSP address
- *
- * This function unmaps a user space buffer into DSP virtual address.
- *
- */
-int user_to_dsp_unmap(struct iommu *mmu, u32 da)
-{
-       unsigned i;
-       struct sg_table *sgt;
-       struct scatterlist *sg;
-
-       sgt = iommu_vunmap(mmu, da);
-       if (!sgt)
-               return -EFAULT;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i)
-               put_page(sg_page(sg));
-       sg_free_table(sgt);
-       kfree(sgt);
-
-       return 0;
-}
index 194badaba0ed0fc1de9ada2970a631b372cc55c1..571864555ddd894c73f2649ca43996b5bf7d77a4 100644 (file)
 #include <dspbridge/ntfy.h>
 #include <dspbridge/sync.h>
 
+/* Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
 /* Bridge Driver */
 #include <dspbridge/dspdeh.h>
 #include <dspbridge/dspio.h>
@@ -287,7 +291,6 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
        struct cod_manager *cod_man;
        struct chnl_mgr *hchnl_mgr;
        struct msg_mgr *hmsg_mgr;
-       struct shm_segs *sm_sg;
        u32 ul_shm_base;
        u32 ul_shm_base_offset;
        u32 ul_shm_limit;
@@ -310,9 +313,18 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
        struct bridge_ioctl_extproc ae_proc[BRDIOCTL_NUMOFMMUTLB];
        struct cfg_hostres *host_res;
        struct bridge_dev_context *pbridge_context;
+       u32 map_attrs;
        u32 shm0_end;
        u32 ul_dyn_ext_base;
        u32 ul_seg1_size = 0;
+       u32 pa_curr = 0;
+       u32 va_curr = 0;
+       u32 gpp_va_curr = 0;
+       u32 num_bytes = 0;
+       u32 all_bits = 0;
+       u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB,
+               HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB
+       };
 
        status = dev_get_bridge_context(hio_mgr->hdev_obj, &pbridge_context);
        if (!pbridge_context) {
@@ -325,8 +337,6 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
                status = -EFAULT;
                goto func_end;
        }
-       sm_sg = &pbridge_context->sh_s;
-
        status = dev_get_cod_mgr(hio_mgr->hdev_obj, &cod_man);
        if (!cod_man) {
                status = -EFAULT;
@@ -461,14 +471,129 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
        if (status)
                goto func_end;
 
-       sm_sg->seg1_pa = ul_gpp_pa;
-       sm_sg->seg1_da = ul_dyn_ext_base;
-       sm_sg->seg1_va = ul_gpp_va;
-       sm_sg->seg1_size = ul_seg1_size;
-       sm_sg->seg0_pa = ul_gpp_pa + ul_pad_size + ul_seg1_size;
-       sm_sg->seg0_da = ul_dsp_va;
-       sm_sg->seg0_va = ul_gpp_va + ul_pad_size + ul_seg1_size;
-       sm_sg->seg0_size = ul_seg_size;
+       pa_curr = ul_gpp_pa;
+       va_curr = ul_dyn_ext_base * hio_mgr->word_size;
+       gpp_va_curr = ul_gpp_va;
+       num_bytes = ul_seg1_size;
+
+       /*
+        * Try to fit into TLB entries. If not possible, push them to page
+        * tables. It is quite possible that if sections are not on
+        * bigger page boundary, we may end up making several small pages.
+        * So, push them onto page tables, if that is the case.
+        */
+       map_attrs = 0x00000000;
+       map_attrs = DSP_MAPLITTLEENDIAN;
+       map_attrs |= DSP_MAPPHYSICALADDR;
+       map_attrs |= DSP_MAPELEMSIZE32;
+       map_attrs |= DSP_MAPDONOTLOCK;
+
+       while (num_bytes) {
+               /*
+                * To find the max. page size with which both PA & VA are
+                * aligned.
+                */
+               all_bits = pa_curr | va_curr;
+               dev_dbg(bridge, "all_bits %x, pa_curr %x, va_curr %x, "
+                       "num_bytes %x\n", all_bits, pa_curr, va_curr,
+                       num_bytes);
+               for (i = 0; i < 4; i++) {
+                       if ((num_bytes >= page_size[i]) && ((all_bits &
+                                                            (page_size[i] -
+                                                             1)) == 0)) {
+                               status =
+                                   hio_mgr->intf_fxns->
+                                   pfn_brd_mem_map(hio_mgr->hbridge_context,
+                                                   pa_curr, va_curr,
+                                                   page_size[i], map_attrs,
+                                                   NULL);
+                               if (status)
+                                       goto func_end;
+                               pa_curr += page_size[i];
+                               va_curr += page_size[i];
+                               gpp_va_curr += page_size[i];
+                               num_bytes -= page_size[i];
+                               /*
+                                * Don't try smaller sizes. Hopefully we have
+                                * reached an address aligned to a bigger page
+                                * size.
+                                */
+                               break;
+                       }
+               }
+       }
+       pa_curr += ul_pad_size;
+       va_curr += ul_pad_size;
+       gpp_va_curr += ul_pad_size;
+
+       /* Configure the TLB entries for the next cacheable segment */
+       num_bytes = ul_seg_size;
+       va_curr = ul_dsp_va * hio_mgr->word_size;
+       while (num_bytes) {
+               /*
+                * To find the max. page size with which both PA & VA are
+                * aligned.
+                */
+               all_bits = pa_curr | va_curr;
+               dev_dbg(bridge, "all_bits for Seg1 %x, pa_curr %x, "
+                       "va_curr %x, num_bytes %x\n", all_bits, pa_curr,
+                       va_curr, num_bytes);
+               for (i = 0; i < 4; i++) {
+                       if (!(num_bytes >= page_size[i]) ||
+                           !((all_bits & (page_size[i] - 1)) == 0))
+                               continue;
+                       if (ndx < MAX_LOCK_TLB_ENTRIES) {
+                               /*
+                                * This is the physical address written to
+                                * DSP MMU.
+                                */
+                               ae_proc[ndx].ul_gpp_pa = pa_curr;
+                               /*
+                                * This is the virtual uncached ioremapped
+                                * address!!!
+                                */
+                               ae_proc[ndx].ul_gpp_va = gpp_va_curr;
+                               ae_proc[ndx].ul_dsp_va =
+                                   va_curr / hio_mgr->word_size;
+                               ae_proc[ndx].ul_size = page_size[i];
+                               ae_proc[ndx].endianism = HW_LITTLE_ENDIAN;
+                               ae_proc[ndx].elem_size = HW_ELEM_SIZE16BIT;
+                               ae_proc[ndx].mixed_mode = HW_MMU_CPUES;
+                               dev_dbg(bridge, "shm MMU TLB entry PA %x"
+                                       " VA %x DSP_VA %x Size %x\n",
+                                       ae_proc[ndx].ul_gpp_pa,
+                                       ae_proc[ndx].ul_gpp_va,
+                                       ae_proc[ndx].ul_dsp_va *
+                                       hio_mgr->word_size, page_size[i]);
+                               ndx++;
+                       } else {
+                               status =
+                                   hio_mgr->intf_fxns->
+                                   pfn_brd_mem_map(hio_mgr->hbridge_context,
+                                                   pa_curr, va_curr,
+                                                   page_size[i], map_attrs,
+                                                   NULL);
+                               dev_dbg(bridge,
+                                       "shm MMU PTE entry PA %x"
+                                       " VA %x DSP_VA %x Size %x\n",
+                                       ae_proc[ndx].ul_gpp_pa,
+                                       ae_proc[ndx].ul_gpp_va,
+                                       ae_proc[ndx].ul_dsp_va *
+                                       hio_mgr->word_size, page_size[i]);
+                               if (status)
+                                       goto func_end;
+                       }
+                       pa_curr += page_size[i];
+                       va_curr += page_size[i];
+                       gpp_va_curr += page_size[i];
+                       num_bytes -= page_size[i];
+                       /*
+                        * Don't try smaller sizes. Hopefully we have reached
+                        * an address aligned to a bigger page size.
+                        */
+                       break;
+               }
+       }
 
        /*
         * Copy remaining entries from CDB. All entries are 1 MB and
@@ -509,12 +634,38 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
                                        "DSP_VA 0x%x\n", ae_proc[ndx].ul_gpp_pa,
                                        ae_proc[ndx].ul_dsp_va);
                                ndx++;
+                       } else {
+                               status = hio_mgr->intf_fxns->pfn_brd_mem_map
+                                   (hio_mgr->hbridge_context,
+                                    hio_mgr->ext_proc_info.ty_tlb[i].
+                                    ul_gpp_phys,
+                                    hio_mgr->ext_proc_info.ty_tlb[i].
+                                    ul_dsp_virt, 0x100000, map_attrs,
+                                    NULL);
                        }
                }
                if (status)
                        goto func_end;
        }
 
+       map_attrs = 0x00000000;
+       map_attrs = DSP_MAPLITTLEENDIAN;
+       map_attrs |= DSP_MAPPHYSICALADDR;
+       map_attrs |= DSP_MAPELEMSIZE32;
+       map_attrs |= DSP_MAPDONOTLOCK;
+
+       /* Map the L4 peripherals */
+       i = 0;
+       while (l4_peripheral_table[i].phys_addr) {
+               status = hio_mgr->intf_fxns->pfn_brd_mem_map
+                   (hio_mgr->hbridge_context, l4_peripheral_table[i].phys_addr,
+                    l4_peripheral_table[i].dsp_virt_addr, HW_PAGE_SIZE4KB,
+                    map_attrs, NULL);
+               if (status)
+                       goto func_end;
+               i++;
+       }
+
        for (i = ndx; i < BRDIOCTL_NUMOFMMUTLB; i++) {
                ae_proc[i].ul_dsp_va = 0;
                ae_proc[i].ul_gpp_pa = 0;
@@ -537,12 +688,12 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
                status = -EFAULT;
                goto func_end;
        } else {
-               if (sm_sg->seg0_da > ul_shm_base) {
+               if (ae_proc[0].ul_dsp_va > ul_shm_base) {
                        status = -EPERM;
                        goto func_end;
                }
                /* ul_shm_base may not be at ul_dsp_va address */
-               ul_shm_base_offset = (ul_shm_base - sm_sg->seg0_da) *
+               ul_shm_base_offset = (ul_shm_base - ae_proc[0].ul_dsp_va) *
                    hio_mgr->word_size;
                /*
                 * bridge_dev_ctrl() will set dev context dsp-mmu info. In
@@ -566,7 +717,8 @@ int bridge_io_on_loaded(struct io_mgr *hio_mgr)
                        goto func_end;
                }
                /* Register SM */
-               status = register_shm_segs(hio_mgr, cod_man, sm_sg->seg0_pa);
+               status =
+                   register_shm_segs(hio_mgr, cod_man, ae_proc[0].ul_gpp_pa);
        }
 
        hio_mgr->shared_mem = (struct shm *)ul_shm_base;
index f22bc12bc0d343294a65eb364c6d3c62c4d5005c..1be081f917a73e643bac5326d7a49dea4bea4ea9 100644 (file)
@@ -23,7 +23,6 @@
 #include <dspbridge/host_os.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
-#include <plat/control.h>
 
 /*  ----------------------------------- DSP/BIOS Bridge */
 #include <dspbridge/dbdefs.h>
 #include <dspbridge/drv.h>
 #include <dspbridge/sync.h>
 
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
 /*  ----------------------------------- Link Driver */
 #include <dspbridge/dspdefs.h>
 #include <dspbridge/dspchnl.h>
@@ -47,6 +50,7 @@
 /*  ----------------------------------- Platform Manager */
 #include <dspbridge/dev.h>
 #include <dspbridge/dspapi.h>
+#include <dspbridge/dmm.h>
 #include <dspbridge/wdt.h>
 
 /*  ----------------------------------- Local */
 #define MMU_SMALL_PAGE_MASK      0xFFFFF000
 #define OMAP3_IVA2_BOOTADDR_MASK 0xFFFFFC00
 #define PAGES_II_LVL_TABLE   512
+#define PHYS_TO_PAGE(phys)      pfn_to_page((phys) >> PAGE_SHIFT)
+
+/*
+ * This is a totally ugly layer violation, but needed until
+ * omap_ctrl_set_dsp_boot*() are provided.
+ */
+#define OMAP3_IVA2_BOOTMOD_IDLE 1
+#define OMAP2_CONTROL_GENERAL 0x270
+#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
+#define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194)
+
+#define OMAP343X_CTRL_REGADDR(reg) \
+       OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+
 
 /* Forward Declarations: */
 static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt);
@@ -91,6 +109,12 @@ static int bridge_brd_mem_copy(struct bridge_dev_context *dev_ctxt,
 static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
                                    u8 *host_buff, u32 dsp_addr,
                                    u32 ul_num_bytes, u32 mem_type);
+static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
+                                 u32 ul_mpu_addr, u32 virt_addr,
+                                 u32 ul_num_bytes, u32 ul_map_attr,
+                                 struct page **mapped_pages);
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
+                                    u32 virt_addr, u32 ul_num_bytes);
 static int bridge_dev_create(struct bridge_dev_context
                                        **dev_cntxt,
                                        struct dev_object *hdev_obj,
@@ -98,8 +122,57 @@ static int bridge_dev_create(struct bridge_dev_context
 static int bridge_dev_ctrl(struct bridge_dev_context *dev_context,
                                  u32 dw_cmd, void *pargs);
 static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt);
+static u32 user_va2_pa(struct mm_struct *mm, u32 address);
+static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa,
+                            u32 va, u32 size,
+                            struct hw_mmu_map_attrs_t *map_attrs);
+static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va,
+                         u32 size, struct hw_mmu_map_attrs_t *attrs);
+static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
+                                 u32 ul_mpu_addr, u32 virt_addr,
+                                 u32 ul_num_bytes,
+                                 struct hw_mmu_map_attrs_t *hw_attrs);
+
 bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr);
 
+/*  ----------------------------------- Globals */
+
+/* Attributes of L2 page tables for DSP MMU */
+struct page_info {
+       u32 num_entries;        /* Number of valid PTEs in the L2 PT */
+};
+
+/* Attributes used to manage the DSP MMU page tables */
+struct pg_table_attrs {
+       spinlock_t pg_lock;     /* Critical section object handle */
+
+       u32 l1_base_pa;         /* Physical address of the L1 PT */
+       u32 l1_base_va;         /* Virtual  address of the L1 PT */
+       u32 l1_size;            /* Size of the L1 PT */
+       u32 l1_tbl_alloc_pa;
+       /* Physical address of Allocated mem for L1 table. May not be aligned */
+       u32 l1_tbl_alloc_va;
+       /* Virtual address of Allocated mem for L1 table. May not be aligned */
+       u32 l1_tbl_alloc_sz;
+       /* Size of consistent memory allocated for L1 table.
+        * May not be aligned */
+
+       u32 l2_base_pa;         /* Physical address of the L2 PT */
+       u32 l2_base_va;         /* Virtual  address of the L2 PT */
+       u32 l2_size;            /* Size of the L2 PT */
+       u32 l2_tbl_alloc_pa;
+       /* Physical address of Allocated mem for L2 table. May not be aligned */
+       u32 l2_tbl_alloc_va;
+       /* Virtual address of Allocated mem for L2 table. May not be aligned */
+       u32 l2_tbl_alloc_sz;
+       /* Size of consistent memory allocated for L2 table.
+        * May not be aligned */
+
+       u32 l2_num_pages;       /* Number of allocated L2 PT */
+       /* Array [l2_num_pages] of L2 PT info structs */
+       struct page_info *pg_info;
+};
+
 /*
  *  This Bridge driver's function interface table.
  */
@@ -119,6 +192,8 @@ static struct bridge_drv_interface drv_interface_fxns = {
        bridge_brd_set_state,
        bridge_brd_mem_copy,
        bridge_brd_mem_write,
+       bridge_brd_mem_map,
+       bridge_brd_mem_un_map,
        /* The following CHNL functions are provided by chnl_io.lib: */
        bridge_chnl_create,
        bridge_chnl_destroy,
@@ -148,6 +223,27 @@ static struct bridge_drv_interface drv_interface_fxns = {
        bridge_msg_set_queue_id,
 };
 
+static inline void flush_all(struct bridge_dev_context *dev_context)
+{
+       if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
+           dev_context->dw_brd_state == BRD_HIBERNATION)
+               wake_dsp(dev_context, NULL);
+
+       hw_mmu_tlb_flush_all(dev_context->dw_dsp_mmu_base);
+}
+
+static void bad_page_dump(u32 pa, struct page *pg)
+{
+       pr_emerg("DSPBRIDGE: MAP function: COUNT 0 FOR PA 0x%x\n", pa);
+       pr_emerg("Bad page state in process '%s'\n"
+                "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n"
+                "Backtrace:\n",
+                current->comm, pg, (int)(2 * sizeof(unsigned long)),
+                (unsigned long)pg->flags, pg->mapping,
+                page_mapcount(pg), page_count(pg));
+       dump_stack();
+}
+
 /*
  *  ======== bridge_drv_entry ========
  *  purpose:
@@ -203,7 +299,8 @@ static int bridge_brd_monitor(struct bridge_dev_context *dev_ctxt)
                (*pdata->dsp_cm_write)(OMAP34XX_CLKSTCTRL_DISABLE_AUTO,
                                        OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
        }
-
+       (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
+                                       OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
        dsp_clk_enable(DSP_CLK_IVA2);
 
        /* set the device state to IDLE */
@@ -274,17 +371,14 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
 {
        int status = 0;
        struct bridge_dev_context *dev_context = dev_ctxt;
-       struct iommu *mmu = NULL;
-       struct shm_segs *sm_sg;
-       int l4_i = 0, tlb_i = 0;
-       u32 sg0_da = 0, sg1_da = 0;
-       struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry;
        u32 dw_sync_addr = 0;
        u32 ul_shm_base;        /* Gpp Phys SM base addr(byte) */
        u32 ul_shm_base_virt;   /* Dsp Virt SM base addr */
        u32 ul_tlb_base_virt;   /* Base of MMU TLB entry */
        /* Offset of shm_base_virt from tlb_base_virt */
        u32 ul_shm_offset_virt;
+       s32 entry_ndx;
+       s32 itmp_entry_ndx = 0; /* DSP-MMU TLB entry base address */
        struct cfg_hostres *resources = NULL;
        u32 temp;
        u32 ul_dsp_clk_rate;
@@ -305,12 +399,12 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
        ul_shm_base_virt *= DSPWORDSIZE;
        DBC_ASSERT(ul_shm_base_virt != 0);
        /* DSP Virtual address */
-       ul_tlb_base_virt = dev_context->sh_s.seg0_da;
+       ul_tlb_base_virt = dev_context->atlb_entry[0].ul_dsp_va;
        DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
        ul_shm_offset_virt =
            ul_shm_base_virt - (ul_tlb_base_virt * DSPWORDSIZE);
        /* Kernel logical address */
-       ul_shm_base = dev_context->sh_s.seg0_va + ul_shm_offset_virt;
+       ul_shm_base = dev_context->atlb_entry[0].ul_gpp_va + ul_shm_offset_virt;
 
        DBC_ASSERT(ul_shm_base != 0);
        /* 2nd wd is used as sync field */
@@ -345,83 +439,78 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
                                        OMAP343X_CONTROL_IVA2_BOOTMOD));
                }
        }
-
        if (!status) {
+               /* Reset and Unreset the RST2, so that BOOTADDR is copied to
+                * IVA2 SYSC register */
+               (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
+                       OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+               udelay(100);
                (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK, 0,
                                        OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-               mmu = dev_context->dsp_mmu;
-               if (mmu)
-                       dsp_mmu_exit(mmu);
-               mmu = dsp_mmu_init();
-               if (IS_ERR(mmu)) {
-                       dev_err(bridge, "dsp_mmu_init failed!\n");
-                       dev_context->dsp_mmu = NULL;
-                       status = (int)mmu;
-               }
-       }
-       if (!status) {
-               dev_context->dsp_mmu = mmu;
-               sm_sg = &dev_context->sh_s;
-               sg0_da = iommu_kmap(mmu, sm_sg->seg0_da, sm_sg->seg0_pa,
-                       sm_sg->seg0_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
-               if (IS_ERR_VALUE(sg0_da)) {
-                       status = (int)sg0_da;
-                       sg0_da = 0;
-               }
-       }
-       if (!status) {
-               sg1_da = iommu_kmap(mmu, sm_sg->seg1_da, sm_sg->seg1_pa,
-                       sm_sg->seg1_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
-               if (IS_ERR_VALUE(sg1_da)) {
-                       status = (int)sg1_da;
-                       sg1_da = 0;
-               }
-       }
-       if (!status) {
-               u32 da;
-               for (tlb_i = 0; tlb_i < BRDIOCTL_NUMOFMMUTLB; tlb_i++) {
-                       if (!tlb[tlb_i].ul_gpp_pa)
+               udelay(100);
+
+               /* Disbale the DSP MMU */
+               hw_mmu_disable(resources->dw_dmmu_base);
+               /* Disable TWL */
+               hw_mmu_twl_disable(resources->dw_dmmu_base);
+
+               /* Only make TLB entry if both addresses are non-zero */
+               for (entry_ndx = 0; entry_ndx < BRDIOCTL_NUMOFMMUTLB;
+                    entry_ndx++) {
+                       struct bridge_ioctl_extproc *e = &dev_context->atlb_entry[entry_ndx];
+                       struct hw_mmu_map_attrs_t map_attrs = {
+                               .endianism = e->endianism,
+                               .element_size = e->elem_size,
+                               .mixed_size = e->mixed_mode,
+                       };
+
+                       if (!e->ul_gpp_pa || !e->ul_dsp_va)
                                continue;
 
-                       dev_dbg(bridge, "IOMMU %d GppPa: 0x%x DspVa 0x%x Size"
-                               " 0x%x\n", tlb_i, tlb[tlb_i].ul_gpp_pa,
-                               tlb[tlb_i].ul_dsp_va, tlb[tlb_i].ul_size);
-
-                       da = iommu_kmap(mmu, tlb[tlb_i].ul_dsp_va,
-                               tlb[tlb_i].ul_gpp_pa, PAGE_SIZE,
-                               IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
-                       if (IS_ERR_VALUE(da)) {
-                               status = (int)da;
-                               break;
-                       }
-               }
-       }
-       if (!status) {
-               u32 da;
-               l4_i = 0;
-               while (l4_peripheral_table[l4_i].phys_addr) {
-                       da = iommu_kmap(mmu, l4_peripheral_table[l4_i].
-                               dsp_virt_addr, l4_peripheral_table[l4_i].
-                               phys_addr, PAGE_SIZE,
-                               IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
-                       if (IS_ERR_VALUE(da)) {
-                               status = (int)da;
-                               break;
-                       }
-                       l4_i++;
+                       dev_dbg(bridge,
+                                       "MMU %d, pa: 0x%x, va: 0x%x, size: 0x%x",
+                                       itmp_entry_ndx,
+                                       e->ul_gpp_pa,
+                                       e->ul_dsp_va,
+                                       e->ul_size);
+
+                       hw_mmu_tlb_add(dev_context->dw_dsp_mmu_base,
+                                       e->ul_gpp_pa,
+                                       e->ul_dsp_va,
+                                       e->ul_size,
+                                       itmp_entry_ndx,
+                                       &map_attrs, 1, 1);
+
+                       itmp_entry_ndx++;
                }
        }
 
        /* Lock the above TLB entries and get the BIOS and load monitor timer
         * information */
        if (!status) {
+               hw_mmu_num_locked_set(resources->dw_dmmu_base, itmp_entry_ndx);
+               hw_mmu_victim_num_set(resources->dw_dmmu_base, itmp_entry_ndx);
+               hw_mmu_ttb_set(resources->dw_dmmu_base,
+                              dev_context->pt_attrs->l1_base_pa);
+               hw_mmu_twl_enable(resources->dw_dmmu_base);
+               /* Enable the SmartIdle and AutoIdle bit for MMU_SYSCONFIG */
+
+               temp = __raw_readl((resources->dw_dmmu_base) + 0x10);
+               temp = (temp & 0xFFFFFFEF) | 0x11;
+               __raw_writel(temp, (resources->dw_dmmu_base) + 0x10);
+
+               /* Let the DSP MMU run */
+               hw_mmu_enable(resources->dw_dmmu_base);
+
                /* Enable the BIOS clock */
                (void)dev_get_symbol(dev_context->hdev_obj,
                                     BRIDGEINIT_BIOSGPTIMER, &ul_bios_gp_timer);
                (void)dev_get_symbol(dev_context->hdev_obj,
                                     BRIDGEINIT_LOADMON_GPTIMER,
                                     &ul_load_monitor_timer);
+       }
 
+       if (!status) {
                if (ul_load_monitor_timer != 0xFFFF) {
                        clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) |
                            ul_load_monitor_timer;
@@ -430,7 +519,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
                        dev_dbg(bridge, "Not able to get the symbol for Load "
                                "Monitor Timer\n");
                }
+       }
 
+       if (!status) {
                if (ul_bios_gp_timer != 0xFFFF) {
                        clk_cmd = (BPWR_ENABLE_CLOCK << MBX_PM_CLK_CMDSHIFT) |
                            ul_bios_gp_timer;
@@ -439,7 +530,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
                        dev_dbg(bridge,
                                "Not able to get the symbol for BIOS Timer\n");
                }
+       }
 
+       if (!status) {
                /* Set the DSP clock rate */
                (void)dev_get_symbol(dev_context->hdev_obj,
                                     "_BRIDGEINIT_DSP_FREQ", &ul_dsp_clk_addr);
@@ -492,6 +585,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
 
                /* Let DSP go */
                dev_dbg(bridge, "%s Unreset\n", __func__);
+               /* Enable DSP MMU Interrupts */
+               hw_mmu_event_enable(resources->dw_dmmu_base,
+                                   HW_MMU_ALL_INTERRUPTS);
                /* release the RST1, DSP starts executing now .. */
                (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 0,
                                        OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
@@ -521,23 +617,11 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
 
                        /* update board state */
                        dev_context->dw_brd_state = BRD_RUNNING;
-                       return 0;
+                       /* (void)chnlsm_enable_interrupt(dev_context); */
                } else {
                        dev_context->dw_brd_state = BRD_UNKNOWN;
                }
        }
-
-       while (tlb_i--) {
-               if (!tlb[tlb_i].ul_gpp_pa)
-                       continue;
-               iommu_kunmap(mmu, tlb[tlb_i].ul_gpp_va);
-       }
-       while (l4_i--)
-               iommu_kunmap(mmu, l4_peripheral_table[l4_i].dsp_virt_addr);
-       if (sg0_da)
-               iommu_kunmap(mmu, sg0_da);
-       if (sg1_da)
-               iommu_kunmap(mmu, sg1_da);
        return status;
 }
 
@@ -553,9 +637,8 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
 {
        int status = 0;
        struct bridge_dev_context *dev_context = dev_ctxt;
+       struct pg_table_attrs *pt_attrs;
        u32 dsp_pwr_state;
-       int i;
-       struct bridge_ioctl_extproc *tlb = dev_context->atlb_entry;
        struct omap_dsp_platform_data *pdata =
                omap_dspbridge_dev->dev.platform_data;
 
@@ -591,37 +674,23 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
 
        dsp_wdt_enable(false);
 
-       /* Reset DSP */
-       (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK,
-               OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
-
+       /* This is a good place to clear the MMU page tables as well */
+       if (dev_context->pt_attrs) {
+               pt_attrs = dev_context->pt_attrs;
+               memset((u8 *) pt_attrs->l1_base_va, 0x00, pt_attrs->l1_size);
+               memset((u8 *) pt_attrs->l2_base_va, 0x00, pt_attrs->l2_size);
+               memset((u8 *) pt_attrs->pg_info, 0x00,
+                      (pt_attrs->l2_num_pages * sizeof(struct page_info)));
+       }
        /* Disable the mailbox interrupts */
        if (dev_context->mbox) {
                omap_mbox_disable_irq(dev_context->mbox, IRQ_RX);
                omap_mbox_put(dev_context->mbox);
                dev_context->mbox = NULL;
        }
-       if (dev_context->dsp_mmu) {
-               pr_err("Proc stop mmu if statement\n");
-               for (i = 0; i < BRDIOCTL_NUMOFMMUTLB; i++) {
-                       if (!tlb[i].ul_gpp_pa)
-                               continue;
-                       iommu_kunmap(dev_context->dsp_mmu, tlb[i].ul_gpp_va);
-               }
-               i = 0;
-               while (l4_peripheral_table[i].phys_addr) {
-                       iommu_kunmap(dev_context->dsp_mmu,
-                               l4_peripheral_table[i].dsp_virt_addr);
-                       i++;
-               }
-               iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg0_da);
-               iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg1_da);
-               dsp_mmu_exit(dev_context->dsp_mmu);
-               dev_context->dsp_mmu = NULL;
-       }
-       /* Reset IVA IOMMU*/
-       (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST2_IVA2_MASK,
-               OMAP3430_RST2_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
+       /* Reset IVA2 clocks*/
+       (*pdata->dsp_prm_write)(OMAP3430_RST1_IVA2_MASK | OMAP3430_RST2_IVA2_MASK |
+                       OMAP3430_RST3_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
 
        dsp_clock_disable_all(dev_context->dsp_per_clks);
        dsp_clk_disable(DSP_CLK_IVA2);
@@ -681,6 +750,10 @@ static int bridge_dev_create(struct bridge_dev_context
        struct bridge_dev_context *dev_context = NULL;
        s32 entry_ndx;
        struct cfg_hostres *resources = config_param;
+       struct pg_table_attrs *pt_attrs;
+       u32 pg_tbl_pa;
+       u32 pg_tbl_va;
+       u32 align_size;
        struct drv_data *drv_datap = dev_get_drvdata(bridge);
 
        /* Allocate and initialize a data structure to contain the bridge driver
@@ -711,8 +784,97 @@ static int bridge_dev_create(struct bridge_dev_context
        if (!dev_context->dw_dsp_base_addr)
                status = -EPERM;
 
+       pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL);
+       if (pt_attrs != NULL) {
+               /* Assuming that we use only DSP's memory map
+                * until 0x4000:0000 , we would need only 1024
+                * L1 enties i.e L1 size = 4K */
+               pt_attrs->l1_size = 0x1000;
+               align_size = pt_attrs->l1_size;
+               /* Align sizes are expected to be power of 2 */
+               /* we like to get aligned on L1 table size */
+               pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l1_size,
+                                                    align_size, &pg_tbl_pa);
+
+               /* Check if the PA is aligned for us */
+               if ((pg_tbl_pa) & (align_size - 1)) {
+                       /* PA not aligned to page table size ,
+                        * try with more allocation and align */
+                       mem_free_phys_mem((void *)pg_tbl_va, pg_tbl_pa,
+                                         pt_attrs->l1_size);
+                       /* we like to get aligned on L1 table size */
+                       pg_tbl_va =
+                           (u32) mem_alloc_phys_mem((pt_attrs->l1_size) * 2,
+                                                    align_size, &pg_tbl_pa);
+                       /* We should be able to get aligned table now */
+                       pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa;
+                       pt_attrs->l1_tbl_alloc_va = pg_tbl_va;
+                       pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size * 2;
+                       /* Align the PA to the next 'align'  boundary */
+                       pt_attrs->l1_base_pa =
+                           ((pg_tbl_pa) +
+                            (align_size - 1)) & (~(align_size - 1));
+                       pt_attrs->l1_base_va =
+                           pg_tbl_va + (pt_attrs->l1_base_pa - pg_tbl_pa);
+               } else {
+                       /* We got aligned PA, cool */
+                       pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa;
+                       pt_attrs->l1_tbl_alloc_va = pg_tbl_va;
+                       pt_attrs->l1_tbl_alloc_sz = pt_attrs->l1_size;
+                       pt_attrs->l1_base_pa = pg_tbl_pa;
+                       pt_attrs->l1_base_va = pg_tbl_va;
+               }
+               if (pt_attrs->l1_base_va)
+                       memset((u8 *) pt_attrs->l1_base_va, 0x00,
+                              pt_attrs->l1_size);
+
+               /* number of L2 page tables = DMM pool used + SHMMEM +EXTMEM +
+                * L4 pages */
+               pt_attrs->l2_num_pages = ((DMMPOOLSIZE >> 20) + 6);
+               pt_attrs->l2_size = HW_MMU_COARSE_PAGE_SIZE *
+                   pt_attrs->l2_num_pages;
+               align_size = 4; /* Make it u32 aligned */
+               /* we like to get aligned on L1 table size */
+               pg_tbl_va = (u32) mem_alloc_phys_mem(pt_attrs->l2_size,
+                                                    align_size, &pg_tbl_pa);
+               pt_attrs->l2_tbl_alloc_pa = pg_tbl_pa;
+               pt_attrs->l2_tbl_alloc_va = pg_tbl_va;
+               pt_attrs->l2_tbl_alloc_sz = pt_attrs->l2_size;
+               pt_attrs->l2_base_pa = pg_tbl_pa;
+               pt_attrs->l2_base_va = pg_tbl_va;
+
+               if (pt_attrs->l2_base_va)
+                       memset((u8 *) pt_attrs->l2_base_va, 0x00,
+                              pt_attrs->l2_size);
+
+               pt_attrs->pg_info = kzalloc(pt_attrs->l2_num_pages *
+                                       sizeof(struct page_info), GFP_KERNEL);
+               dev_dbg(bridge,
+                       "L1 pa %x, va %x, size %x\n L2 pa %x, va "
+                       "%x, size %x\n", pt_attrs->l1_base_pa,
+                       pt_attrs->l1_base_va, pt_attrs->l1_size,
+                       pt_attrs->l2_base_pa, pt_attrs->l2_base_va,
+                       pt_attrs->l2_size);
+               dev_dbg(bridge, "pt_attrs %p L2 NumPages %x pg_info %p\n",
+                       pt_attrs, pt_attrs->l2_num_pages, pt_attrs->pg_info);
+       }
+       if ((pt_attrs != NULL) && (pt_attrs->l1_base_va != 0) &&
+           (pt_attrs->l2_base_va != 0) && (pt_attrs->pg_info != NULL))
+               dev_context->pt_attrs = pt_attrs;
+       else
+               status = -ENOMEM;
+
        if (!status) {
+               spin_lock_init(&pt_attrs->pg_lock);
                dev_context->tc_word_swap_on = drv_datap->tc_wordswapon;
+
+               /* Set the Clock Divisor for the DSP module */
+               udelay(5);
+               /* MMU address is obtained from the host
+                * resources struct */
+               dev_context->dw_dsp_mmu_base = resources->dw_dmmu_base;
+       }
+       if (!status) {
                dev_context->hdev_obj = hdev_obj;
                /* Store current board state. */
                dev_context->dw_brd_state = BRD_UNKNOWN;
@@ -722,6 +884,23 @@ static int bridge_dev_create(struct bridge_dev_context
                /* Return ptr to our device state to the DSP API for storage */
                *dev_cntxt = dev_context;
        } else {
+               if (pt_attrs != NULL) {
+                       kfree(pt_attrs->pg_info);
+
+                       if (pt_attrs->l2_tbl_alloc_va) {
+                               mem_free_phys_mem((void *)
+                                                 pt_attrs->l2_tbl_alloc_va,
+                                                 pt_attrs->l2_tbl_alloc_pa,
+                                                 pt_attrs->l2_tbl_alloc_sz);
+                       }
+                       if (pt_attrs->l1_tbl_alloc_va) {
+                               mem_free_phys_mem((void *)
+                                                 pt_attrs->l1_tbl_alloc_va,
+                                                 pt_attrs->l1_tbl_alloc_pa,
+                                                 pt_attrs->l1_tbl_alloc_sz);
+                       }
+               }
+               kfree(pt_attrs);
                kfree(dev_context);
        }
 func_end:
@@ -789,6 +968,7 @@ static int bridge_dev_ctrl(struct bridge_dev_context *dev_context,
  */
 static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
 {
+       struct pg_table_attrs *pt_attrs;
        int status = 0;
        struct bridge_dev_context *dev_context = (struct bridge_dev_context *)
            dev_ctxt;
@@ -802,6 +982,23 @@ static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
 
        /* first put the device to stop state */
        bridge_brd_stop(dev_context);
+       if (dev_context->pt_attrs) {
+               pt_attrs = dev_context->pt_attrs;
+               kfree(pt_attrs->pg_info);
+
+               if (pt_attrs->l2_tbl_alloc_va) {
+                       mem_free_phys_mem((void *)pt_attrs->l2_tbl_alloc_va,
+                                         pt_attrs->l2_tbl_alloc_pa,
+                                         pt_attrs->l2_tbl_alloc_sz);
+               }
+               if (pt_attrs->l1_tbl_alloc_va) {
+                       mem_free_phys_mem((void *)pt_attrs->l1_tbl_alloc_va,
+                                         pt_attrs->l1_tbl_alloc_pa,
+                                         pt_attrs->l1_tbl_alloc_sz);
+               }
+               kfree(pt_attrs);
+
+       }
 
        if (dev_context->resources) {
                host_res = dev_context->resources;
@@ -832,6 +1029,8 @@ static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
                        iounmap((void *)host_res->dw_mem_base[3]);
                if (host_res->dw_mem_base[4])
                        iounmap((void *)host_res->dw_mem_base[4]);
+               if (host_res->dw_dmmu_base)
+                       iounmap(host_res->dw_dmmu_base);
                if (host_res->dw_per_base)
                        iounmap(host_res->dw_per_base);
                if (host_res->dw_per_pm_base)
@@ -845,6 +1044,7 @@ static int bridge_dev_destroy(struct bridge_dev_context *dev_ctxt)
                host_res->dw_mem_base[2] = (u32) NULL;
                host_res->dw_mem_base[3] = (u32) NULL;
                host_res->dw_mem_base[4] = (u32) NULL;
+               host_res->dw_dmmu_base = NULL;
                host_res->dw_sys_ctrl_base = NULL;
 
                kfree(host_res);
@@ -927,6 +1127,673 @@ static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
        return status;
 }
 
+/*
+ *  ======== bridge_brd_mem_map ========
+ *      This function maps MPU buffer to the DSP address space. It performs
+ *  linear to physical address translation if required. It translates each
+ *  page since linear addresses can be physically non-contiguous
+ *  All address & size arguments are assumed to be page aligned (in proc.c)
+ *
+ *  TODO: Disable MMU while updating the page tables (but that'll stall DSP)
+ */
+static int bridge_brd_mem_map(struct bridge_dev_context *dev_ctxt,
+                                 u32 ul_mpu_addr, u32 virt_addr,
+                                 u32 ul_num_bytes, u32 ul_map_attr,
+                                 struct page **mapped_pages)
+{
+       u32 attrs;
+       int status = 0;
+       struct bridge_dev_context *dev_context = dev_ctxt;
+       struct hw_mmu_map_attrs_t hw_attrs;
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = current->mm;
+       u32 write = 0;
+       u32 num_usr_pgs = 0;
+       struct page *mapped_page, *pg;
+       s32 pg_num;
+       u32 va = virt_addr;
+       struct task_struct *curr_task = current;
+       u32 pg_i = 0;
+       u32 mpu_addr, pa;
+
+       dev_dbg(bridge,
+               "%s hDevCtxt %p, pa %x, va %x, size %x, ul_map_attr %x\n",
+               __func__, dev_ctxt, ul_mpu_addr, virt_addr, ul_num_bytes,
+               ul_map_attr);
+       if (ul_num_bytes == 0)
+               return -EINVAL;
+
+       if (ul_map_attr & DSP_MAP_DIR_MASK) {
+               attrs = ul_map_attr;
+       } else {
+               /* Assign default attributes */
+               attrs = ul_map_attr | (DSP_MAPVIRTUALADDR | DSP_MAPELEMSIZE16);
+       }
+       /* Take mapping properties */
+       if (attrs & DSP_MAPBIGENDIAN)
+               hw_attrs.endianism = HW_BIG_ENDIAN;
+       else
+               hw_attrs.endianism = HW_LITTLE_ENDIAN;
+
+       hw_attrs.mixed_size = (enum hw_mmu_mixed_size_t)
+           ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2);
+       /* Ignore element_size if mixed_size is enabled */
+       if (hw_attrs.mixed_size == 0) {
+               if (attrs & DSP_MAPELEMSIZE8) {
+                       /* Size is 8 bit */
+                       hw_attrs.element_size = HW_ELEM_SIZE8BIT;
+               } else if (attrs & DSP_MAPELEMSIZE16) {
+                       /* Size is 16 bit */
+                       hw_attrs.element_size = HW_ELEM_SIZE16BIT;
+               } else if (attrs & DSP_MAPELEMSIZE32) {
+                       /* Size is 32 bit */
+                       hw_attrs.element_size = HW_ELEM_SIZE32BIT;
+               } else if (attrs & DSP_MAPELEMSIZE64) {
+                       /* Size is 64 bit */
+                       hw_attrs.element_size = HW_ELEM_SIZE64BIT;
+               } else {
+                       /*
+                        * Mixedsize isn't enabled, so size can't be
+                        * zero here
+                        */
+                       return -EINVAL;
+               }
+       }
+       if (attrs & DSP_MAPDONOTLOCK)
+               hw_attrs.donotlockmpupage = 1;
+       else
+               hw_attrs.donotlockmpupage = 0;
+
+       if (attrs & DSP_MAPVMALLOCADDR) {
+               return mem_map_vmalloc(dev_ctxt, ul_mpu_addr, virt_addr,
+                                      ul_num_bytes, &hw_attrs);
+       }
+       /*
+        * Do OS-specific user-va to pa translation.
+        * Combine physically contiguous regions to reduce TLBs.
+        * Pass the translated pa to pte_update.
+        */
+       if ((attrs & DSP_MAPPHYSICALADDR)) {
+               status = pte_update(dev_context, ul_mpu_addr, virt_addr,
+                                   ul_num_bytes, &hw_attrs);
+               goto func_cont;
+       }
+
+       /*
+        * Important Note: ul_mpu_addr is mapped from user application process
+        * to current process - it must lie completely within the current
+        * virtual memory address space in order to be of use to us here!
+        */
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, ul_mpu_addr);
+       if (vma)
+               dev_dbg(bridge,
+                       "VMAfor UserBuf: ul_mpu_addr=%x, ul_num_bytes=%x, "
+                       "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n", ul_mpu_addr,
+                       ul_num_bytes, vma->vm_start, vma->vm_end,
+                       vma->vm_flags);
+
+       /*
+        * It is observed that under some circumstances, the user buffer is
+        * spread across several VMAs. So loop through and check if the entire
+        * user buffer is covered
+        */
+       while ((vma) && (ul_mpu_addr + ul_num_bytes > vma->vm_end)) {
+               /* jump to the next VMA region */
+               vma = find_vma(mm, vma->vm_end + 1);
+               dev_dbg(bridge,
+                       "VMA for UserBuf ul_mpu_addr=%x ul_num_bytes=%x, "
+                       "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n", ul_mpu_addr,
+                       ul_num_bytes, vma->vm_start, vma->vm_end,
+                       vma->vm_flags);
+       }
+       if (!vma) {
+               pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
+                      __func__, ul_mpu_addr, ul_num_bytes);
+               status = -EINVAL;
+               up_read(&mm->mmap_sem);
+               goto func_cont;
+       }
+
+       if (vma->vm_flags & VM_IO) {
+               num_usr_pgs = ul_num_bytes / PG_SIZE4K;
+               mpu_addr = ul_mpu_addr;
+
+               /* Get the physical addresses for user buffer */
+               for (pg_i = 0; pg_i < num_usr_pgs; pg_i++) {
+                       pa = user_va2_pa(mm, mpu_addr);
+                       if (!pa) {
+                               status = -EPERM;
+                               pr_err("DSPBRIDGE: VM_IO mapping physical"
+                                      "address is invalid\n");
+                               break;
+                       }
+                       if (pfn_valid(__phys_to_pfn(pa))) {
+                               pg = PHYS_TO_PAGE(pa);
+                               get_page(pg);
+                               if (page_count(pg) < 1) {
+                                       pr_err("Bad page in VM_IO buffer\n");
+                                       bad_page_dump(pa, pg);
+                               }
+                       }
+                       status = pte_set(dev_context->pt_attrs, pa,
+                                        va, HW_PAGE_SIZE4KB, &hw_attrs);
+                       if (status)
+                               break;
+
+                       va += HW_PAGE_SIZE4KB;
+                       mpu_addr += HW_PAGE_SIZE4KB;
+                       pa += HW_PAGE_SIZE4KB;
+               }
+       } else {
+               num_usr_pgs = ul_num_bytes / PG_SIZE4K;
+               if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+                       write = 1;
+
+               for (pg_i = 0; pg_i < num_usr_pgs; pg_i++) {
+                       pg_num = get_user_pages(curr_task, mm, ul_mpu_addr, 1,
+                                               write, 1, &mapped_page, NULL);
+                       if (pg_num > 0) {
+                               if (page_count(mapped_page) < 1) {
+                                       pr_err("Bad page count after doing"
+                                              "get_user_pages on"
+                                              "user buffer\n");
+                                       bad_page_dump(page_to_phys(mapped_page),
+                                                     mapped_page);
+                               }
+                               status = pte_set(dev_context->pt_attrs,
+                                                page_to_phys(mapped_page), va,
+                                                HW_PAGE_SIZE4KB, &hw_attrs);
+                               if (status)
+                                       break;
+
+                               if (mapped_pages)
+                                       mapped_pages[pg_i] = mapped_page;
+
+                               va += HW_PAGE_SIZE4KB;
+                               ul_mpu_addr += HW_PAGE_SIZE4KB;
+                       } else {
+                               pr_err("DSPBRIDGE: get_user_pages FAILED,"
+                                      "MPU addr = 0x%x,"
+                                      "vma->vm_flags = 0x%lx,"
+                                      "get_user_pages Err"
+                                      "Value = %d, Buffer"
+                                      "size=0x%x\n", ul_mpu_addr,
+                                      vma->vm_flags, pg_num, ul_num_bytes);
+                               status = -EPERM;
+                               break;
+                       }
+               }
+       }
+       up_read(&mm->mmap_sem);
+func_cont:
+       if (status) {
+               /*
+                * Roll out the mapped pages incase it failed in middle of
+                * mapping
+                */
+               if (pg_i) {
+                       bridge_brd_mem_un_map(dev_context, virt_addr,
+                                          (pg_i * PG_SIZE4K));
+               }
+               status = -EPERM;
+       }
+       /*
+        * In any case, flush the TLB
+        * This is called from here instead from pte_update to avoid unnecessary
+        * repetition while mapping non-contiguous physical regions of a virtual
+        * region
+        */
+       flush_all(dev_context);
+       dev_dbg(bridge, "%s status %x\n", __func__, status);
+       return status;
+}
+
+/*
+ *  ======== bridge_brd_mem_un_map ========
+ *      Invalidate the PTEs for the DSP VA block to be unmapped.
+ *
+ *      PTEs of a mapped memory block are contiguous in any page table
+ *      So, instead of looking up the PTE address for every 4K block,
+ *      we clear consecutive PTEs until we unmap all the bytes
+ */
+static int bridge_brd_mem_un_map(struct bridge_dev_context *dev_ctxt,
+                                    u32 virt_addr, u32 ul_num_bytes)
+{
+       u32 l1_base_va;
+       u32 l2_base_va;
+       u32 l2_base_pa;
+       u32 l2_page_num;
+       u32 pte_val;
+       u32 pte_size;
+       u32 pte_count;
+       u32 pte_addr_l1;
+       u32 pte_addr_l2 = 0;
+       u32 rem_bytes;
+       u32 rem_bytes_l2;
+       u32 va_curr;
+       struct page *pg = NULL;
+       int status = 0;
+       struct bridge_dev_context *dev_context = dev_ctxt;
+       struct pg_table_attrs *pt = dev_context->pt_attrs;
+       u32 temp;
+       u32 paddr;
+       u32 numof4k_pages = 0;
+
+       va_curr = virt_addr;
+       rem_bytes = ul_num_bytes;
+       rem_bytes_l2 = 0;
+       l1_base_va = pt->l1_base_va;
+       pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va_curr);
+       dev_dbg(bridge, "%s dev_ctxt %p, va %x, NumBytes %x l1_base_va %x, "
+               "pte_addr_l1 %x\n", __func__, dev_ctxt, virt_addr,
+               ul_num_bytes, l1_base_va, pte_addr_l1);
+
+       while (rem_bytes && !status) {
+               u32 va_curr_orig = va_curr;
+               /* Find whether the L1 PTE points to a valid L2 PT */
+               pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va_curr);
+               pte_val = *(u32 *) pte_addr_l1;
+               pte_size = hw_mmu_pte_size_l1(pte_val);
+
+               if (pte_size != HW_MMU_COARSE_PAGE_SIZE)
+                       goto skip_coarse_page;
+
+               /*
+                * Get the L2 PA from the L1 PTE, and find
+                * corresponding L2 VA
+                */
+               l2_base_pa = hw_mmu_pte_coarse_l1(pte_val);
+               l2_base_va = l2_base_pa - pt->l2_base_pa + pt->l2_base_va;
+               l2_page_num =
+                   (l2_base_pa - pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE;
+               /*
+                * Find the L2 PTE address from which we will start
+                * clearing, the number of PTEs to be cleared on this
+                * page, and the size of VA space that needs to be
+                * cleared on this L2 page
+                */
+               pte_addr_l2 = hw_mmu_pte_addr_l2(l2_base_va, va_curr);
+               pte_count = pte_addr_l2 & (HW_MMU_COARSE_PAGE_SIZE - 1);
+               pte_count = (HW_MMU_COARSE_PAGE_SIZE - pte_count) / sizeof(u32);
+               if (rem_bytes < (pte_count * PG_SIZE4K))
+                       pte_count = rem_bytes / PG_SIZE4K;
+               rem_bytes_l2 = pte_count * PG_SIZE4K;
+
+               /*
+                * Unmap the VA space on this L2 PT. A quicker way
+                * would be to clear pte_count entries starting from
+                * pte_addr_l2. However, below code checks that we don't
+                * clear invalid entries or less than 64KB for a 64KB
+                * entry. Similar checking is done for L1 PTEs too
+                * below
+                */
+               while (rem_bytes_l2 && !status) {
+                       pte_val = *(u32 *) pte_addr_l2;
+                       pte_size = hw_mmu_pte_size_l2(pte_val);
+                       /* va_curr aligned to pte_size? */
+                       if (pte_size == 0 || rem_bytes_l2 < pte_size ||
+                           va_curr & (pte_size - 1)) {
+                               status = -EPERM;
+                               break;
+                       }
+
+                       /* Collect Physical addresses from VA */
+                       paddr = (pte_val & ~(pte_size - 1));
+                       if (pte_size == HW_PAGE_SIZE64KB)
+                               numof4k_pages = 16;
+                       else
+                               numof4k_pages = 1;
+                       temp = 0;
+                       while (temp++ < numof4k_pages) {
+                               if (!pfn_valid(__phys_to_pfn(paddr))) {
+                                       paddr += HW_PAGE_SIZE4KB;
+                                       continue;
+                               }
+                               pg = PHYS_TO_PAGE(paddr);
+                               if (page_count(pg) < 1) {
+                                       pr_info("DSPBRIDGE: UNMAP function: "
+                                               "COUNT 0 FOR PA 0x%x, size = "
+                                               "0x%x\n", paddr, ul_num_bytes);
+                                       bad_page_dump(paddr, pg);
+                               } else {
+                                       set_page_dirty(pg);
+                                       page_cache_release(pg);
+                               }
+                               paddr += HW_PAGE_SIZE4KB;
+                       }
+                       if (hw_mmu_pte_clear(pte_addr_l2, va_curr, pte_size)) {
+                               status = -EPERM;
+                               goto EXIT_LOOP;
+                       }
+
+                       status = 0;
+                       rem_bytes_l2 -= pte_size;
+                       va_curr += pte_size;
+                       pte_addr_l2 += (pte_size >> 12) * sizeof(u32);
+               }
+               spin_lock(&pt->pg_lock);
+               if (rem_bytes_l2 == 0) {
+                       pt->pg_info[l2_page_num].num_entries -= pte_count;
+                       if (pt->pg_info[l2_page_num].num_entries == 0) {
+                               /*
+                                * Clear the L1 PTE pointing to the L2 PT
+                                */
+                               if (!hw_mmu_pte_clear(l1_base_va, va_curr_orig,
+                                                    HW_MMU_COARSE_PAGE_SIZE))
+                                       status = 0;
+                               else {
+                                       status = -EPERM;
+                                       spin_unlock(&pt->pg_lock);
+                                       goto EXIT_LOOP;
+                               }
+                       }
+                       rem_bytes -= pte_count * PG_SIZE4K;
+               } else
+                       status = -EPERM;
+
+               spin_unlock(&pt->pg_lock);
+               continue;
+skip_coarse_page:
+               /* va_curr aligned to pte_size? */
+               /* pte_size = 1 MB or 16 MB */
+               if (pte_size == 0 || rem_bytes < pte_size ||
+                   va_curr & (pte_size - 1)) {
+                       status = -EPERM;
+                       break;
+               }
+
+               if (pte_size == HW_PAGE_SIZE1MB)
+                       numof4k_pages = 256;
+               else
+                       numof4k_pages = 4096;
+               temp = 0;
+               /* Collect Physical addresses from VA */
+               paddr = (pte_val & ~(pte_size - 1));
+               while (temp++ < numof4k_pages) {
+                       if (pfn_valid(__phys_to_pfn(paddr))) {
+                               pg = PHYS_TO_PAGE(paddr);
+                               if (page_count(pg) < 1) {
+                                       pr_info("DSPBRIDGE: UNMAP function: "
+                                               "COUNT 0 FOR PA 0x%x, size = "
+                                               "0x%x\n", paddr, ul_num_bytes);
+                                       bad_page_dump(paddr, pg);
+                               } else {
+                                       set_page_dirty(pg);
+                                       page_cache_release(pg);
+                               }
+                       }
+                       paddr += HW_PAGE_SIZE4KB;
+               }
+               if (!hw_mmu_pte_clear(l1_base_va, va_curr, pte_size)) {
+                       status = 0;
+                       rem_bytes -= pte_size;
+                       va_curr += pte_size;
+               } else {
+                       status = -EPERM;
+                       goto EXIT_LOOP;
+               }
+       }
+       /*
+        * It is better to flush the TLB here, so that any stale old entries
+        * get flushed
+        */
+EXIT_LOOP:
+       flush_all(dev_context);
+       dev_dbg(bridge,
+               "%s: va_curr %x, pte_addr_l1 %x pte_addr_l2 %x rem_bytes %x,"
+               " rem_bytes_l2 %x status %x\n", __func__, va_curr, pte_addr_l1,
+               pte_addr_l2, rem_bytes, rem_bytes_l2, status);
+       return status;
+}
+
+/*
+ *  ======== user_va2_pa ========
+ *  Purpose:
+ *      This function walks through the page tables to convert a userland
+ *      virtual address to physical address
+ */
+static u32 user_va2_pa(struct mm_struct *mm, u32 address)
+{
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+
+       pgd = pgd_offset(mm, address);
+       if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
+               pmd = pmd_offset(pgd, address);
+               if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
+                       ptep = pte_offset_map(pmd, address);
+                       if (ptep) {
+                               pte = *ptep;
+                               if (pte_present(pte))
+                                       return pte & PAGE_MASK;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *  ======== pte_update ========
+ *      This function calculates the optimum page-aligned addresses and sizes
+ *      Caller must pass page-aligned values
+ */
+static int pte_update(struct bridge_dev_context *dev_ctxt, u32 pa,
+                            u32 va, u32 size,
+                            struct hw_mmu_map_attrs_t *map_attrs)
+{
+       u32 i;
+       u32 all_bits;
+       u32 pa_curr = pa;
+       u32 va_curr = va;
+       u32 num_bytes = size;
+       struct bridge_dev_context *dev_context = dev_ctxt;
+       int status = 0;
+       u32 page_size[] = { HW_PAGE_SIZE16MB, HW_PAGE_SIZE1MB,
+               HW_PAGE_SIZE64KB, HW_PAGE_SIZE4KB
+       };
+
+       while (num_bytes && !status) {
+               /* To find the max. page size with which both PA & VA are
+                * aligned */
+               all_bits = pa_curr | va_curr;
+
+               for (i = 0; i < 4; i++) {
+                       if ((num_bytes >= page_size[i]) && ((all_bits &
+                                                            (page_size[i] -
+                                                             1)) == 0)) {
+                               status =
+                                   pte_set(dev_context->pt_attrs, pa_curr,
+                                           va_curr, page_size[i], map_attrs);
+                               pa_curr += page_size[i];
+                               va_curr += page_size[i];
+                               num_bytes -= page_size[i];
+                               /* Don't try smaller sizes. Hopefully we have
+                                * reached an address aligned to a bigger page
+                                * size */
+                               break;
+                       }
+               }
+       }
+
+       return status;
+}
+
+/*
+ *  ======== pte_set ========
+ *      This function calculates PTE address (MPU virtual) to be updated
+ *      It also manages the L2 page tables
+ */
+static int pte_set(struct pg_table_attrs *pt, u32 pa, u32 va,
+                         u32 size, struct hw_mmu_map_attrs_t *attrs)
+{
+       u32 i;
+       u32 pte_val;
+       u32 pte_addr_l1;
+       u32 pte_size;
+       /* Base address of the PT that will be updated */
+       u32 pg_tbl_va;
+       u32 l1_base_va;
+       /* Compiler warns that the next three variables might be used
+        * uninitialized in this function. Doesn't seem so. Working around,
+        * anyways. */
+       u32 l2_base_va = 0;
+       u32 l2_base_pa = 0;
+       u32 l2_page_num = 0;
+       int status = 0;
+
+       l1_base_va = pt->l1_base_va;
+       pg_tbl_va = l1_base_va;
+       if ((size == HW_PAGE_SIZE64KB) || (size == HW_PAGE_SIZE4KB)) {
+               /* Find whether the L1 PTE points to a valid L2 PT */
+               pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va);
+               if (pte_addr_l1 <= (pt->l1_base_va + pt->l1_size)) {
+                       pte_val = *(u32 *) pte_addr_l1;
+                       pte_size = hw_mmu_pte_size_l1(pte_val);
+               } else {
+                       return -EPERM;
+               }
+               spin_lock(&pt->pg_lock);
+               if (pte_size == HW_MMU_COARSE_PAGE_SIZE) {
+                       /* Get the L2 PA from the L1 PTE, and find
+                        * corresponding L2 VA */
+                       l2_base_pa = hw_mmu_pte_coarse_l1(pte_val);
+                       l2_base_va =
+                           l2_base_pa - pt->l2_base_pa + pt->l2_base_va;
+                       l2_page_num =
+                           (l2_base_pa -
+                            pt->l2_base_pa) / HW_MMU_COARSE_PAGE_SIZE;
+               } else if (pte_size == 0) {
+                       /* L1 PTE is invalid. Allocate a L2 PT and
+                        * point the L1 PTE to it */
+                       /* Find a free L2 PT. */
+                       for (i = 0; (i < pt->l2_num_pages) &&
+                            (pt->pg_info[i].num_entries != 0); i++)
+                               ;;
+                       if (i < pt->l2_num_pages) {
+                               l2_page_num = i;
+                               l2_base_pa = pt->l2_base_pa + (l2_page_num *
+                                               HW_MMU_COARSE_PAGE_SIZE);
+                               l2_base_va = pt->l2_base_va + (l2_page_num *
+                                               HW_MMU_COARSE_PAGE_SIZE);
+                               /* Endianness attributes are ignored for
+                                * HW_MMU_COARSE_PAGE_SIZE */
+                               status =
+                                   hw_mmu_pte_set(l1_base_va, l2_base_pa, va,
+                                                  HW_MMU_COARSE_PAGE_SIZE,
+                                                  attrs);
+                       } else {
+                               status = -ENOMEM;
+                       }
+               } else {
+                       /* Found valid L1 PTE of another size.
+                        * Should not overwrite it. */
+                       status = -EPERM;
+               }
+               if (!status) {
+                       pg_tbl_va = l2_base_va;
+                       if (size == HW_PAGE_SIZE64KB)
+                               pt->pg_info[l2_page_num].num_entries += 16;
+                       else
+                               pt->pg_info[l2_page_num].num_entries++;
+                       dev_dbg(bridge, "PTE: L2 BaseVa %x, BasePa %x, PageNum "
+                               "%x, num_entries %x\n", l2_base_va,
+                               l2_base_pa, l2_page_num,
+                               pt->pg_info[l2_page_num].num_entries);
+               }
+               spin_unlock(&pt->pg_lock);
+       }
+       if (!status) {
+               dev_dbg(bridge, "PTE: pg_tbl_va %x, pa %x, va %x, size %x\n",
+                       pg_tbl_va, pa, va, size);
+               dev_dbg(bridge, "PTE: endianism %x, element_size %x, "
+                       "mixed_size %x\n", attrs->endianism,
+                       attrs->element_size, attrs->mixed_size);
+               status = hw_mmu_pte_set(pg_tbl_va, pa, va, size, attrs);
+       }
+
+       return status;
+}
+
+/* Memory map kernel VA -- memory allocated with vmalloc */
+static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
+                                 u32 ul_mpu_addr, u32 virt_addr,
+                                 u32 ul_num_bytes,
+                                 struct hw_mmu_map_attrs_t *hw_attrs)
+{
+       int status = 0;
+       struct page *page[1];
+       u32 i;
+       u32 pa_curr;
+       u32 pa_next;
+       u32 va_curr;
+       u32 size_curr;
+       u32 num_pages;
+       u32 pa;
+       u32 num_of4k_pages;
+       u32 temp = 0;
+
+       /*
+        * Do Kernel va to pa translation.
+        * Combine physically contiguous regions to reduce TLBs.
+        * Pass the translated pa to pte_update.
+        */
+       num_pages = ul_num_bytes / PAGE_SIZE;   /* PAGE_SIZE = OS page size */
+       i = 0;
+       va_curr = ul_mpu_addr;
+       page[0] = vmalloc_to_page((void *)va_curr);
+       pa_next = page_to_phys(page[0]);
+       while (!status && (i < num_pages)) {
+               /*
+                * Reuse pa_next from the previous iteraion to avoid
+                * an extra va2pa call
+                */
+               pa_curr = pa_next;
+               size_curr = PAGE_SIZE;
+               /*
+                * If the next page is physically contiguous,
+                * map it with the current one by increasing
+                * the size of the region to be mapped
+                */
+               while (++i < num_pages) {
+                       page[0] =
+                           vmalloc_to_page((void *)(va_curr + size_curr));
+                       pa_next = page_to_phys(page[0]);
+
+                       if (pa_next == (pa_curr + size_curr))
+                               size_curr += PAGE_SIZE;
+                       else
+                               break;
+
+               }
+               if (pa_next == 0) {
+                       status = -ENOMEM;
+                       break;
+               }
+               pa = pa_curr;
+               num_of4k_pages = size_curr / HW_PAGE_SIZE4KB;
+               while (temp++ < num_of4k_pages) {
+                       get_page(PHYS_TO_PAGE(pa));
+                       pa += HW_PAGE_SIZE4KB;
+               }
+               status = pte_update(dev_context, pa_curr, virt_addr +
+                                   (va_curr - ul_mpu_addr), size_curr,
+                                   hw_attrs);
+               va_curr += size_curr;
+       }
+       /*
+        * In any case, flush the TLB
+        * This is called from here instead from pte_update to avoid unnecessary
+        * repetition while mapping non-contiguous physical regions of a virtual
+        * region
+        */
+       flush_all(dev_context);
+       dev_dbg(bridge, "%s status %x\n", __func__, status);
+       return status;
+}
+
 /*
  *  ======== wait_for_start ========
  *      Wait for the singal from DSP that it has started, or time out.
index b57a9fd5e757d98dac71c2f1de68dbd12dfaebd7..fb9026e1403c0d29f8e624681217d5286fc33d51 100644 (file)
 #include <dspbridge/dev.h>
 #include <dspbridge/iodefs.h>
 
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
 #include <dspbridge/pwr_sh.h>
 
 /*  ----------------------------------- Bridge Driver */
index 66dbf02549e40caef9b046335773679a2abb6577..ba2961049dad720d5f26cbb4cdb9b5cb6bb2952f 100644 (file)
@@ -134,16 +134,17 @@ int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
 
                if (!status) {
                        ul_tlb_base_virt =
-                           dev_context->sh_s.seg0_da * DSPWORDSIZE;
+                           dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
                        DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
-                       dw_ext_prog_virt_mem = dev_context->sh_s.seg0_va;
+                       dw_ext_prog_virt_mem =
+                           dev_context->atlb_entry[0].ul_gpp_va;
 
                        if (!trace_read) {
                                ul_shm_offset_virt =
                                    ul_shm_base_virt - ul_tlb_base_virt;
                                ul_shm_offset_virt +=
                                    PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base +
-                                                 1, PAGE_SIZE * 16);
+                                                 1, HW_PAGE_SIZE64KB);
                                dw_ext_prog_virt_mem -= ul_shm_offset_virt;
                                dw_ext_prog_virt_mem +=
                                    (ul_ext_base - ul_dyn_ext_base);
@@ -317,9 +318,8 @@ int write_ext_dsp_data(struct bridge_dev_context *dev_context,
                        ret = -EPERM;
 
                if (!ret) {
-                       ul_tlb_base_virt = dev_context->sh_s.seg0_da *
-                                                               DSPWORDSIZE;
-
+                       ul_tlb_base_virt =
+                           dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
                        DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
 
                        if (symbols_reloaded) {
@@ -337,7 +337,7 @@ int write_ext_dsp_data(struct bridge_dev_context *dev_context,
                            ul_shm_base_virt - ul_tlb_base_virt;
                        if (trace_load) {
                                dw_ext_prog_virt_mem =
-                                       dev_context->sh_s.seg0_va;
+                                   dev_context->atlb_entry[0].ul_gpp_va;
                        } else {
                                dw_ext_prog_virt_mem = host_res->dw_mem_base[1];
                                dw_ext_prog_virt_mem +=
@@ -393,6 +393,7 @@ int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
                omap_dspbridge_dev->dev.platform_data;
        struct cfg_hostres *resources = dev_context->resources;
        int status = 0;
+       u32 temp;
 
        if (!dev_context->mbox)
                return 0;
@@ -436,7 +437,7 @@ int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
                omap_mbox_restore_ctx(dev_context->mbox);
 
                /* Access MMU SYS CONFIG register to generate a short wakeup */
-               iommu_read_reg(dev_context->dsp_mmu, MMU_SYSCONFIG);
+               temp = readl(resources->dw_dmmu_base + 0x10);
 
                dev_context->dw_brd_state = BRD_RUNNING;
        } else if (dev_context->dw_brd_state == BRD_RETENTION) {
index e24ea0c7391491cef345e464cca0fde7dd944e92..3430418190da8fa62ad31c09843362b2c40edda1 100644 (file)
 #include <dspbridge/drv.h>
 #include <dspbridge/wdt.h>
 
+static u32 fault_addr;
+
+static void mmu_fault_dpc(unsigned long data)
+{
+       struct deh_mgr *deh = (void *)data;
+
+       if (!deh)
+               return;
+
+       bridge_deh_notify(deh, DSP_MMUFAULT, 0);
+}
+
+static irqreturn_t mmu_fault_isr(int irq, void *data)
+{
+       struct deh_mgr *deh = data;
+       struct cfg_hostres *resources;
+       u32 event;
+
+       if (!deh)
+               return IRQ_HANDLED;
+
+       resources = deh->hbridge_context->resources;
+       if (!resources) {
+               dev_dbg(bridge, "%s: Failed to get Host Resources\n",
+                               __func__);
+               return IRQ_HANDLED;
+       }
+
+       hw_mmu_event_status(resources->dw_dmmu_base, &event);
+       if (event == HW_MMU_TRANSLATION_FAULT) {
+               hw_mmu_fault_addr_read(resources->dw_dmmu_base, &fault_addr);
+               dev_dbg(bridge, "%s: event=0x%x, fault_addr=0x%x\n", __func__,
+                               event, fault_addr);
+               /*
+                * Schedule a DPC directly. In the future, it may be
+                * necessary to check if DSP MMU fault is intended for
+                * Bridge.
+                */
+               tasklet_schedule(&deh->dpc_tasklet);
+
+               /* Disable the MMU events, else once we clear it will
+                * start to raise INTs again */
+               hw_mmu_event_disable(resources->dw_dmmu_base,
+                               HW_MMU_TRANSLATION_FAULT);
+       } else {
+               hw_mmu_event_disable(resources->dw_dmmu_base,
+                               HW_MMU_ALL_INTERRUPTS);
+       }
+       return IRQ_HANDLED;
+}
+
 int bridge_deh_create(struct deh_mgr **ret_deh,
                struct dev_object *hdev_obj)
 {
@@ -58,9 +109,18 @@ int bridge_deh_create(struct deh_mgr **ret_deh,
        }
        ntfy_init(deh->ntfy_obj);
 
+       /* Create a MMUfault DPC */
+       tasklet_init(&deh->dpc_tasklet, mmu_fault_dpc, (u32) deh);
+
        /* Fill in context structure */
        deh->hbridge_context = hbridge_context;
 
+       /* Install ISR function for DSP MMU fault */
+       status = request_irq(INT_DSP_MMU_IRQ, mmu_fault_isr, 0,
+                       "DspBridge\tiommu fault", deh);
+       if (status < 0)
+               goto err;
+
        *ret_deh = deh;
        return 0;
 
@@ -80,6 +140,11 @@ int bridge_deh_destroy(struct deh_mgr *deh)
                ntfy_delete(deh->ntfy_obj);
                kfree(deh->ntfy_obj);
        }
+       /* Disable DSP MMU fault */
+       free_irq(INT_DSP_MMU_IRQ, deh);
+
+       /* Free DPC object */
+       tasklet_kill(&deh->dpc_tasklet);
 
        /* Deallocate the DEH manager object */
        kfree(deh);
@@ -101,6 +166,48 @@ int bridge_deh_register_notify(struct deh_mgr *deh, u32 event_mask,
                return ntfy_unregister(deh->ntfy_obj, hnotification);
 }
 
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
+{
+       struct cfg_hostres *resources;
+       struct hw_mmu_map_attrs_t map_attrs = {
+               .endianism = HW_LITTLE_ENDIAN,
+               .element_size = HW_ELEM_SIZE16BIT,
+               .mixed_size = HW_MMU_CPUES,
+       };
+       void *dummy_va_addr;
+
+       resources = dev_context->resources;
+       dummy_va_addr = (void*)__get_free_page(GFP_ATOMIC);
+
+       /*
+        * Before acking the MMU fault, let's make sure MMU can only
+        * access entry #0. Then add a new entry so that the DSP OS
+        * can continue in order to dump the stack.
+        */
+       hw_mmu_twl_disable(resources->dw_dmmu_base);
+       hw_mmu_tlb_flush_all(resources->dw_dmmu_base);
+
+       hw_mmu_tlb_add(resources->dw_dmmu_base,
+                       virt_to_phys(dummy_va_addr), fault_addr,
+                       HW_PAGE_SIZE4KB, 1,
+                       &map_attrs, HW_SET, HW_SET);
+
+       dsp_clk_enable(DSP_CLK_GPT8);
+
+       dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
+
+       /* Clear MMU interrupt */
+       hw_mmu_event_ack(resources->dw_dmmu_base,
+                       HW_MMU_TRANSLATION_FAULT);
+       dump_dsp_stack(dev_context);
+       dsp_clk_disable(DSP_CLK_GPT8);
+
+       hw_mmu_disable(resources->dw_dmmu_base);
+       free_page((unsigned long)dummy_va_addr);
+}
+#endif
+
 static inline const char *event_to_string(int event)
 {
        switch (event) {
@@ -133,7 +240,13 @@ void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
 #endif
                break;
        case DSP_MMUFAULT:
-               dev_err(bridge, "%s: %s, addr=0x%x", __func__, str, info);
+               dev_err(bridge, "%s: %s, addr=0x%x", __func__,
+                               str, fault_addr);
+#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
+               print_dsp_trace_buffer(dev_context);
+               dump_dl_modules(dev_context);
+               mmu_fault_print_stack(dev_context);
+#endif
                break;
        default:
                dev_err(bridge, "%s: %s", __func__, str);
diff --git a/drivers/staging/tidspbridge/hw/EasiGlobal.h b/drivers/staging/tidspbridge/hw/EasiGlobal.h
new file mode 100644 (file)
index 0000000..e48d7f6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * EasiGlobal.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _EASIGLOBAL_H
+#define _EASIGLOBAL_H
+#include <linux/types.h>
+
+/*
+ * DEFINE:        READ_ONLY, WRITE_ONLY &  READ_WRITE
+ *
+ * DESCRIPTION: Defines used to describe register types for EASI-checker tests.
+ */
+
+#define READ_ONLY    1
+#define WRITE_ONLY   2
+#define READ_WRITE   3
+
+/*
+ * MACRO:        _DEBUG_LEVEL1_EASI
+ *
+ * DESCRIPTION:  A MACRO which can be used to indicate that a particular beach
+ *               register access function was called.
+ *
+ * NOTE:         We currently dont use this functionality.
+ */
+#define _DEBUG_LEVEL1_EASI(easi_num)     ((void)0)
+
+#endif /* _EASIGLOBAL_H */
diff --git a/drivers/staging/tidspbridge/hw/MMUAccInt.h b/drivers/staging/tidspbridge/hw/MMUAccInt.h
new file mode 100644 (file)
index 0000000..1cefca3
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * MMUAccInt.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MMU_ACC_INT_H
+#define _MMU_ACC_INT_H
+
+/* Mappings of level 1 EASI function numbers to function names */
+
+#define EASIL1_MMUMMU_SYSCONFIG_READ_REGISTER32 (MMU_BASE_EASIL1 + 3)
+#define EASIL1_MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32  (MMU_BASE_EASIL1 + 17)
+#define EASIL1_MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32    (MMU_BASE_EASIL1 + 39)
+#define EASIL1_MMUMMU_IRQSTATUS_WRITE_REGISTER32   (MMU_BASE_EASIL1 + 51)
+#define EASIL1_MMUMMU_IRQENABLE_READ_REGISTER32 (MMU_BASE_EASIL1 + 102)
+#define EASIL1_MMUMMU_IRQENABLE_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 103)
+#define EASIL1_MMUMMU_WALKING_STTWL_RUNNING_READ32 (MMU_BASE_EASIL1 + 156)
+#define EASIL1_MMUMMU_CNTLTWL_ENABLE_READ32 (MMU_BASE_EASIL1 + 174)
+#define EASIL1_MMUMMU_CNTLTWL_ENABLE_WRITE32   (MMU_BASE_EASIL1 + 180)
+#define EASIL1_MMUMMU_CNTLMMU_ENABLE_WRITE32     (MMU_BASE_EASIL1 + 190)
+#define EASIL1_MMUMMU_FAULT_AD_READ_REGISTER32   (MMU_BASE_EASIL1 + 194)
+#define EASIL1_MMUMMU_TTB_WRITE_REGISTER32  (MMU_BASE_EASIL1 + 198)
+#define EASIL1_MMUMMU_LOCK_READ_REGISTER32   (MMU_BASE_EASIL1 + 203)
+#define EASIL1_MMUMMU_LOCK_WRITE_REGISTER32  (MMU_BASE_EASIL1 + 204)
+#define EASIL1_MMUMMU_LOCK_BASE_VALUE_READ32  (MMU_BASE_EASIL1 + 205)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_READ32 (MMU_BASE_EASIL1 + 209)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_WRITE32 (MMU_BASE_EASIL1 + 211)
+#define EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_SET32  (MMU_BASE_EASIL1 + 212)
+#define EASIL1_MMUMMU_LD_TLB_READ_REGISTER32    (MMU_BASE_EASIL1 + 213)
+#define EASIL1_MMUMMU_LD_TLB_WRITE_REGISTER32   (MMU_BASE_EASIL1 + 214)
+#define EASIL1_MMUMMU_CAM_WRITE_REGISTER32   (MMU_BASE_EASIL1 + 226)
+#define EASIL1_MMUMMU_RAM_WRITE_REGISTER32 (MMU_BASE_EASIL1 + 268)
+#define EASIL1_MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32  (MMU_BASE_EASIL1 + 322)
+
+/* Register offset address definitions */
+#define MMU_MMU_SYSCONFIG_OFFSET   0x10
+#define MMU_MMU_IRQSTATUS_OFFSET  0x18
+#define MMU_MMU_IRQENABLE_OFFSET    0x1c
+#define MMU_MMU_WALKING_ST_OFFSET 0x40
+#define MMU_MMU_CNTL_OFFSET   0x44
+#define MMU_MMU_FAULT_AD_OFFSET  0x48
+#define MMU_MMU_TTB_OFFSET  0x4c
+#define MMU_MMU_LOCK_OFFSET   0x50
+#define MMU_MMU_LD_TLB_OFFSET  0x54
+#define MMU_MMU_CAM_OFFSET   0x58
+#define MMU_MMU_RAM_OFFSET   0x5c
+#define MMU_MMU_GFLUSH_OFFSET  0x60
+#define MMU_MMU_FLUSH_ENTRY_OFFSET  0x64
+/* Bitfield mask and offset declarations */
+#define MMU_MMU_SYSCONFIG_IDLE_MODE_MASK  0x18
+#define MMU_MMU_SYSCONFIG_IDLE_MODE_OFFSET  3
+#define MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK  0x1
+#define MMU_MMU_SYSCONFIG_AUTO_IDLE_OFFSET   0
+#define MMU_MMU_WALKING_ST_TWL_RUNNING_MASK 0x1
+#define MMU_MMU_WALKING_ST_TWL_RUNNING_OFFSET  0
+#define MMU_MMU_CNTL_TWL_ENABLE_MASK 0x4
+#define MMU_MMU_CNTL_TWL_ENABLE_OFFSET 2
+#define MMU_MMU_CNTL_MMU_ENABLE_MASK    0x2
+#define MMU_MMU_CNTL_MMU_ENABLE_OFFSET   1
+#define MMU_MMU_LOCK_BASE_VALUE_MASK 0xfc00
+#define MMU_MMU_LOCK_BASE_VALUE_OFFSET   10
+#define MMU_MMU_LOCK_CURRENT_VICTIM_MASK   0x3f0
+#define MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET    4
+
+#endif /* _MMU_ACC_INT_H */
diff --git a/drivers/staging/tidspbridge/hw/MMURegAcM.h b/drivers/staging/tidspbridge/hw/MMURegAcM.h
new file mode 100644 (file)
index 0000000..ab1a16d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * MMURegAcM.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _MMU_REG_ACM_H
+#define _MMU_REG_ACM_H
+
+#include <linux/io.h>
+#include <EasiGlobal.h>
+
+#include "MMUAccInt.h"
+
+#if defined(USE_LEVEL_1_MACROS)
+
+#define MMUMMU_SYSCONFIG_READ_REGISTER32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_READ_REGISTER32),\
+      __raw_readl((base_address)+MMU_MMU_SYSCONFIG_OFFSET))
+
+#define MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\
+    register u32 data = __raw_readl((base_address)+offset);\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_IDLE_MODE_WRITE32);\
+    data &= ~(MMU_MMU_SYSCONFIG_IDLE_MODE_MASK);\
+    new_value <<= MMU_MMU_SYSCONFIG_IDLE_MODE_OFFSET;\
+    new_value &= MMU_MMU_SYSCONFIG_IDLE_MODE_MASK;\
+    new_value |= data;\
+    __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\
+    register u32 data = __raw_readl((base_address)+offset);\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_SYSCONFIG_AUTO_IDLE_WRITE32);\
+    data &= ~(MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK);\
+    new_value <<= MMU_MMU_SYSCONFIG_AUTO_IDLE_OFFSET;\
+    new_value &= MMU_MMU_SYSCONFIG_AUTO_IDLE_MASK;\
+    new_value |= data;\
+    __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_IRQSTATUS_READ_REGISTER32(base_address)\
+    (_DEBUG_LEVEL1_EASI(easil1_mmummu_irqstatus_read_register32),\
+      __raw_readl((base_address)+MMU_MMU_IRQSTATUS_OFFSET))
+
+#define MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_IRQSTATUS_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQSTATUS_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_IRQENABLE_READ_REGISTER32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQENABLE_READ_REGISTER32),\
+      __raw_readl((base_address)+MMU_MMU_IRQENABLE_OFFSET))
+
+#define MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_IRQENABLE_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_IRQENABLE_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_WALKING_STTWL_RUNNING_READ32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_WALKING_STTWL_RUNNING_READ32),\
+      (((__raw_readl(((base_address)+(MMU_MMU_WALKING_ST_OFFSET))))\
+      & MMU_MMU_WALKING_ST_TWL_RUNNING_MASK) >>\
+      MMU_MMU_WALKING_ST_TWL_RUNNING_OFFSET))
+
+#define MMUMMU_CNTLTWL_ENABLE_READ32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLTWL_ENABLE_READ32),\
+      (((__raw_readl(((base_address)+(MMU_MMU_CNTL_OFFSET)))) &\
+      MMU_MMU_CNTL_TWL_ENABLE_MASK) >>\
+      MMU_MMU_CNTL_TWL_ENABLE_OFFSET))
+
+#define MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_CNTL_OFFSET;\
+    register u32 data = __raw_readl((base_address)+offset);\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLTWL_ENABLE_WRITE32);\
+    data &= ~(MMU_MMU_CNTL_TWL_ENABLE_MASK);\
+    new_value <<= MMU_MMU_CNTL_TWL_ENABLE_OFFSET;\
+    new_value &= MMU_MMU_CNTL_TWL_ENABLE_MASK;\
+    new_value |= data;\
+    __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_CNTL_OFFSET;\
+    register u32 data = __raw_readl((base_address)+offset);\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CNTLMMU_ENABLE_WRITE32);\
+    data &= ~(MMU_MMU_CNTL_MMU_ENABLE_MASK);\
+    new_value <<= MMU_MMU_CNTL_MMU_ENABLE_OFFSET;\
+    new_value &= MMU_MMU_CNTL_MMU_ENABLE_MASK;\
+    new_value |= data;\
+    __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_FAULT_AD_READ_REGISTER32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_FAULT_AD_READ_REGISTER32),\
+      __raw_readl((base_address)+MMU_MMU_FAULT_AD_OFFSET))
+
+#define MMUMMU_TTB_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_TTB_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_TTB_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_LOCK_READ_REGISTER32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_READ_REGISTER32),\
+      __raw_readl((base_address)+MMU_MMU_LOCK_OFFSET))
+
+#define MMUMMU_LOCK_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_LOCK_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_LOCK_BASE_VALUE_READ32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_BASE_VALUE_READ32),\
+      (((__raw_readl(((base_address)+(MMU_MMU_LOCK_OFFSET)))) &\
+      MMU_MMU_LOCK_BASE_VALUE_MASK) >>\
+      MMU_MMU_LOCK_BASE_VALUE_OFFSET))
+
+#define MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_LOCK_OFFSET;\
+    register u32 data = __raw_readl((base_address)+offset);\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(easil1_mmummu_lock_base_value_write32);\
+    data &= ~(MMU_MMU_LOCK_BASE_VALUE_MASK);\
+    new_value <<= MMU_MMU_LOCK_BASE_VALUE_OFFSET;\
+    new_value &= MMU_MMU_LOCK_BASE_VALUE_MASK;\
+    new_value |= data;\
+    __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_READ32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_READ32),\
+      (((__raw_readl(((base_address)+(MMU_MMU_LOCK_OFFSET)))) &\
+      MMU_MMU_LOCK_CURRENT_VICTIM_MASK) >>\
+      MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET))
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_LOCK_OFFSET;\
+    register u32 data = __raw_readl((base_address)+offset);\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_WRITE32);\
+    data &= ~(MMU_MMU_LOCK_CURRENT_VICTIM_MASK);\
+    new_value <<= MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET;\
+    new_value &= MMU_MMU_LOCK_CURRENT_VICTIM_MASK;\
+    new_value |= data;\
+    __raw_writel(new_value, base_address+offset);\
+}
+
+#define MMUMMU_LOCK_CURRENT_VICTIM_SET32(var, value)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LOCK_CURRENT_VICTIM_SET32),\
+      (((var) & ~(MMU_MMU_LOCK_CURRENT_VICTIM_MASK)) |\
+      (((value) << MMU_MMU_LOCK_CURRENT_VICTIM_OFFSET) &\
+      MMU_MMU_LOCK_CURRENT_VICTIM_MASK)))
+
+#define MMUMMU_LD_TLB_READ_REGISTER32(base_address)\
+    (_DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LD_TLB_READ_REGISTER32),\
+      __raw_readl((base_address)+MMU_MMU_LD_TLB_OFFSET))
+
+#define MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_LD_TLB_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_LD_TLB_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_CAM_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_CAM_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_CAM_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_RAM_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_RAM_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_RAM_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#define MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, value)\
+{\
+    const u32 offset = MMU_MMU_FLUSH_ENTRY_OFFSET;\
+    register u32 new_value = (value);\
+    _DEBUG_LEVEL1_EASI(EASIL1_MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32);\
+    __raw_writel(new_value, (base_address)+offset);\
+}
+
+#endif /* USE_LEVEL_1_MACROS */
+
+#endif /* _MMU_REG_ACM_H */
diff --git a/drivers/staging/tidspbridge/hw/hw_defs.h b/drivers/staging/tidspbridge/hw/hw_defs.h
new file mode 100644 (file)
index 0000000..d5266d4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * hw_defs.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Global HW definitions
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HW_DEFS_H
+#define _HW_DEFS_H
+
+/* Page size */
+#define HW_PAGE_SIZE4KB   0x1000
+#define HW_PAGE_SIZE64KB  0x10000
+#define HW_PAGE_SIZE1MB   0x100000
+#define HW_PAGE_SIZE16MB  0x1000000
+
+/* hw_status:  return type for HW API */
+typedef long hw_status;
+
+/*  Macro used to set and clear any bit */
+#define HW_CLEAR       0
+#define HW_SET         1
+
+/* hw_endianism_t:  Enumerated Type used to specify the endianism
+ *             Do NOT change these values. They are used as bit fields. */
+enum hw_endianism_t {
+       HW_LITTLE_ENDIAN,
+       HW_BIG_ENDIAN
+};
+
+/* hw_element_size_t:  Enumerated Type used to specify the element size
+ *             Do NOT change these values. They are used as bit fields. */
+enum hw_element_size_t {
+       HW_ELEM_SIZE8BIT,
+       HW_ELEM_SIZE16BIT,
+       HW_ELEM_SIZE32BIT,
+       HW_ELEM_SIZE64BIT
+};
+
+/* hw_idle_mode_t:  Enumerated Type used to specify Idle modes */
+enum hw_idle_mode_t {
+       HW_FORCE_IDLE,
+       HW_NO_IDLE,
+       HW_SMART_IDLE
+};
+
+#endif /* _HW_DEFS_H */
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.c b/drivers/staging/tidspbridge/hw/hw_mmu.c
new file mode 100644 (file)
index 0000000..014f5d5
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ * hw_mmu.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * API definitions to setup MMU TLB and PTE
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/io.h>
+#include "MMURegAcM.h"
+#include <hw_defs.h>
+#include <hw_mmu.h>
+#include <linux/types.h>
+#include <linux/err.h>
+
+#define MMU_BASE_VAL_MASK      0xFC00
+#define MMU_PAGE_MAX        3
+#define MMU_ELEMENTSIZE_MAX      3
+#define MMU_ADDR_MASK      0xFFFFF000
+#define MMU_TTB_MASK        0xFFFFC000
+#define MMU_SECTION_ADDR_MASK    0xFFF00000
+#define MMU_SSECTION_ADDR_MASK   0xFF000000
+#define MMU_PAGE_TABLE_MASK      0xFFFFFC00
+#define MMU_LARGE_PAGE_MASK      0xFFFF0000
+#define MMU_SMALL_PAGE_MASK      0xFFFFF000
+
+#define MMU_LOAD_TLB   0x00000001
+#define MMU_GFLUSH     0x60
+
+/*
+ * hw_mmu_page_size_t: Enumerated Type used to specify the MMU Page Size(SLSS)
+ */
+enum hw_mmu_page_size_t {
+       HW_MMU_SECTION,
+       HW_MMU_LARGE_PAGE,
+       HW_MMU_SMALL_PAGE,
+       HW_MMU_SUPERSECTION
+};
+
+/*
+ * FUNCTION          : mmu_flush_entry
+ *
+ * INPUTS:
+ *
+ *       Identifier      : base_address
+ *       Type          : const u32
+ *       Description     : Base Address of instance of MMU module
+ *
+ * RETURNS:
+ *
+ *       Type          : hw_status
+ *       Description     : 0            -- No errors occured
+ *                      RET_BAD_NULL_PARAM     -- A Pointer
+ *                                             Paramater was set to NULL
+ *
+ * PURPOSE:          : Flush the TLB entry pointed by the
+ *                     lock counter register
+ *                     even if this entry is set protected
+ *
+ * METHOD:            : Check the Input parameter and Flush a
+ *                      single entry in the TLB.
+ */
+static hw_status mmu_flush_entry(const void __iomem *base_address);
+
+/*
+ * FUNCTION          : mmu_set_cam_entry
+ *
+ * INPUTS:
+ *
+ *       Identifier      : base_address
+ *       TypE          : const u32
+ *       Description     : Base Address of instance of MMU module
+ *
+ *       Identifier      : page_sz
+ *       TypE          : const u32
+ *       Description     : It indicates the page size
+ *
+ *       Identifier      : preserved_bit
+ *       Type          : const u32
+ *       Description     : It indicates the TLB entry is preserved entry
+ *                                                     or not
+ *
+ *       Identifier      : valid_bit
+ *       Type          : const u32
+ *       Description     : It indicates the TLB entry is valid entry or not
+ *
+ *
+ *       Identifier      : virtual_addr_tag
+ *       Type          : const u32
+ *       Description     : virtual Address
+ *
+ * RETURNS:
+ *
+ *       Type          : hw_status
+ *       Description     : 0            -- No errors occured
+ *                      RET_BAD_NULL_PARAM     -- A Pointer Paramater
+ *                                                was set to NULL
+ *                      RET_PARAM_OUT_OF_RANGE -- Input Parameter out
+ *                                                of Range
+ *
+ * PURPOSE:            : Set MMU_CAM reg
+ *
+ * METHOD:             : Check the Input parameters and set the CAM entry.
+ */
+static hw_status mmu_set_cam_entry(const void __iomem *base_address,
+                                  const u32 page_sz,
+                                  const u32 preserved_bit,
+                                  const u32 valid_bit,
+                                  const u32 virtual_addr_tag);
+
+/*
+ * FUNCTION          : mmu_set_ram_entry
+ *
+ * INPUTS:
+ *
+ *       Identifier      : base_address
+ *       Type          : const u32
+ *       Description     : Base Address of instance of MMU module
+ *
+ *       Identifier      : physical_addr
+ *       Type          : const u32
+ *       Description     : Physical Address to which the corresponding
+ *                      virtual   Address shouldpoint
+ *
+ *       Identifier      : endianism
+ *       Type          : hw_endianism_t
+ *       Description     : endianism for the given page
+ *
+ *       Identifier      : element_size
+ *       Type          : hw_element_size_t
+ *       Description     : The element size ( 8,16, 32 or 64 bit)
+ *
+ *       Identifier      : mixed_size
+ *       Type          : hw_mmu_mixed_size_t
+ *       Description     : Element Size to follow CPU or TLB
+ *
+ * RETURNS:
+ *
+ *       Type          : hw_status
+ *       Description     : 0            -- No errors occured
+ *                      RET_BAD_NULL_PARAM     -- A Pointer Paramater
+ *                                                     was set to NULL
+ *                      RET_PARAM_OUT_OF_RANGE -- Input Parameter
+ *                                                     out of Range
+ *
+ * PURPOSE:          : Set MMU_CAM reg
+ *
+ * METHOD:            : Check the Input parameters and set the RAM entry.
+ */
+static hw_status mmu_set_ram_entry(const void __iomem *base_address,
+                                  const u32 physical_addr,
+                                  enum hw_endianism_t endianism,
+                                  enum hw_element_size_t element_size,
+                                  enum hw_mmu_mixed_size_t mixed_size);
+
+/* HW FUNCTIONS */
+
+hw_status hw_mmu_enable(const void __iomem *base_address)
+{
+       hw_status status = 0;
+
+       MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_SET);
+
+       return status;
+}
+
+hw_status hw_mmu_disable(const void __iomem *base_address)
+{
+       hw_status status = 0;
+
+       MMUMMU_CNTLMMU_ENABLE_WRITE32(base_address, HW_CLEAR);
+
+       return status;
+}
+
+hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
+                               u32 num_locked_entries)
+{
+       hw_status status = 0;
+
+       MMUMMU_LOCK_BASE_VALUE_WRITE32(base_address, num_locked_entries);
+
+       return status;
+}
+
+hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
+                               u32 victim_entry_num)
+{
+       hw_status status = 0;
+
+       MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, victim_entry_num);
+
+       return status;
+}
+
+hw_status hw_mmu_event_ack(const void __iomem *base_address, u32 irq_mask)
+{
+       hw_status status = 0;
+
+       MMUMMU_IRQSTATUS_WRITE_REGISTER32(base_address, irq_mask);
+
+       return status;
+}
+
+hw_status hw_mmu_event_disable(const void __iomem *base_address, u32 irq_mask)
+{
+       hw_status status = 0;
+       u32 irq_reg;
+
+       irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
+
+       MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg & ~irq_mask);
+
+       return status;
+}
+
+hw_status hw_mmu_event_enable(const void __iomem *base_address, u32 irq_mask)
+{
+       hw_status status = 0;
+       u32 irq_reg;
+
+       irq_reg = MMUMMU_IRQENABLE_READ_REGISTER32(base_address);
+
+       MMUMMU_IRQENABLE_WRITE_REGISTER32(base_address, irq_reg | irq_mask);
+
+       return status;
+}
+
+hw_status hw_mmu_event_status(const void __iomem *base_address, u32 *irq_mask)
+{
+       hw_status status = 0;
+
+       *irq_mask = MMUMMU_IRQSTATUS_READ_REGISTER32(base_address);
+
+       return status;
+}
+
+hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, u32 *addr)
+{
+       hw_status status = 0;
+
+       /* read values from register */
+       *addr = MMUMMU_FAULT_AD_READ_REGISTER32(base_address);
+
+       return status;
+}
+
+hw_status hw_mmu_ttb_set(const void __iomem *base_address, u32 ttb_phys_addr)
+{
+       hw_status status = 0;
+       u32 load_ttb;
+
+       load_ttb = ttb_phys_addr & ~0x7FUL;
+       /* write values to register */
+       MMUMMU_TTB_WRITE_REGISTER32(base_address, load_ttb);
+
+       return status;
+}
+
+hw_status hw_mmu_twl_enable(const void __iomem *base_address)
+{
+       hw_status status = 0;
+
+       MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_SET);
+
+       return status;
+}
+
+hw_status hw_mmu_twl_disable(const void __iomem *base_address)
+{
+       hw_status status = 0;
+
+       MMUMMU_CNTLTWL_ENABLE_WRITE32(base_address, HW_CLEAR);
+
+       return status;
+}
+
+hw_status hw_mmu_tlb_flush(const void __iomem *base_address, u32 virtual_addr,
+                          u32 page_sz)
+{
+       hw_status status = 0;
+       u32 virtual_addr_tag;
+       enum hw_mmu_page_size_t pg_size_bits;
+
+       switch (page_sz) {
+       case HW_PAGE_SIZE4KB:
+               pg_size_bits = HW_MMU_SMALL_PAGE;
+               break;
+
+       case HW_PAGE_SIZE64KB:
+               pg_size_bits = HW_MMU_LARGE_PAGE;
+               break;
+
+       case HW_PAGE_SIZE1MB:
+               pg_size_bits = HW_MMU_SECTION;
+               break;
+
+       case HW_PAGE_SIZE16MB:
+               pg_size_bits = HW_MMU_SUPERSECTION;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Generate the 20-bit tag from virtual address */
+       virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
+
+       mmu_set_cam_entry(base_address, pg_size_bits, 0, 0, virtual_addr_tag);
+
+       mmu_flush_entry(base_address);
+
+       return status;
+}
+
+hw_status hw_mmu_tlb_add(const void __iomem *base_address,
+                        u32 physical_addr,
+                        u32 virtual_addr,
+                        u32 page_sz,
+                        u32 entry_num,
+                        struct hw_mmu_map_attrs_t *map_attrs,
+                        s8 preserved_bit, s8 valid_bit)
+{
+       hw_status status = 0;
+       u32 lock_reg;
+       u32 virtual_addr_tag;
+       enum hw_mmu_page_size_t mmu_pg_size;
+
+       /*Check the input Parameters */
+       switch (page_sz) {
+       case HW_PAGE_SIZE4KB:
+               mmu_pg_size = HW_MMU_SMALL_PAGE;
+               break;
+
+       case HW_PAGE_SIZE64KB:
+               mmu_pg_size = HW_MMU_LARGE_PAGE;
+               break;
+
+       case HW_PAGE_SIZE1MB:
+               mmu_pg_size = HW_MMU_SECTION;
+               break;
+
+       case HW_PAGE_SIZE16MB:
+               mmu_pg_size = HW_MMU_SUPERSECTION;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       lock_reg = MMUMMU_LOCK_READ_REGISTER32(base_address);
+
+       /* Generate the 20-bit tag from virtual address */
+       virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
+
+       /* Write the fields in the CAM Entry Register */
+       mmu_set_cam_entry(base_address, mmu_pg_size, preserved_bit, valid_bit,
+                         virtual_addr_tag);
+
+       /* Write the different fields of the RAM Entry Register */
+       /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit) */
+       mmu_set_ram_entry(base_address, physical_addr, map_attrs->endianism,
+                         map_attrs->element_size, map_attrs->mixed_size);
+
+       /* Update the MMU Lock Register */
+       /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1) */
+       MMUMMU_LOCK_CURRENT_VICTIM_WRITE32(base_address, entry_num);
+
+       /* Enable loading of an entry in TLB by writing 1
+          into LD_TLB_REG register */
+       MMUMMU_LD_TLB_WRITE_REGISTER32(base_address, MMU_LOAD_TLB);
+
+       MMUMMU_LOCK_WRITE_REGISTER32(base_address, lock_reg);
+
+       return status;
+}
+
+hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
+                        u32 physical_addr,
+                        u32 virtual_addr,
+                        u32 page_sz, struct hw_mmu_map_attrs_t *map_attrs)
+{
+       hw_status status = 0;
+       u32 pte_addr, pte_val;
+       s32 num_entries = 1;
+
+       switch (page_sz) {
+       case HW_PAGE_SIZE4KB:
+               pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SMALL_PAGE_MASK);
+               pte_val =
+                   ((physical_addr & MMU_SMALL_PAGE_MASK) |
+                    (map_attrs->endianism << 9) | (map_attrs->
+                                                   element_size << 4) |
+                    (map_attrs->mixed_size << 11) | 2);
+               break;
+
+       case HW_PAGE_SIZE64KB:
+               num_entries = 16;
+               pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_LARGE_PAGE_MASK);
+               pte_val =
+                   ((physical_addr & MMU_LARGE_PAGE_MASK) |
+                    (map_attrs->endianism << 9) | (map_attrs->
+                                                   element_size << 4) |
+                    (map_attrs->mixed_size << 11) | 1);
+               break;
+
+       case HW_PAGE_SIZE1MB:
+               pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SECTION_ADDR_MASK);
+               pte_val =
+                   ((((physical_addr & MMU_SECTION_ADDR_MASK) |
+                      (map_attrs->endianism << 15) | (map_attrs->
+                                                      element_size << 10) |
+                      (map_attrs->mixed_size << 17)) & ~0x40000) | 0x2);
+               break;
+
+       case HW_PAGE_SIZE16MB:
+               num_entries = 16;
+               pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SSECTION_ADDR_MASK);
+               pte_val =
+                   (((physical_addr & MMU_SSECTION_ADDR_MASK) |
+                     (map_attrs->endianism << 15) | (map_attrs->
+                                                     element_size << 10) |
+                     (map_attrs->mixed_size << 17)
+                    ) | 0x40000 | 0x2);
+               break;
+
+       case HW_MMU_COARSE_PAGE_SIZE:
+               pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SECTION_ADDR_MASK);
+               pte_val = (physical_addr & MMU_PAGE_TABLE_MASK) | 1;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       while (--num_entries >= 0)
+               ((u32 *) pte_addr)[num_entries] = pte_val;
+
+       return status;
+}
+
+hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, u32 virtual_addr, u32 page_size)
+{
+       hw_status status = 0;
+       u32 pte_addr;
+       s32 num_entries = 1;
+
+       switch (page_size) {
+       case HW_PAGE_SIZE4KB:
+               pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SMALL_PAGE_MASK);
+               break;
+
+       case HW_PAGE_SIZE64KB:
+               num_entries = 16;
+               pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_LARGE_PAGE_MASK);
+               break;
+
+       case HW_PAGE_SIZE1MB:
+       case HW_MMU_COARSE_PAGE_SIZE:
+               pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SECTION_ADDR_MASK);
+               break;
+
+       case HW_PAGE_SIZE16MB:
+               num_entries = 16;
+               pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va,
+                                             virtual_addr &
+                                             MMU_SSECTION_ADDR_MASK);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       while (--num_entries >= 0)
+               ((u32 *) pte_addr)[num_entries] = 0;
+
+       return status;
+}
+
+/* mmu_flush_entry */
+static hw_status mmu_flush_entry(const void __iomem *base_address)
+{
+       hw_status status = 0;
+       u32 flush_entry_data = 0x1;
+
+       /* write values to register */
+       MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, flush_entry_data);
+
+       return status;
+}
+
+/* mmu_set_cam_entry */
+static hw_status mmu_set_cam_entry(const void __iomem *base_address,
+                                  const u32 page_sz,
+                                  const u32 preserved_bit,
+                                  const u32 valid_bit,
+                                  const u32 virtual_addr_tag)
+{
+       hw_status status = 0;
+       u32 mmu_cam_reg;
+
+       mmu_cam_reg = (virtual_addr_tag << 12);
+       mmu_cam_reg = (mmu_cam_reg) | (page_sz) | (valid_bit << 2) |
+           (preserved_bit << 3);
+
+       /* write values to register */
+       MMUMMU_CAM_WRITE_REGISTER32(base_address, mmu_cam_reg);
+
+       return status;
+}
+
+/* mmu_set_ram_entry */
+static hw_status mmu_set_ram_entry(const void __iomem *base_address,
+                                  const u32 physical_addr,
+                                  enum hw_endianism_t endianism,
+                                  enum hw_element_size_t element_size,
+                                  enum hw_mmu_mixed_size_t mixed_size)
+{
+       hw_status status = 0;
+       u32 mmu_ram_reg;
+
+       mmu_ram_reg = (physical_addr & MMU_ADDR_MASK);
+       mmu_ram_reg = (mmu_ram_reg) | ((endianism << 9) | (element_size << 7) |
+                                      (mixed_size << 6));
+
+       /* write values to register */
+       MMUMMU_RAM_WRITE_REGISTER32(base_address, mmu_ram_reg);
+
+       return status;
+
+}
+
+void hw_mmu_tlb_flush_all(const void __iomem *base)
+{
+       __raw_writeb(1, base + MMU_GFLUSH);
+}
diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.h b/drivers/staging/tidspbridge/hw/hw_mmu.h
new file mode 100644 (file)
index 0000000..1458a2c
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * hw_mmu.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * MMU types and API declarations
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _HW_MMU_H
+#define _HW_MMU_H
+
+#include <linux/types.h>
+
+/* Bitmasks for interrupt sources */
+#define HW_MMU_TRANSLATION_FAULT   0x2
+#define HW_MMU_ALL_INTERRUPTS      0x1F
+
+#define HW_MMU_COARSE_PAGE_SIZE 0x400
+
+/* hw_mmu_mixed_size_t:  Enumerated Type used to specify whether to follow
+                       CPU/TLB Element size */
+enum hw_mmu_mixed_size_t {
+       HW_MMU_TLBES,
+       HW_MMU_CPUES
+};
+
+/* hw_mmu_map_attrs_t:  Struct containing MMU mapping attributes */
+struct hw_mmu_map_attrs_t {
+       enum hw_endianism_t endianism;
+       enum hw_element_size_t element_size;
+       enum hw_mmu_mixed_size_t mixed_size;
+       bool donotlockmpupage;
+};
+
+extern hw_status hw_mmu_enable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_disable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
+                                      u32 num_locked_entries);
+
+extern hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
+                                      u32 victim_entry_num);
+
+/* For MMU faults */
+extern hw_status hw_mmu_event_ack(const void __iomem *base_address,
+                                 u32 irq_mask);
+
+extern hw_status hw_mmu_event_disable(const void __iomem *base_address,
+                                     u32 irq_mask);
+
+extern hw_status hw_mmu_event_enable(const void __iomem *base_address,
+                                    u32 irq_mask);
+
+extern hw_status hw_mmu_event_status(const void __iomem *base_address,
+                                    u32 *irq_mask);
+
+extern hw_status hw_mmu_fault_addr_read(const void __iomem *base_address,
+                                       u32 *addr);
+
+/* Set the TT base address */
+extern hw_status hw_mmu_ttb_set(const void __iomem *base_address,
+                               u32 ttb_phys_addr);
+
+extern hw_status hw_mmu_twl_enable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_twl_disable(const void __iomem *base_address);
+
+extern hw_status hw_mmu_tlb_flush(const void __iomem *base_address,
+                                 u32 virtual_addr, u32 page_sz);
+
+extern hw_status hw_mmu_tlb_add(const void __iomem *base_address,
+                               u32 physical_addr,
+                               u32 virtual_addr,
+                               u32 page_sz,
+                               u32 entry_num,
+                               struct hw_mmu_map_attrs_t *map_attrs,
+                               s8 preserved_bit, s8 valid_bit);
+
+/* For PTEs */
+extern hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
+                               u32 physical_addr,
+                               u32 virtual_addr,
+                               u32 page_sz,
+                               struct hw_mmu_map_attrs_t *map_attrs);
+
+extern hw_status hw_mmu_pte_clear(const u32 pg_tbl_va,
+                                 u32 virtual_addr, u32 page_size);
+
+void hw_mmu_tlb_flush_all(const void __iomem *base);
+
+static inline u32 hw_mmu_pte_addr_l1(u32 l1_base, u32 va)
+{
+       u32 pte_addr;
+       u32 va31_to20;
+
+       va31_to20 = va >> (20 - 2);     /* Left-shift by 2 here itself */
+       va31_to20 &= 0xFFFFFFFCUL;
+       pte_addr = l1_base + va31_to20;
+
+       return pte_addr;
+}
+
+static inline u32 hw_mmu_pte_addr_l2(u32 l2_base, u32 va)
+{
+       u32 pte_addr;
+
+       pte_addr = (l2_base & 0xFFFFFC00) | ((va >> 10) & 0x3FC);
+
+       return pte_addr;
+}
+
+static inline u32 hw_mmu_pte_coarse_l1(u32 pte_val)
+{
+       u32 pte_coarse;
+
+       pte_coarse = pte_val & 0xFFFFFC00;
+
+       return pte_coarse;
+}
+
+static inline u32 hw_mmu_pte_size_l1(u32 pte_val)
+{
+       u32 pte_size = 0;
+
+       if ((pte_val & 0x3) == 0x1) {
+               /* Points to L2 PT */
+               pte_size = HW_MMU_COARSE_PAGE_SIZE;
+       }
+
+       if ((pte_val & 0x3) == 0x2) {
+               if (pte_val & (1 << 18))
+                       pte_size = HW_PAGE_SIZE16MB;
+               else
+                       pte_size = HW_PAGE_SIZE1MB;
+       }
+
+       return pte_size;
+}
+
+static inline u32 hw_mmu_pte_size_l2(u32 pte_val)
+{
+       u32 pte_size = 0;
+
+       if (pte_val & 0x2)
+               pte_size = HW_PAGE_SIZE4KB;
+       else if (pte_val & 0x1)
+               pte_size = HW_PAGE_SIZE64KB;
+
+       return pte_size;
+}
+
+#endif /* _HW_MMU_H */
index dfb55cca34c74a71fa1a75b8c9ec9ee47d09463a..38122dbf877a198c0e52a1ed21a358b2eb6828f1 100644 (file)
@@ -68,6 +68,7 @@ struct cfg_hostres {
        void __iomem *dw_per_base;
        u32 dw_per_pm_base;
        u32 dw_core_pm_base;
+       void __iomem *dw_dmmu_base;
        void __iomem *dw_sys_ctrl_base;
 };
 
index 9bdd48f5742994ab0376cf680944b1c57835035d..357458fadd2a3a50935efd751a20649512b86596 100644 (file)
@@ -27,6 +27,7 @@
 #include <dspbridge/nodedefs.h>
 #include <dspbridge/dispdefs.h>
 #include <dspbridge/dspdefs.h>
+#include <dspbridge/dmm.h>
 #include <dspbridge/host_os.h>
 
 /*  ----------------------------------- This */
@@ -232,6 +233,29 @@ extern int dev_get_chnl_mgr(struct dev_object *hdev_obj,
 extern int dev_get_cmm_mgr(struct dev_object *hdev_obj,
                                  struct cmm_object **mgr);
 
+/*
+ *  ======== dev_get_dmm_mgr ========
+ *  Purpose:
+ *      Retrieve the handle to the dynamic memory manager created for this
+ *      device.
+ *  Parameters:
+ *      hdev_obj:     Handle to device object created with
+ *                      dev_create_device().
+ *      *mgr:           Ptr to location to store handle.
+ *  Returns:
+ *      0:        Success.
+ *      -EFAULT:    Invalid hdev_obj.
+ *  Requires:
+ *      mgr != NULL.
+ *      DEV Initialized.
+ *  Ensures:
+ *      0:        *mgr contains a handle to a channel manager object,
+ *                      or NULL.
+ *      else:           *mgr is NULL.
+ */
+extern int dev_get_dmm_mgr(struct dev_object *hdev_obj,
+                                 struct dmm_object **mgr);
+
 /*
  *  ======== dev_get_cod_mgr ========
  *  Purpose:
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dmm.h b/drivers/staging/tidspbridge/include/dspbridge/dmm.h
new file mode 100644 (file)
index 0000000..6c58335
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * dmm.h
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Dynamic Memory Mapping(DMM) module manages the DSP Virtual address
+ * space that can be directly mapped to any MPU buffer or memory region.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef DMM_
+#define DMM_
+
+#include <dspbridge/dbdefs.h>
+
+struct dmm_object;
+
+/* DMM attributes used in dmm_create() */
+struct dmm_mgrattrs {
+       u32 reserved;
+};
+
+#define DMMPOOLSIZE      0x4000000
+
+/*
+ *  ======== dmm_get_handle ========
+ *  Purpose:
+ *      Return the dynamic memory manager object for this device.
+ *      This is typically called from the client process.
+ */
+
+extern int dmm_get_handle(void *hprocessor,
+                                struct dmm_object **dmm_manager);
+
+extern int dmm_reserve_memory(struct dmm_object *dmm_mgr,
+                                    u32 size, u32 *prsv_addr);
+
+extern int dmm_un_reserve_memory(struct dmm_object *dmm_mgr,
+                                       u32 rsv_addr);
+
+extern int dmm_map_memory(struct dmm_object *dmm_mgr, u32 addr,
+                                u32 size);
+
+extern int dmm_un_map_memory(struct dmm_object *dmm_mgr,
+                                   u32 addr, u32 *psize);
+
+extern int dmm_destroy(struct dmm_object *dmm_mgr);
+
+extern int dmm_delete_tables(struct dmm_object *dmm_mgr);
+
+extern int dmm_create(struct dmm_object **dmm_manager,
+                            struct dev_object *hdev_obj,
+                            const struct dmm_mgrattrs *mgr_attrts);
+
+extern bool dmm_init(void);
+
+extern void dmm_exit(void);
+
+extern int dmm_create_tables(struct dmm_object *dmm_mgr,
+                                   u32 addr, u32 size);
+
+#ifdef DSP_DMM_DEBUG
+u32 dmm_mem_map_dump(struct dmm_object *dmm_mgr);
+#endif
+
+#endif /* DMM_ */
index 75a2c9b5c6f29cee45a86999eb081e8f2503b93f..c1f363ec9afab51b225c1fc0007c7edf62e5dbb7 100644 (file)
@@ -108,6 +108,12 @@ struct dmm_map_object {
        struct bridge_dma_map_info dma_info;
 };
 
+/* Used for DMM reserved memory accounting */
+struct dmm_rsv_object {
+       struct list_head link;
+       u32 dsp_reserved_addr;
+};
+
 /* New structure (member of process context) abstracts DMM resource info */
 struct dspheap_res_object {
        s32 heap_allocated;     /* DMM status */
@@ -159,6 +165,10 @@ struct process_context {
        struct list_head dmm_map_list;
        spinlock_t dmm_map_lock;
 
+       /* DMM reserved memory resources */
+       struct list_head dmm_rsv_list;
+       spinlock_t dmm_rsv_lock;
+
        /* DSP Heap resources */
        struct dspheap_res_object *pdspheap_list;
 
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h b/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h
deleted file mode 100644 (file)
index cb38d4c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * dsp-mmu.h
- *
- * DSP-BIOS Bridge driver support functions for TI OMAP processors.
- *
- * DSP iommu.
- *
- * Copyright (C) 2005-2010 Texas Instruments, Inc.
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef _DSP_MMU_
-#define _DSP_MMU_
-
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-
-/**
- * dsp_mmu_init() - initialize dsp_mmu module and returns a handle
- *
- * This function initialize dsp mmu module and returns a struct iommu
- * handle to use it for dsp maps.
- *
- */
-struct iommu *dsp_mmu_init(void);
-
-/**
- * dsp_mmu_exit() - destroy dsp mmu module
- * @mmu:       Pointer to iommu handle.
- *
- * This function destroys dsp mmu module.
- *
- */
-void dsp_mmu_exit(struct iommu *mmu);
-
-/**
- * user_to_dsp_map() - maps user to dsp virtual address
- * @mmu:       Pointer to iommu handle.
- * @uva:               Virtual user space address.
- * @da         DSP address
- * @size               Buffer size to map.
- * @usr_pgs    struct page array pointer where the user pages will be stored
- *
- * This function maps a user space buffer into DSP virtual address.
- *
- */
-u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
-                                               struct page **usr_pgs);
-
-/**
- * user_to_dsp_unmap() - unmaps DSP virtual buffer.
- * @mmu:       Pointer to iommu handle.
- * @da         DSP address
- *
- * This function unmaps a user space buffer into DSP virtual address.
- *
- */
-int user_to_dsp_unmap(struct iommu *mmu, u32 da);
-
-#endif
index 615363474810e85c0f4b3c07191b8c744054e883..0ae7d1646a1bf74f4642a94fd27ddef262011a5d 100644 (file)
@@ -161,6 +161,48 @@ typedef int(*fxn_brd_memwrite) (struct bridge_dev_context
                                       u32 dsp_addr, u32 ul_num_bytes,
                                       u32 mem_type);
 
+/*
+ *  ======== bridge_brd_mem_map ========
+ *  Purpose:
+ *      Map a MPU memory region to a DSP/IVA memory space
+ *  Parameters:
+ *      dev_ctxt:    Handle to Bridge driver defined device info.
+ *      ul_mpu_addr:      MPU memory region start address.
+ *      virt_addr:      DSP/IVA memory region u8 address.
+ *      ul_num_bytes:     Number of bytes to map.
+ *      map_attrs:       Mapping attributes (e.g. endianness).
+ *  Returns:
+ *      0:        Success.
+ *      -EPERM:      Other, unspecified error.
+ *  Requires:
+ *      dev_ctxt != NULL;
+ *  Ensures:
+ */
+typedef int(*fxn_brd_memmap) (struct bridge_dev_context
+                                    * dev_ctxt, u32 ul_mpu_addr,
+                                    u32 virt_addr, u32 ul_num_bytes,
+                                    u32 map_attr,
+                                    struct page **mapped_pages);
+
+/*
+ *  ======== bridge_brd_mem_un_map ========
+ *  Purpose:
+ *      UnMap an MPU memory region from DSP/IVA memory space
+ *  Parameters:
+ *      dev_ctxt:    Handle to Bridge driver defined device info.
+ *      virt_addr:      DSP/IVA memory region u8 address.
+ *      ul_num_bytes:     Number of bytes to unmap.
+ *  Returns:
+ *      0:        Success.
+ *      -EPERM:      Other, unspecified error.
+ *  Requires:
+ *      dev_ctxt != NULL;
+ *  Ensures:
+ */
+typedef int(*fxn_brd_memunmap) (struct bridge_dev_context
+                                      * dev_ctxt,
+                                      u32 virt_addr, u32 ul_num_bytes);
+
 /*
  *  ======== bridge_brd_stop ========
  *  Purpose:
@@ -951,6 +993,8 @@ struct bridge_drv_interface {
        fxn_brd_setstate pfn_brd_set_state;     /* Sets the Board State */
        fxn_brd_memcopy pfn_brd_mem_copy;       /* Copies DSP Memory */
        fxn_brd_memwrite pfn_brd_mem_write;     /* Write DSP Memory w/o halt */
+       fxn_brd_memmap pfn_brd_mem_map; /* Maps MPU mem to DSP mem */
+       fxn_brd_memunmap pfn_brd_mem_un_map;    /* Unmaps MPU mem to DSP mem */
        fxn_chnl_create pfn_chnl_create;        /* Create channel manager. */
        fxn_chnl_destroy pfn_chnl_destroy;      /* Destroy channel manager. */
        fxn_chnl_open pfn_chnl_open;    /* Create a new channel. */
index bad180108adaae3fcf0d70811c37f56b0c2c2251..41e0594dff340d1cae3ab50f6e350c35dcc49969 100644 (file)
 #ifndef DSPIOCTL_
 #define DSPIOCTL_
 
+/* ------------------------------------ Hardware Abstraction Layer */
+#include <hw_defs.h>
+#include <hw_mmu.h>
+
 /*
  * Any IOCTLS at or above this value are reserved for standard Bridge driver
  * interfaces.
@@ -61,6 +65,9 @@ struct bridge_ioctl_extproc {
        /* GPP virtual address. __va does not work for ioremapped addresses */
        u32 ul_gpp_va;
        u32 ul_size;            /* Size of the mapped memory in bytes */
+       enum hw_endianism_t endianism;
+       enum hw_mmu_mixed_size_t mixed_mode;
+       enum hw_element_size_t elem_size;
 };
 
 #endif /* DSPIOCTL_ */
index 2d12aab6b5bf1ed218068ff5b480bc61a1b972be..5e09fd165d9d4c9294aaf76333ca290cde8e6f26 100644 (file)
@@ -550,6 +550,29 @@ extern int proc_map(void *hprocessor,
                           void **pp_map_addr, u32 ul_map_attr,
                           struct process_context *pr_ctxt);
 
+/*
+ *  ======== proc_reserve_memory ========
+ *  Purpose:
+ *      Reserve a virtually contiguous region of DSP address space.
+ *  Parameters:
+ *      hprocessor      :   The processor handle.
+ *      ul_size          :   Size of the address space to reserve.
+ *      pp_rsv_addr       :   Ptr to DSP side reserved u8 address.
+ *  Returns:
+ *      0       :   Success.
+ *      -EFAULT     :   Invalid processor handle.
+ *      -EPERM       :   General failure.
+ *      -ENOMEM     :   Cannot reserve chunk of this size.
+ *  Requires:
+ *      pp_rsv_addr is not NULL
+ *      PROC Initialized.
+ *  Ensures:
+ *  Details:
+ */
+extern int proc_reserve_memory(void *hprocessor,
+                                     u32 ul_size, void **pp_rsv_addr,
+                                     struct process_context *pr_ctxt);
+
 /*
  *  ======== proc_un_map ========
  *  Purpose:
@@ -572,4 +595,27 @@ extern int proc_map(void *hprocessor,
 extern int proc_un_map(void *hprocessor, void *map_addr,
                              struct process_context *pr_ctxt);
 
+/*
+ *  ======== proc_un_reserve_memory ========
+ *  Purpose:
+ *      Frees a previously reserved region of DSP address space.
+ *  Parameters:
+ *      hprocessor      :   The processor handle.
+ *      prsv_addr      :   Ptr to DSP side reservedBYTE address.
+ *  Returns:
+ *      0       :   Success.
+ *      -EFAULT     :   Invalid processor handle.
+ *      -EPERM       :   General failure.
+ *      -ENOENT   :   Cannot find a reserved region starting with this
+ *                   :   address.
+ *  Requires:
+ *      prsv_addr is not NULL
+ *      PROC Initialized.
+ *  Ensures:
+ *  Details:
+ */
+extern int proc_un_reserve_memory(void *hprocessor,
+                                        void *prsv_addr,
+                                        struct process_context *pr_ctxt);
+
 #endif /* PROC_ */
index 7b30267ef0e29daa168eb2a09067708d59c05d4f..132e960967b970b75a6441cf65127de390efe973 100644 (file)
@@ -34,6 +34,7 @@
 #include <dspbridge/cod.h>
 #include <dspbridge/drv.h>
 #include <dspbridge/proc.h>
+#include <dspbridge/dmm.h>
 
 /*  ----------------------------------- Resource Manager */
 #include <dspbridge/mgr.h>
@@ -74,6 +75,7 @@ struct dev_object {
        struct msg_mgr *hmsg_mgr;       /* Message manager. */
        struct io_mgr *hio_mgr; /* IO manager (CHNL, msg_ctrl) */
        struct cmm_object *hcmm_mgr;    /* SM memory manager. */
+       struct dmm_object *dmm_mgr;     /* Dynamic memory manager. */
        struct ldr_module *module_obj;  /* Bridge Module handle. */
        u32 word_size;          /* DSP word size: quick access. */
        struct drv_object *hdrv_obj;    /* Driver Object */
@@ -248,6 +250,9 @@ int dev_create_device(struct dev_object **device_obj,
                        /* Instantiate the DEH module */
                        status = bridge_deh_create(&dev_obj->hdeh_mgr, dev_obj);
                }
+               /* Create DMM mgr . */
+               status = dmm_create(&dev_obj->dmm_mgr,
+                                   (struct dev_object *)dev_obj, NULL);
        }
        /* Add the new DEV_Object to the global list: */
        if (!status) {
@@ -273,6 +278,8 @@ leave:
                        kfree(dev_obj->proc_list);
                        if (dev_obj->cod_mgr)
                                cod_delete(dev_obj->cod_mgr);
+                       if (dev_obj->dmm_mgr)
+                               dmm_destroy(dev_obj->dmm_mgr);
                        kfree(dev_obj);
                }
 
@@ -382,6 +389,11 @@ int dev_destroy_device(struct dev_object *hdev_obj)
                        dev_obj->hcmm_mgr = NULL;
                }
 
+               if (dev_obj->dmm_mgr) {
+                       dmm_destroy(dev_obj->dmm_mgr);
+                       dev_obj->dmm_mgr = NULL;
+               }
+
                /* Call the driver's bridge_dev_destroy() function: */
                /* Require of DevDestroy */
                if (dev_obj->hbridge_context) {
@@ -461,6 +473,32 @@ int dev_get_cmm_mgr(struct dev_object *hdev_obj,
        return status;
 }
 
+/*
+ *  ======== dev_get_dmm_mgr ========
+ *  Purpose:
+ *      Retrieve the handle to the dynamic memory manager created for this
+ *      device.
+ */
+int dev_get_dmm_mgr(struct dev_object *hdev_obj,
+                          struct dmm_object **mgr)
+{
+       int status = 0;
+       struct dev_object *dev_obj = hdev_obj;
+
+       DBC_REQUIRE(refs > 0);
+       DBC_REQUIRE(mgr != NULL);
+
+       if (hdev_obj) {
+               *mgr = dev_obj->dmm_mgr;
+       } else {
+               *mgr = NULL;
+               status = -EFAULT;
+       }
+
+       DBC_ENSURE(!status || (mgr != NULL && *mgr == NULL));
+       return status;
+}
+
 /*
  *  ======== dev_get_cod_mgr ========
  *  Purpose:
@@ -713,8 +751,10 @@ void dev_exit(void)
 
        refs--;
 
-       if (refs == 0)
+       if (refs == 0) {
                cmm_exit();
+               dmm_exit();
+       }
 
        DBC_ENSURE(refs >= 0);
 }
@@ -726,12 +766,25 @@ void dev_exit(void)
  */
 bool dev_init(void)
 {
-       bool ret = true;
+       bool cmm_ret, dmm_ret, ret = true;
 
        DBC_REQUIRE(refs >= 0);
 
-       if (refs == 0)
-               ret = cmm_init();
+       if (refs == 0) {
+               cmm_ret = cmm_init();
+               dmm_ret = dmm_init();
+
+               ret = cmm_ret && dmm_ret;
+
+               if (!ret) {
+                       if (cmm_ret)
+                               cmm_exit();
+
+                       if (dmm_ret)
+                               dmm_exit();
+
+               }
+       }
 
        if (ret)
                refs++;
@@ -1065,6 +1118,8 @@ static void store_interface_fxns(struct bridge_drv_interface *drv_fxns,
                STORE_FXN(fxn_brd_setstate, pfn_brd_set_state);
                STORE_FXN(fxn_brd_memcopy, pfn_brd_mem_copy);
                STORE_FXN(fxn_brd_memwrite, pfn_brd_mem_write);
+               STORE_FXN(fxn_brd_memmap, pfn_brd_mem_map);
+               STORE_FXN(fxn_brd_memunmap, pfn_brd_mem_un_map);
                STORE_FXN(fxn_chnl_create, pfn_chnl_create);
                STORE_FXN(fxn_chnl_destroy, pfn_chnl_destroy);
                STORE_FXN(fxn_chnl_open, pfn_chnl_open);
diff --git a/drivers/staging/tidspbridge/pmgr/dmm.c b/drivers/staging/tidspbridge/pmgr/dmm.c
new file mode 100644 (file)
index 0000000..8685233
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * dmm.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * The Dynamic Memory Manager (DMM) module manages the DSP Virtual address
+ * space that can be directly mapped to any MPU buffer or memory region
+ *
+ * Notes:
+ *   Region: Generic memory entitiy having a start address and a size
+ *   Chunk:  Reserved region
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#include <linux/types.h>
+
+/*  ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+
+/*  ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/*  ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/*  ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/sync.h>
+
+/*  ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/proc.h>
+
+/*  ----------------------------------- This */
+#include <dspbridge/dmm.h>
+
+/*  ----------------------------------- Defines, Data Structures, Typedefs */
+#define DMM_ADDR_VIRTUAL(a) \
+       (((struct map_page *)(a) - virtual_mapping_table) * PG_SIZE4K +\
+       dyn_mem_map_beg)
+#define DMM_ADDR_TO_INDEX(a) (((a) - dyn_mem_map_beg) / PG_SIZE4K)
+
+/* DMM Mgr */
+struct dmm_object {
+       /* Dmm Lock is used to serialize access mem manager for
+        * multi-threads. */
+       spinlock_t dmm_lock;    /* Lock to access dmm mgr */
+};
+
+/*  ----------------------------------- Globals */
+static u32 refs;               /* module reference count */
+struct map_page {
+       u32 region_size:15;
+       u32 mapped_size:15;
+       u32 reserved:1;
+       u32 mapped:1;
+};
+
+/*  Create the free list */
+static struct map_page *virtual_mapping_table;
+static u32 free_region;                /* The index of free region */
+static u32 free_size;
+static u32 dyn_mem_map_beg;    /* The Beginning of dynamic memory mapping */
+static u32 table_size;         /* The size of virt and phys pages tables */
+
+/*  ----------------------------------- Function Prototypes */
+static struct map_page *get_region(u32 addr);
+static struct map_page *get_free_region(u32 len);
+static struct map_page *get_mapped_region(u32 addrs);
+
+/*  ======== dmm_create_tables ========
+ *  Purpose:
+ *      Create table to hold the information of physical address
+ *      the buffer pages that is passed by the user, and the table
+ *      to hold the information of the virtual memory that is reserved
+ *      for DSP.
+ */
+int dmm_create_tables(struct dmm_object *dmm_mgr, u32 addr, u32 size)
+{
+       struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+       int status = 0;
+
+       status = dmm_delete_tables(dmm_obj);
+       if (!status) {
+               dyn_mem_map_beg = addr;
+               table_size = PG_ALIGN_HIGH(size, PG_SIZE4K) / PG_SIZE4K;
+               /*  Create the free list */
+               virtual_mapping_table = __vmalloc(table_size *
+                               sizeof(struct map_page), GFP_KERNEL |
+                               __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
+               if (virtual_mapping_table == NULL)
+                       status = -ENOMEM;
+               else {
+                       /* On successful allocation,
+                        * all entries are zero ('free') */
+                       free_region = 0;
+                       free_size = table_size * PG_SIZE4K;
+                       virtual_mapping_table[0].region_size = table_size;
+               }
+       }
+
+       if (status)
+               pr_err("%s: failure, status 0x%x\n", __func__, status);
+
+       return status;
+}
+
+/*
+ *  ======== dmm_create ========
+ *  Purpose:
+ *      Create a dynamic memory manager object.
+ */
+int dmm_create(struct dmm_object **dmm_manager,
+                     struct dev_object *hdev_obj,
+                     const struct dmm_mgrattrs *mgr_attrts)
+{
+       struct dmm_object *dmm_obj = NULL;
+       int status = 0;
+       DBC_REQUIRE(refs > 0);
+       DBC_REQUIRE(dmm_manager != NULL);
+
+       *dmm_manager = NULL;
+       /* create, zero, and tag a cmm mgr object */
+       dmm_obj = kzalloc(sizeof(struct dmm_object), GFP_KERNEL);
+       if (dmm_obj != NULL) {
+               spin_lock_init(&dmm_obj->dmm_lock);
+               *dmm_manager = dmm_obj;
+       } else {
+               status = -ENOMEM;
+       }
+
+       return status;
+}
+
+/*
+ *  ======== dmm_destroy ========
+ *  Purpose:
+ *      Release the communication memory manager resources.
+ */
+int dmm_destroy(struct dmm_object *dmm_mgr)
+{
+       struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+       int status = 0;
+
+       DBC_REQUIRE(refs > 0);
+       if (dmm_mgr) {
+               status = dmm_delete_tables(dmm_obj);
+               if (!status)
+                       kfree(dmm_obj);
+       } else
+               status = -EFAULT;
+
+       return status;
+}
+
+/*
+ *  ======== dmm_delete_tables ========
+ *  Purpose:
+ *      Delete DMM Tables.
+ */
+int dmm_delete_tables(struct dmm_object *dmm_mgr)
+{
+       int status = 0;
+
+       DBC_REQUIRE(refs > 0);
+       /* Delete all DMM tables */
+       if (dmm_mgr)
+               vfree(virtual_mapping_table);
+       else
+               status = -EFAULT;
+       return status;
+}
+
+/*
+ *  ======== dmm_exit ========
+ *  Purpose:
+ *      Discontinue usage of module; free resources when reference count
+ *      reaches 0.
+ */
+void dmm_exit(void)
+{
+       DBC_REQUIRE(refs > 0);
+
+       refs--;
+}
+
+/*
+ *  ======== dmm_get_handle ========
+ *  Purpose:
+ *      Return the dynamic memory manager object for this device.
+ *      This is typically called from the client process.
+ */
+int dmm_get_handle(void *hprocessor, struct dmm_object **dmm_manager)
+{
+       int status = 0;
+       struct dev_object *hdev_obj;
+
+       DBC_REQUIRE(refs > 0);
+       DBC_REQUIRE(dmm_manager != NULL);
+       if (hprocessor != NULL)
+               status = proc_get_dev_object(hprocessor, &hdev_obj);
+       else
+               hdev_obj = dev_get_first();     /* default */
+
+       if (!status)
+               status = dev_get_dmm_mgr(hdev_obj, dmm_manager);
+
+       return status;
+}
+
+/*
+ *  ======== dmm_init ========
+ *  Purpose:
+ *      Initializes private state of DMM module.
+ */
+bool dmm_init(void)
+{
+       bool ret = true;
+
+       DBC_REQUIRE(refs >= 0);
+
+       if (ret)
+               refs++;
+
+       DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
+
+       virtual_mapping_table = NULL;
+       table_size = 0;
+
+       return ret;
+}
+
+/*
+ *  ======== dmm_map_memory ========
+ *  Purpose:
+ *      Add a mapping block to the reserved chunk. DMM assumes that this block
+ *  will be mapped in the DSP/IVA's address space. DMM returns an error if a
+ *  mapping overlaps another one. This function stores the info that will be
+ *  required later while unmapping the block.
+ */
+int dmm_map_memory(struct dmm_object *dmm_mgr, u32 addr, u32 size)
+{
+       struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+       struct map_page *chunk;
+       int status = 0;
+
+       spin_lock(&dmm_obj->dmm_lock);
+       /* Find the Reserved memory chunk containing the DSP block to
+        * be mapped */
+       chunk = (struct map_page *)get_region(addr);
+       if (chunk != NULL) {
+               /* Mark the region 'mapped', leave the 'reserved' info as-is */
+               chunk->mapped = true;
+               chunk->mapped_size = (size / PG_SIZE4K);
+       } else
+               status = -ENOENT;
+       spin_unlock(&dmm_obj->dmm_lock);
+
+       dev_dbg(bridge, "%s dmm_mgr %p, addr %x, size %x\n\tstatus %x, "
+               "chunk %p", __func__, dmm_mgr, addr, size, status, chunk);
+
+       return status;
+}
+
+/*
+ *  ======== dmm_reserve_memory ========
+ *  Purpose:
+ *      Reserve a chunk of virtually contiguous DSP/IVA address space.
+ */
+int dmm_reserve_memory(struct dmm_object *dmm_mgr, u32 size,
+                             u32 *prsv_addr)
+{
+       int status = 0;
+       struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+       struct map_page *node;
+       u32 rsv_addr = 0;
+       u32 rsv_size = 0;
+
+       spin_lock(&dmm_obj->dmm_lock);
+
+       /* Try to get a DSP chunk from the free list */
+       node = get_free_region(size);
+       if (node != NULL) {
+               /*  DSP chunk of given size is available. */
+               rsv_addr = DMM_ADDR_VIRTUAL(node);
+               /* Calculate the number entries to use */
+               rsv_size = size / PG_SIZE4K;
+               if (rsv_size < node->region_size) {
+                       /* Mark remainder of free region */
+                       node[rsv_size].mapped = false;
+                       node[rsv_size].reserved = false;
+                       node[rsv_size].region_size =
+                           node->region_size - rsv_size;
+                       node[rsv_size].mapped_size = 0;
+               }
+               /*  get_region will return first fit chunk. But we only use what
+                  is requested. */
+               node->mapped = false;
+               node->reserved = true;
+               node->region_size = rsv_size;
+               node->mapped_size = 0;
+               /* Return the chunk's starting address */
+               *prsv_addr = rsv_addr;
+       } else
+               /*dSP chunk of given size is not available */
+               status = -ENOMEM;
+
+       spin_unlock(&dmm_obj->dmm_lock);
+
+       dev_dbg(bridge, "%s dmm_mgr %p, size %x, prsv_addr %p\n\tstatus %x, "
+               "rsv_addr %x, rsv_size %x\n", __func__, dmm_mgr, size,
+               prsv_addr, status, rsv_addr, rsv_size);
+
+       return status;
+}
+
+/*
+ *  ======== dmm_un_map_memory ========
+ *  Purpose:
+ *      Remove the mapped block from the reserved chunk.
+ */
+int dmm_un_map_memory(struct dmm_object *dmm_mgr, u32 addr, u32 *psize)
+{
+       struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+       struct map_page *chunk;
+       int status = 0;
+
+       spin_lock(&dmm_obj->dmm_lock);
+       chunk = get_mapped_region(addr);
+       if (chunk == NULL)
+               status = -ENOENT;
+
+       if (!status) {
+               /* Unmap the region */
+               *psize = chunk->mapped_size * PG_SIZE4K;
+               chunk->mapped = false;
+               chunk->mapped_size = 0;
+       }
+       spin_unlock(&dmm_obj->dmm_lock);
+
+       dev_dbg(bridge, "%s: dmm_mgr %p, addr %x, psize %p\n\tstatus %x, "
+               "chunk %p\n", __func__, dmm_mgr, addr, psize, status, chunk);
+
+       return status;
+}
+
+/*
+ *  ======== dmm_un_reserve_memory ========
+ *  Purpose:
+ *      Free a chunk of reserved DSP/IVA address space.
+ */
+int dmm_un_reserve_memory(struct dmm_object *dmm_mgr, u32 rsv_addr)
+{
+       struct dmm_object *dmm_obj = (struct dmm_object *)dmm_mgr;
+       struct map_page *chunk;
+       u32 i;
+       int status = 0;
+       u32 chunk_size;
+
+       spin_lock(&dmm_obj->dmm_lock);
+
+       /* Find the chunk containing the reserved address */
+       chunk = get_mapped_region(rsv_addr);
+       if (chunk == NULL)
+               status = -ENOENT;
+
+       if (!status) {
+               /* Free all the mapped pages for this reserved region */
+               i = 0;
+               while (i < chunk->region_size) {
+                       if (chunk[i].mapped) {
+                               /* Remove mapping from the page tables. */
+                               chunk_size = chunk[i].mapped_size;
+                               /* Clear the mapping flags */
+                               chunk[i].mapped = false;
+                               chunk[i].mapped_size = 0;
+                               i += chunk_size;
+                       } else
+                               i++;
+               }
+               /* Clear the flags (mark the region 'free') */
+               chunk->reserved = false;
+               /* NOTE: We do NOT coalesce free regions here.
+                * Free regions are coalesced in get_region(), as it traverses
+                *the whole mapping table
+                */
+       }
+       spin_unlock(&dmm_obj->dmm_lock);
+
+       dev_dbg(bridge, "%s: dmm_mgr %p, rsv_addr %x\n\tstatus %x chunk %p",
+               __func__, dmm_mgr, rsv_addr, status, chunk);
+
+       return status;
+}
+
+/*
+ *  ======== get_region ========
+ *  Purpose:
+ *      Returns a region containing the specified memory region
+ */
+static struct map_page *get_region(u32 addr)
+{
+       struct map_page *curr_region = NULL;
+       u32 i = 0;
+
+       if (virtual_mapping_table != NULL) {
+               /* find page mapped by this address */
+               i = DMM_ADDR_TO_INDEX(addr);
+               if (i < table_size)
+                       curr_region = virtual_mapping_table + i;
+       }
+
+       dev_dbg(bridge, "%s: curr_region %p, free_region %d, free_size %d\n",
+               __func__, curr_region, free_region, free_size);
+       return curr_region;
+}
+
+/*
+ *  ======== get_free_region ========
+ *  Purpose:
+ *  Returns the requested free region
+ */
+static struct map_page *get_free_region(u32 len)
+{
+       struct map_page *curr_region = NULL;
+       u32 i = 0;
+       u32 region_size = 0;
+       u32 next_i = 0;
+
+       if (virtual_mapping_table == NULL)
+               return curr_region;
+       if (len > free_size) {
+               /* Find the largest free region
+                * (coalesce during the traversal) */
+               while (i < table_size) {
+                       region_size = virtual_mapping_table[i].region_size;
+                       next_i = i + region_size;
+                       if (virtual_mapping_table[i].reserved == false) {
+                               /* Coalesce, if possible */
+                               if (next_i < table_size &&
+                                   virtual_mapping_table[next_i].reserved
+                                   == false) {
+                                       virtual_mapping_table[i].region_size +=
+                                           virtual_mapping_table
+                                           [next_i].region_size;
+                                       continue;
+                               }
+                               region_size *= PG_SIZE4K;
+                               if (region_size > free_size) {
+                                       free_region = i;
+                                       free_size = region_size;
+                               }
+                       }
+                       i = next_i;
+               }
+       }
+       if (len <= free_size) {
+               curr_region = virtual_mapping_table + free_region;
+               free_region += (len / PG_SIZE4K);
+               free_size -= len;
+       }
+       return curr_region;
+}
+
+/*
+ *  ======== get_mapped_region ========
+ *  Purpose:
+ *  Returns the requestedmapped region
+ */
+static struct map_page *get_mapped_region(u32 addrs)
+{
+       u32 i = 0;
+       struct map_page *curr_region = NULL;
+
+       if (virtual_mapping_table == NULL)
+               return curr_region;
+
+       i = DMM_ADDR_TO_INDEX(addrs);
+       if (i < table_size && (virtual_mapping_table[i].mapped ||
+                              virtual_mapping_table[i].reserved))
+               curr_region = virtual_mapping_table + i;
+       return curr_region;
+}
+
+#ifdef DSP_DMM_DEBUG
+u32 dmm_mem_map_dump(struct dmm_object *dmm_mgr)
+{
+       struct map_page *curr_node = NULL;
+       u32 i;
+       u32 freemem = 0;
+       u32 bigsize = 0;
+
+       spin_lock(&dmm_mgr->dmm_lock);
+
+       if (virtual_mapping_table != NULL) {
+               for (i = 0; i < table_size; i +=
+                    virtual_mapping_table[i].region_size) {
+                       curr_node = virtual_mapping_table + i;
+                       if (curr_node->reserved) {
+                               /*printk("RESERVED size = 0x%x, "
+                                  "Map size = 0x%x\n",
+                                  (curr_node->region_size * PG_SIZE4K),
+                                  (curr_node->mapped == false) ? 0 :
+                                  (curr_node->mapped_size * PG_SIZE4K));
+                                */
+                       } else {
+/*                             printk("UNRESERVED size = 0x%x\n",
+                                       (curr_node->region_size * PG_SIZE4K));
+ */
+                               freemem += (curr_node->region_size * PG_SIZE4K);
+                               if (curr_node->region_size > bigsize)
+                                       bigsize = curr_node->region_size;
+                       }
+               }
+       }
+       spin_unlock(&dmm_mgr->dmm_lock);
+       printk(KERN_INFO "Total DSP VA FREE memory = %d Mbytes\n",
+              freemem / (1024 * 1024));
+       printk(KERN_INFO "Total DSP VA USED memory= %d Mbytes \n",
+              (((table_size * PG_SIZE4K) - freemem)) / (1024 * 1024));
+       printk(KERN_INFO "DSP VA - Biggest FREE block = %d Mbytes \n\n",
+              (bigsize * PG_SIZE4K / (1024 * 1024)));
+
+       return 0;
+}
+#endif
index 981551ce4d78684e792957f974a4af39b84b9176..86ca785f191356ef865aac33d035a36e40373327 100644 (file)
@@ -993,10 +993,27 @@ u32 procwrap_register_notify(union trapped_args *args, void *pr_ctxt)
 /*
  * ======== procwrap_reserve_memory ========
  */
-u32 __deprecated procwrap_reserve_memory(union trapped_args *args,
-                                                       void *pr_ctxt)
+u32 procwrap_reserve_memory(union trapped_args *args, void *pr_ctxt)
 {
-       return 0;
+       int status;
+       void *prsv_addr;
+       void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+       if ((args->args_proc_rsvmem.ul_size <= 0) ||
+           (args->args_proc_rsvmem.ul_size & (PG_SIZE4K - 1)) != 0)
+               return -EINVAL;
+
+       status = proc_reserve_memory(hprocessor,
+                                    args->args_proc_rsvmem.ul_size, &prsv_addr,
+                                    pr_ctxt);
+       if (!status) {
+               if (put_user(prsv_addr, args->args_proc_rsvmem.pp_rsv_addr)) {
+                       status = -EINVAL;
+                       proc_un_reserve_memory(args->args_proc_rsvmem.
+                                              hprocessor, prsv_addr, pr_ctxt);
+               }
+       }
+       return status;
 }
 
 /*
@@ -1025,10 +1042,15 @@ u32 procwrap_un_map(union trapped_args *args, void *pr_ctxt)
 /*
  * ======== procwrap_un_reserve_memory ========
  */
-u32 __deprecated procwrap_un_reserve_memory(union trapped_args *args,
-                                                       void *pr_ctxt)
+u32 procwrap_un_reserve_memory(union trapped_args *args, void *pr_ctxt)
 {
-       return 0;
+       int status;
+       void *hprocessor = ((struct process_context *)pr_ctxt)->hprocessor;
+
+       status = proc_un_reserve_memory(hprocessor,
+                                       args->args_proc_unrsvmem.prsv_addr,
+                                       pr_ctxt);
+       return status;
 }
 
 /*
index 91cc168516e5e25f553b3cdb8fe317ea12720b2f..81b1b90135502b52a20d002760decbcd249f3196 100644 (file)
@@ -146,6 +146,7 @@ int drv_remove_all_dmm_res_elements(void *process_ctxt)
        struct process_context *ctxt = (struct process_context *)process_ctxt;
        int status = 0;
        struct dmm_map_object *temp_map, *map_obj;
+       struct dmm_rsv_object *temp_rsv, *rsv_obj;
 
        /* Free DMM mapped memory resources */
        list_for_each_entry_safe(map_obj, temp_map, &ctxt->dmm_map_list, link) {
@@ -155,6 +156,16 @@ int drv_remove_all_dmm_res_elements(void *process_ctxt)
                        pr_err("%s: proc_un_map failed!"
                               " status = 0x%xn", __func__, status);
        }
+
+       /* Free DMM reserved memory resources */
+       list_for_each_entry_safe(rsv_obj, temp_rsv, &ctxt->dmm_rsv_list, link) {
+               status = proc_un_reserve_memory(ctxt->hprocessor, (void *)
+                                               rsv_obj->dsp_reserved_addr,
+                                               ctxt);
+               if (status)
+                       pr_err("%s: proc_un_reserve_memory failed!"
+                              " status = 0x%xn", __func__, status);
+       }
        return status;
 }
 
@@ -732,6 +743,7 @@ static int request_bridge_resources(struct cfg_hostres *res)
        host_res->dw_sys_ctrl_base = ioremap(OMAP_SYSC_BASE, OMAP_SYSC_SIZE);
        dev_dbg(bridge, "dw_mem_base[0] 0x%x\n", host_res->dw_mem_base[0]);
        dev_dbg(bridge, "dw_mem_base[3] 0x%x\n", host_res->dw_mem_base[3]);
+       dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
 
        /* for 24xx base port is not mapping the mamory for DSP
         * internal memory TODO Do a ioremap here */
@@ -785,6 +797,8 @@ int drv_request_bridge_res_dsp(void **phost_resources)
                                                         OMAP_PER_PRM_SIZE);
                host_res->dw_core_pm_base = (u32) ioremap(OMAP_CORE_PRM_BASE,
                                                          OMAP_CORE_PRM_SIZE);
+               host_res->dw_dmmu_base = ioremap(OMAP_DMMU_BASE,
+                                                OMAP_DMMU_SIZE);
 
                dev_dbg(bridge, "dw_mem_base[0] 0x%x\n",
                        host_res->dw_mem_base[0]);
@@ -796,6 +810,7 @@ int drv_request_bridge_res_dsp(void **phost_resources)
                        host_res->dw_mem_base[3]);
                dev_dbg(bridge, "dw_mem_base[4] 0x%x\n",
                        host_res->dw_mem_base[4]);
+               dev_dbg(bridge, "dw_dmmu_base %p\n", host_res->dw_dmmu_base);
 
                shm_size = drv_datap->shm_size;
                if (shm_size >= 0x10000) {
index 34be43fec044da6ed15e3370c7c64963772f7454..324fcdffb3b36d74a1db1830b229f303e936d859 100644 (file)
@@ -509,6 +509,8 @@ static int bridge_open(struct inode *ip, struct file *filp)
                pr_ctxt->res_state = PROC_RES_ALLOCATED;
                spin_lock_init(&pr_ctxt->dmm_map_lock);
                INIT_LIST_HEAD(&pr_ctxt->dmm_map_list);
+               spin_lock_init(&pr_ctxt->dmm_rsv_lock);
+               INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list);
 
                pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL);
                if (pr_ctxt->node_id) {
index a660247f527ac6a6b92725372328aca17af8ff40..1562f3c1281c642af3a854da4de650afb000b362 100644 (file)
@@ -56,6 +56,7 @@
 /*  ----------------------------------- This */
 #include <dspbridge/nodepriv.h>
 #include <dspbridge/node.h>
+#include <dspbridge/dmm.h>
 
 /* Static/Dynamic Loader includes */
 #include <dspbridge/dbll.h>
@@ -316,6 +317,10 @@ int node_allocate(struct proc_object *hprocessor,
        u32 mapped_addr = 0;
        u32 map_attrs = 0x0;
        struct dsp_processorstate proc_state;
+#ifdef DSP_DMM_DEBUG
+       struct dmm_object *dmm_mgr;
+       struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+#endif
 
        void *node_res;
 
@@ -425,12 +430,34 @@ int node_allocate(struct proc_object *hprocessor,
        if (status)
                goto func_cont;
 
+       status = proc_reserve_memory(hprocessor,
+                                    pnode->create_args.asa.task_arg_obj.
+                                    heap_size + PAGE_SIZE,
+                                    (void **)&(pnode->create_args.asa.
+                                       task_arg_obj.udsp_heap_res_addr),
+                                    pr_ctxt);
+       if (status) {
+               pr_err("%s: Failed to reserve memory for heap: 0x%x\n",
+                      __func__, status);
+               goto func_cont;
+       }
+#ifdef DSP_DMM_DEBUG
+       status = dmm_get_handle(p_proc_object, &dmm_mgr);
+       if (!dmm_mgr) {
+               status = DSP_EHANDLE;
+               goto func_cont;
+       }
+
+       dmm_mem_map_dump(dmm_mgr);
+#endif
+
        map_attrs |= DSP_MAPLITTLEENDIAN;
        map_attrs |= DSP_MAPELEMSIZE32;
        map_attrs |= DSP_MAPVIRTUALADDR;
        status = proc_map(hprocessor, (void *)attr_in->pgpp_virt_addr,
                          pnode->create_args.asa.task_arg_obj.heap_size,
-                         NULL, (void **)&mapped_addr, map_attrs,
+                         (void *)pnode->create_args.asa.task_arg_obj.
+                         udsp_heap_res_addr, (void **)&mapped_addr, map_attrs,
                          pr_ctxt);
        if (status)
                pr_err("%s: Failed to map memory for Heap: 0x%x\n",
@@ -2484,7 +2511,11 @@ static void delete_node(struct node_object *hnode,
        struct stream_chnl stream;
        struct node_msgargs node_msg_args;
        struct node_taskargs task_arg_obj;
-
+#ifdef DSP_DMM_DEBUG
+       struct dmm_object *dmm_mgr;
+       struct proc_object *p_proc_object =
+           (struct proc_object *)hnode->hprocessor;
+#endif
        int status;
        if (!hnode)
                goto func_end;
@@ -2545,6 +2576,19 @@ static void delete_node(struct node_object *hnode,
                        status = proc_un_map(hnode->hprocessor, (void *)
                                             task_arg_obj.udsp_heap_addr,
                                             pr_ctxt);
+
+                       status = proc_un_reserve_memory(hnode->hprocessor,
+                                                       (void *)
+                                                       task_arg_obj.
+                                                       udsp_heap_res_addr,
+                                                       pr_ctxt);
+#ifdef DSP_DMM_DEBUG
+                       status = dmm_get_handle(p_proc_object, &dmm_mgr);
+                       if (dmm_mgr)
+                               dmm_mem_map_dump(dmm_mgr);
+                       else
+                               status = DSP_EHANDLE;
+#endif
                }
        }
        if (node_type != NODE_MESSAGE) {
index 7a15a02efedf8b99bfc7c36d187179a096118369..b47d7aa747b1d95181fa228d79dec9ce322aa24f 100644 (file)
@@ -39,6 +39,7 @@
 #include <dspbridge/cod.h>
 #include <dspbridge/dev.h>
 #include <dspbridge/procpriv.h>
+#include <dspbridge/dmm.h>
 
 /*  ----------------------------------- Resource Manager */
 #include <dspbridge/mgr.h>
@@ -51,7 +52,6 @@
 #include <dspbridge/msg.h>
 #include <dspbridge/dspioctl.h>
 #include <dspbridge/drv.h>
-#include <_tiomap.h>
 
 /*  ----------------------------------- This */
 #include <dspbridge/proc.h>
@@ -151,21 +151,34 @@ static struct dmm_map_object *add_mapping_info(struct process_context *pr_ctxt,
        return map_obj;
 }
 
+static int match_exact_map_obj(struct dmm_map_object *map_obj,
+                                       u32 dsp_addr, u32 size)
+{
+       if (map_obj->dsp_addr == dsp_addr && map_obj->size != size)
+               pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
+                               __func__, dsp_addr, map_obj->size, size);
+
+       return map_obj->dsp_addr == dsp_addr &&
+               map_obj->size == size;
+}
+
 static void remove_mapping_information(struct process_context *pr_ctxt,
-                                               u32 dsp_addr)
+                                               u32 dsp_addr, u32 size)
 {
        struct dmm_map_object *map_obj;
 
-       pr_debug("%s: looking for virt 0x%x\n", __func__, dsp_addr);
+       pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
+                                                       dsp_addr, size);
 
        spin_lock(&pr_ctxt->dmm_map_lock);
        list_for_each_entry(map_obj, &pr_ctxt->dmm_map_list, link) {
-               pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x\n",
+               pr_debug("%s: candidate: mpu_addr 0x%x virt 0x%x size 0x%x\n",
                                                        __func__,
                                                        map_obj->mpu_addr,
-                                                       map_obj->dsp_addr);
+                                                       map_obj->dsp_addr,
+                                                       map_obj->size);
 
-               if (map_obj->dsp_addr == dsp_addr) {
+               if (match_exact_map_obj(map_obj, dsp_addr, size)) {
                        pr_debug("%s: match, deleting map info\n", __func__);
                        list_del(&map_obj->link);
                        kfree(map_obj->dma_info.sg);
@@ -1077,6 +1090,7 @@ int proc_load(void *hprocessor, const s32 argc_index,
        s32 cnew_envp;          /* "  " in new_envp[] */
        s32 nproc_id = 0;       /* Anticipate MP version. */
        struct dcd_manager *hdcd_handle;
+       struct dmm_object *dmm_mgr;
        u32 dw_ext_end;
        u32 proc_id;
        int brd_state;
@@ -1267,6 +1281,25 @@ int proc_load(void *hprocessor, const s32 argc_index,
                        if (!status)
                                status = cod_get_sym_value(cod_mgr, EXTEND,
                                                           &dw_ext_end);
+
+                       /* Reset DMM structs and add an initial free chunk */
+                       if (!status) {
+                               status =
+                                   dev_get_dmm_mgr(p_proc_object->hdev_obj,
+                                                   &dmm_mgr);
+                               if (dmm_mgr) {
+                                       /* Set dw_ext_end to DMM START u8
+                                        * address */
+                                       dw_ext_end =
+                                           (dw_ext_end + 1) * DSPWORDSIZE;
+                                       /* DMM memory is from EXT_END */
+                                       status = dmm_create_tables(dmm_mgr,
+                                                                  dw_ext_end,
+                                                                  DMMPOOLSIZE);
+                               } else {
+                                       status = -EFAULT;
+                               }
+                       }
                }
        }
        /* Restore the original argv[0] */
@@ -1319,10 +1352,12 @@ int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
 {
        u32 va_align;
        u32 pa_align;
+       struct dmm_object *dmm_mgr;
        u32 size_align;
        int status = 0;
        struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
        struct dmm_map_object *map_obj;
+       u32 tmp_addr = 0;
 
 #ifdef CONFIG_TIDSPBRIDGE_CACHE_LINE_CHECK
        if ((ul_map_attr & BUFMODE_MASK) != RBUF) {
@@ -1347,30 +1382,33 @@ int proc_map(void *hprocessor, void *pmpu_addr, u32 ul_size,
        }
        /* Critical section */
        mutex_lock(&proc_lock);
+       dmm_get_handle(p_proc_object, &dmm_mgr);
+       if (dmm_mgr)
+               status = dmm_map_memory(dmm_mgr, va_align, size_align);
+       else
+               status = -EFAULT;
 
        /* Add mapping to the page tables. */
        if (!status) {
+
+               /* Mapped address = MSB of VA | LSB of PA */
+               tmp_addr = (va_align | ((u32) pmpu_addr & (PG_SIZE4K - 1)));
                /* mapped memory resource tracking */
-               map_obj = add_mapping_info(pr_ctxt, pa_align, va_align,
+               map_obj = add_mapping_info(pr_ctxt, pa_align, tmp_addr,
                                                size_align);
-               if (!map_obj) {
+               if (!map_obj)
                        status = -ENOMEM;
-               } else {
-                       va_align = user_to_dsp_map(
-                               p_proc_object->hbridge_context->dsp_mmu,
-                               pa_align, va_align, size_align,
-                               map_obj->pages);
-                       if (IS_ERR_VALUE(va_align))
-                               status = (int)va_align;
-               }
+               else
+                       status = (*p_proc_object->intf_fxns->pfn_brd_mem_map)
+                           (p_proc_object->hbridge_context, pa_align, va_align,
+                            size_align, ul_map_attr, map_obj->pages);
        }
        if (!status) {
                /* Mapped address = MSB of VA | LSB of PA */
-               map_obj->dsp_addr = (va_align |
-                                       ((u32)pmpu_addr & (PG_SIZE4K - 1)));
-               *pp_map_addr = (void *)map_obj->dsp_addr;
+               *pp_map_addr = (void *) tmp_addr;
        } else {
-               remove_mapping_information(pr_ctxt, va_align);
+               remove_mapping_information(pr_ctxt, tmp_addr, size_align);
+               dmm_un_map_memory(dmm_mgr, va_align, &size_align);
        }
        mutex_unlock(&proc_lock);
 
@@ -1462,6 +1500,55 @@ func_end:
        return status;
 }
 
+/*
+ *  ======== proc_reserve_memory ========
+ *  Purpose:
+ *      Reserve a virtually contiguous region of DSP address space.
+ */
+int proc_reserve_memory(void *hprocessor, u32 ul_size,
+                              void **pp_rsv_addr,
+                              struct process_context *pr_ctxt)
+{
+       struct dmm_object *dmm_mgr;
+       int status = 0;
+       struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+       struct dmm_rsv_object *rsv_obj;
+
+       if (!p_proc_object) {
+               status = -EFAULT;
+               goto func_end;
+       }
+
+       status = dmm_get_handle(p_proc_object, &dmm_mgr);
+       if (!dmm_mgr) {
+               status = -EFAULT;
+               goto func_end;
+       }
+
+       status = dmm_reserve_memory(dmm_mgr, ul_size, (u32 *) pp_rsv_addr);
+       if (status != 0)
+               goto func_end;
+
+       /*
+        * A successful reserve should be followed by insertion of rsv_obj
+        * into dmm_rsv_list, so that reserved memory resource tracking
+        * remains uptodate
+        */
+       rsv_obj = kmalloc(sizeof(struct dmm_rsv_object), GFP_KERNEL);
+       if (rsv_obj) {
+               rsv_obj->dsp_reserved_addr = (u32) *pp_rsv_addr;
+               spin_lock(&pr_ctxt->dmm_rsv_lock);
+               list_add(&rsv_obj->link, &pr_ctxt->dmm_rsv_list);
+               spin_unlock(&pr_ctxt->dmm_rsv_lock);
+       }
+
+func_end:
+       dev_dbg(bridge, "%s: hprocessor: 0x%p ul_size: 0x%x pp_rsv_addr: 0x%p "
+               "status 0x%x\n", __func__, hprocessor,
+               ul_size, pp_rsv_addr, status);
+       return status;
+}
+
 /*
  *  ======== proc_start ========
  *  Purpose:
@@ -1610,7 +1697,9 @@ int proc_un_map(void *hprocessor, void *map_addr,
 {
        int status = 0;
        struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+       struct dmm_object *dmm_mgr;
        u32 va_align;
+       u32 size_align;
 
        va_align = PG_ALIGN_LOW((u32) map_addr, PG_SIZE4K);
        if (!p_proc_object) {
@@ -1618,11 +1707,24 @@ int proc_un_map(void *hprocessor, void *map_addr,
                goto func_end;
        }
 
+       status = dmm_get_handle(hprocessor, &dmm_mgr);
+       if (!dmm_mgr) {
+               status = -EFAULT;
+               goto func_end;
+       }
+
        /* Critical section */
        mutex_lock(&proc_lock);
+       /*
+        * Update DMM structures. Get the size to unmap.
+        * This function returns error if the VA is not mapped
+        */
+       status = dmm_un_map_memory(dmm_mgr, (u32) va_align, &size_align);
        /* Remove mapping from the page tables. */
-       status = user_to_dsp_unmap(p_proc_object->hbridge_context->dsp_mmu,
-                                                               va_align);
+       if (!status) {
+               status = (*p_proc_object->intf_fxns->pfn_brd_mem_un_map)
+                   (p_proc_object->hbridge_context, va_align, size_align);
+       }
 
        mutex_unlock(&proc_lock);
        if (status)
@@ -1633,7 +1735,7 @@ int proc_un_map(void *hprocessor, void *map_addr,
         * from dmm_map_list, so that mapped memory resource tracking
         * remains uptodate
         */
-       remove_mapping_information(pr_ctxt, (u32) map_addr);
+       remove_mapping_information(pr_ctxt, (u32) map_addr, size_align);
 
 func_end:
        dev_dbg(bridge, "%s: hprocessor: 0x%p map_addr: 0x%p status: 0x%x\n",
@@ -1641,6 +1743,55 @@ func_end:
        return status;
 }
 
+/*
+ *  ======== proc_un_reserve_memory ========
+ *  Purpose:
+ *      Frees a previously reserved region of DSP address space.
+ */
+int proc_un_reserve_memory(void *hprocessor, void *prsv_addr,
+                                 struct process_context *pr_ctxt)
+{
+       struct dmm_object *dmm_mgr;
+       int status = 0;
+       struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
+       struct dmm_rsv_object *rsv_obj;
+
+       if (!p_proc_object) {
+               status = -EFAULT;
+               goto func_end;
+       }
+
+       status = dmm_get_handle(p_proc_object, &dmm_mgr);
+       if (!dmm_mgr) {
+               status = -EFAULT;
+               goto func_end;
+       }
+
+       status = dmm_un_reserve_memory(dmm_mgr, (u32) prsv_addr);
+       if (status != 0)
+               goto func_end;
+
+       /*
+        * A successful unreserve should be followed by removal of rsv_obj
+        * from dmm_rsv_list, so that reserved memory resource tracking
+        * remains uptodate
+        */
+       spin_lock(&pr_ctxt->dmm_rsv_lock);
+       list_for_each_entry(rsv_obj, &pr_ctxt->dmm_rsv_list, link) {
+               if (rsv_obj->dsp_reserved_addr == (u32) prsv_addr) {
+                       list_del(&rsv_obj->link);
+                       kfree(rsv_obj);
+                       break;
+               }
+       }
+       spin_unlock(&pr_ctxt->dmm_rsv_lock);
+
+func_end:
+       dev_dbg(bridge, "%s: hprocessor: 0x%p prsv_addr: 0x%p status: 0x%x\n",
+               __func__, hprocessor, prsv_addr, status);
+       return status;
+}
+
 /*
  *  ======== = proc_monitor ======== ==
  *  Purpose:
index 9ec82796634ecf50cbd5da43dd8b30b0eddc3706..c5690b2a89244769f6af1bfc4b061f663599e32c 100644 (file)
@@ -1032,6 +1032,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
        struct tm6000_fh   *fh=priv;
        struct tm6000_core *dev = fh->dev;
 
+       dev->norm = *norm;
        rc = tm6000_init_analog_mode(dev);
 
        fh->width  = dev->width;
index 5969e848d297ea44951a8c7418e09d74bfd6422e..fed25105970a94d06ca185fa81603f79968d67f8 100644 (file)
@@ -887,7 +887,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
 
                struct fb_deferred_io *fbdefio;
 
-               fbdefio = kmalloc(GFP_KERNEL, sizeof(struct fb_deferred_io));
+               fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
 
                if (fbdefio) {
                        fbdefio->delay = DL_DEFIO_WRITE_DELAY;
index e992d5d9e15bc13e80031e99591f92c1e62357c0..7cc3d2407d1b604633a928ceb3b2593df1cd08af 100644 (file)
@@ -1675,13 +1675,14 @@ static int  device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
 
                {
                        char essid[IW_ESSID_MAX_SIZE+1];
-                       if (wrq->u.essid.pointer)
+                       if (wrq->u.essid.pointer) {
                                rc = iwctl_giwessid(dev, NULL,
                                                    &(wrq->u.essid), essid);
                                if (copy_to_user(wrq->u.essid.pointer,
                                                         essid,
                                                         wrq->u.essid.length) )
                                        rc = -EFAULT;
+                       }
                }
                break;
 
index 5a2197012065a492d073e16308d222a50aa00a25..7777d9a60a5238db70721f38c2c9c5ee41f07b62 100644 (file)
@@ -1417,7 +1417,6 @@ cy_as_usb_set_enum_config(cy_as_device_handle handle,
         */
        bus_mask   = 0;
        media_mask = 0;
-       media_mask = 0;
        for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
                for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
                        if (config_p->devices_to_enumerate[bus][device] ==
index 4af83d5318f2705d551cd65fc898645e217e339d..6a71f52c59b1f0a575b8ba69aeac20a9fd2c733a 100644 (file)
@@ -139,7 +139,7 @@ exit:
 }
 
 int prism2_add_key(struct wiphy *wiphy, struct net_device *dev,
-                  u8 key_index, const u8 *mac_addr,
+                  u8 key_index, bool pairwise, const u8 *mac_addr,
                   struct key_params *params)
 {
        wlandevice_t *wlandev = dev->ml_priv;
@@ -198,7 +198,7 @@ exit:
 }
 
 int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
-                  u8 key_index, const u8 *mac_addr, void *cookie,
+                  u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie,
                   void (*callback)(void *cookie, struct key_params*))
 {
        wlandevice_t *wlandev = dev->ml_priv;
@@ -227,7 +227,7 @@ int prism2_get_key(struct wiphy *wiphy, struct net_device *dev,
 }
 
 int prism2_del_key(struct wiphy *wiphy, struct net_device *dev,
-                  u8 key_index, const u8 *mac_addr)
+                  u8 key_index, bool pairwise, const u8 *mac_addr)
 {
        wlandevice_t *wlandev = dev->ml_priv;
        u32 did;
index aa1792c8429ea4c049868f40f9374d9e326a3743..b7b4a733b467f69b95e864d41dcb1f4af79db8d7 100644 (file)
@@ -522,8 +522,8 @@ static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr)
                if (copy_to_user(useraddr, &edata, sizeof(edata)))
                        return -EFAULT;
                return 0;
-       }
 #endif
+       }
 
        return -EOPNOTSUPP;
 }
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
new file mode 100644 (file)
index 0000000..c43ef48
--- /dev/null
@@ -0,0 +1,11 @@
+obj-y                          += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
+                                  tty_buffer.o tty_port.o tty_mutex.o
+obj-$(CONFIG_LEGACY_PTYS)      += pty.o
+obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-$(CONFIG_AUDIT)            += tty_audit.o
+obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
+obj-$(CONFIG_N_HDLC)           += n_hdlc.o
+obj-$(CONFIG_N_GSM)            += n_gsm.o
+obj-$(CONFIG_R3964)            += n_r3964.o
+
+obj-y                          += vt/
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
new file mode 100644 (file)
index 0000000..81b4658
--- /dev/null
@@ -0,0 +1,2764 @@
+/*
+ * n_gsm.c GSM 0710 tty multiplexor
+ * Copyright (c) 2009/10 Intel Corporation
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *     * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
+ *
+ * TO DO:
+ *     Mostly done:    ioctls for setting modes/timing
+ *     Partly done:    hooks so you can pull off frames to non tty devs
+ *     Restart DLCI 0 when it closes ?
+ *     Test basic encoding
+ *     Improve the tx engine
+ *     Resolve tx side locking by adding a queue_head and routing
+ *             all control traffic via it
+ *     General tidy/document
+ *     Review the locking/move to refcounts more (mux now moved to an
+ *             alloc/free model ready)
+ *     Use newest tty open/close port helpers and install hooks
+ *     What to do about power functions ?
+ *     Termios setting and negotiation
+ *     Do we need a 'which mux are you' ioctl to correlate mux and tty sets
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/tty_flip.h>
+#include <linux/tty_driver.h>
+#include <linux/serial.h>
+#include <linux/kfifo.h>
+#include <linux/skbuff.h>
+#include <linux/gsmmux.h>
+
+static int debug;
+module_param(debug, int, 0600);
+
+#define T1     (HZ/10)
+#define T2     (HZ/3)
+#define N2     3
+
+/* Use long timers for testing at low speed with debug on */
+#ifdef DEBUG_TIMING
+#define T1     HZ
+#define T2     (2 * HZ)
+#endif
+
+/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
+   limits so this is plenty */
+#define MAX_MRU 512
+#define MAX_MTU 512
+
+/*
+ *     Each block of data we have queued to go out is in the form of
+ *     a gsm_msg which holds everything we need in a link layer independant
+ *     format
+ */
+
+struct gsm_msg {
+       struct gsm_msg *next;
+       u8 addr;                /* DLCI address + flags */
+       u8 ctrl;                /* Control byte + flags */
+       unsigned int len;       /* Length of data block (can be zero) */
+       unsigned char *data;    /* Points into buffer but not at the start */
+       unsigned char buffer[0];
+};
+
+/*
+ *     Each active data link has a gsm_dlci structure associated which ties
+ *     the link layer to an optional tty (if the tty side is open). To avoid
+ *     complexity right now these are only ever freed up when the mux is
+ *     shut down.
+ *
+ *     At the moment we don't free DLCI objects until the mux is torn down
+ *     this avoid object life time issues but might be worth review later.
+ */
+
+struct gsm_dlci {
+       struct gsm_mux *gsm;
+       int addr;
+       int state;
+#define DLCI_CLOSED            0
+#define DLCI_OPENING           1       /* Sending SABM not seen UA */
+#define DLCI_OPEN              2       /* SABM/UA complete */
+#define DLCI_CLOSING           3       /* Sending DISC not seen UA/DM */
+
+       /* Link layer */
+       spinlock_t lock;        /* Protects the internal state */
+       struct timer_list t1;   /* Retransmit timer for SABM and UA */
+       int retries;
+       /* Uplink tty if active */
+       struct tty_port port;   /* The tty bound to this DLCI if there is one */
+       struct kfifo *fifo;     /* Queue fifo for the DLCI */
+       struct kfifo _fifo;     /* For new fifo API porting only */
+       int adaption;           /* Adaption layer in use */
+       u32 modem_rx;           /* Our incoming virtual modem lines */
+       u32 modem_tx;           /* Our outgoing modem lines */
+       int dead;               /* Refuse re-open */
+       /* Flow control */
+       int throttled;          /* Private copy of throttle state */
+       int constipated;        /* Throttle status for outgoing */
+       /* Packetised I/O */
+       struct sk_buff *skb;    /* Frame being sent */
+       struct sk_buff_head skb_list;   /* Queued frames */
+       /* Data handling callback */
+       void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
+};
+
+/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
+
+#define NUM_DLCI               64
+
+/*
+ *     DLCI 0 is used to pass control blocks out of band of the data
+ *     flow (and with a higher link priority). One command can be outstanding
+ *     at a time and we use this structure to manage them. They are created
+ *     and destroyed by the user context, and updated by the receive paths
+ *     and timers
+ */
+
+struct gsm_control {
+       u8 cmd;         /* Command we are issuing */
+       u8 *data;       /* Data for the command in case we retransmit */
+       int len;        /* Length of block for retransmission */
+       int done;       /* Done flag */
+       int error;      /* Error if any */
+};
+
+/*
+ *     Each GSM mux we have is represented by this structure. If we are
+ *     operating as an ldisc then we use this structure as our ldisc
+ *     state. We need to sort out lifetimes and locking with respect
+ *     to the gsm mux array. For now we don't free DLCI objects that
+ *     have been instantiated until the mux itself is terminated.
+ *
+ *     To consider further: tty open versus mux shutdown.
+ */
+
+struct gsm_mux {
+       struct tty_struct *tty;         /* The tty our ldisc is bound to */
+       spinlock_t lock;
+
+       /* Events on the GSM channel */
+       wait_queue_head_t event;
+
+       /* Bits for GSM mode decoding */
+
+       /* Framing Layer */
+       unsigned char *buf;
+       int state;
+#define GSM_SEARCH             0
+#define GSM_START              1
+#define GSM_ADDRESS            2
+#define GSM_CONTROL            3
+#define GSM_LEN                        4
+#define GSM_DATA               5
+#define GSM_FCS                        6
+#define GSM_OVERRUN            7
+       unsigned int len;
+       unsigned int address;
+       unsigned int count;
+       int escape;
+       int encoding;
+       u8 control;
+       u8 fcs;
+       u8 *txframe;                    /* TX framing buffer */
+
+       /* Methods for the receiver side */
+       void (*receive)(struct gsm_mux *gsm, u8 ch);
+       void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
+       /* And transmit side */
+       int (*output)(struct gsm_mux *mux, u8 *data, int len);
+
+       /* Link Layer */
+       unsigned int mru;
+       unsigned int mtu;
+       int initiator;                  /* Did we initiate connection */
+       int dead;                       /* Has the mux been shut down */
+       struct gsm_dlci *dlci[NUM_DLCI];
+       int constipated;                /* Asked by remote to shut up */
+
+       spinlock_t tx_lock;
+       unsigned int tx_bytes;          /* TX data outstanding */
+#define TX_THRESH_HI           8192
+#define TX_THRESH_LO           2048
+       struct gsm_msg *tx_head;        /* Pending data packets */
+       struct gsm_msg *tx_tail;
+
+       /* Control messages */
+       struct timer_list t2_timer;     /* Retransmit timer for commands */
+       int cretries;                   /* Command retry counter */
+       struct gsm_control *pending_cmd;/* Our current pending command */
+       spinlock_t control_lock;        /* Protects the pending command */
+
+       /* Configuration */
+       int adaption;           /* 1 or 2 supported */
+       u8 ftype;               /* UI or UIH */
+       int t1, t2;             /* Timers in 1/100th of a sec */
+       int n2;                 /* Retry count */
+
+       /* Statistics (not currently exposed) */
+       unsigned long bad_fcs;
+       unsigned long malformed;
+       unsigned long io_error;
+       unsigned long bad_size;
+       unsigned long unsupported;
+};
+
+
+/*
+ *     Mux objects - needed so that we can translate a tty index into the
+ *     relevant mux and DLCI.
+ */
+
+#define MAX_MUX                4                       /* 256 minors */
+static struct gsm_mux *gsm_mux[MAX_MUX];       /* GSM muxes */
+static spinlock_t gsm_mux_lock;
+
+/*
+ *     This section of the driver logic implements the GSM encodings
+ *     both the basic and the 'advanced'. Reliable transport is not
+ *     supported.
+ */
+
+#define CR                     0x02
+#define EA                     0x01
+#define        PF                      0x10
+
+/* I is special: the rest are ..*/
+#define RR                     0x01
+#define UI                     0x03
+#define RNR                    0x05
+#define REJ                    0x09
+#define DM                     0x0F
+#define SABM                   0x2F
+#define DISC                   0x43
+#define UA                     0x63
+#define        UIH                     0xEF
+
+/* Channel commands */
+#define CMD_NSC                        0x09
+#define CMD_TEST               0x11
+#define CMD_PSC                        0x21
+#define CMD_RLS                        0x29
+#define CMD_FCOFF              0x31
+#define CMD_PN                 0x41
+#define CMD_RPN                        0x49
+#define CMD_FCON               0x51
+#define CMD_CLD                        0x61
+#define CMD_SNC                        0x69
+#define CMD_MSC                        0x71
+
+/* Virtual modem bits */
+#define MDM_FC                 0x01
+#define MDM_RTC                        0x02
+#define MDM_RTR                        0x04
+#define MDM_IC                 0x20
+#define MDM_DV                 0x40
+
+#define GSM0_SOF               0xF9
+#define GSM1_SOF               0x7E
+#define GSM1_ESCAPE            0x7D
+#define GSM1_ESCAPE_BITS       0x20
+#define XON                    0x11
+#define XOFF                   0x13
+
+static const struct tty_port_operations gsm_port_ops;
+
+/*
+ *     CRC table for GSM 0710
+ */
+
+static const u8 gsm_fcs8[256] = {
+       0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
+       0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+       0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
+       0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+       0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
+       0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+       0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
+       0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+       0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
+       0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+       0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
+       0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+       0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
+       0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+       0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
+       0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+       0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
+       0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+       0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
+       0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+       0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
+       0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+       0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
+       0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+       0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
+       0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+       0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
+       0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+       0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
+       0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+       0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
+       0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+#define INIT_FCS       0xFF
+#define GOOD_FCS       0xCF
+
+/**
+ *     gsm_fcs_add     -       update FCS
+ *     @fcs: Current FCS
+ *     @c: Next data
+ *
+ *     Update the FCS to include c. Uses the algorithm in the specification
+ *     notes.
+ */
+
+static inline u8 gsm_fcs_add(u8 fcs, u8 c)
+{
+       return gsm_fcs8[fcs ^ c];
+}
+
+/**
+ *     gsm_fcs_add_block       -       update FCS for a block
+ *     @fcs: Current FCS
+ *     @c: buffer of data
+ *     @len: length of buffer
+ *
+ *     Update the FCS to include c. Uses the algorithm in the specification
+ *     notes.
+ */
+
+static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
+{
+       while (len--)
+               fcs = gsm_fcs8[fcs ^ *c++];
+       return fcs;
+}
+
+/**
+ *     gsm_read_ea             -       read a byte into an EA
+ *     @val: variable holding value
+ *     c: byte going into the EA
+ *
+ *     Processes one byte of an EA. Updates the passed variable
+ *     and returns 1 if the EA is now completely read
+ */
+
+static int gsm_read_ea(unsigned int *val, u8 c)
+{
+       /* Add the next 7 bits into the value */
+       *val <<= 7;
+       *val |= c >> 1;
+       /* Was this the last byte of the EA 1 = yes*/
+       return c & EA;
+}
+
+/**
+ *     gsm_encode_modem        -       encode modem data bits
+ *     @dlci: DLCI to encode from
+ *
+ *     Returns the correct GSM encoded modem status bits (6 bit field) for
+ *     the current status of the DLCI and attached tty object
+ */
+
+static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
+{
+       u8 modembits = 0;
+       /* FC is true flow control not modem bits */
+       if (dlci->throttled)
+               modembits |= MDM_FC;
+       if (dlci->modem_tx & TIOCM_DTR)
+               modembits |= MDM_RTC;
+       if (dlci->modem_tx & TIOCM_RTS)
+               modembits |= MDM_RTR;
+       if (dlci->modem_tx & TIOCM_RI)
+               modembits |= MDM_IC;
+       if (dlci->modem_tx & TIOCM_CD)
+               modembits |= MDM_DV;
+       return modembits;
+}
+
+/**
+ *     gsm_print_packet        -       display a frame for debug
+ *     @hdr: header to print before decode
+ *     @addr: address EA from the frame
+ *     @cr: C/R bit from the frame
+ *     @control: control including PF bit
+ *     @data: following data bytes
+ *     @dlen: length of data
+ *
+ *     Displays a packet in human readable format for debugging purposes. The
+ *     style is based on amateur radio LAP-B dump display.
+ */
+
+static void gsm_print_packet(const char *hdr, int addr, int cr,
+                                       u8 control, const u8 *data, int dlen)
+{
+       if (!(debug & 1))
+               return;
+
+       printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
+
+       switch (control & ~PF) {
+       case SABM:
+               printk(KERN_CONT "SABM");
+               break;
+       case UA:
+               printk(KERN_CONT "UA");
+               break;
+       case DISC:
+               printk(KERN_CONT "DISC");
+               break;
+       case DM:
+               printk(KERN_CONT "DM");
+               break;
+       case UI:
+               printk(KERN_CONT "UI");
+               break;
+       case UIH:
+               printk(KERN_CONT "UIH");
+               break;
+       default:
+               if (!(control & 0x01)) {
+                       printk(KERN_CONT "I N(S)%d N(R)%d",
+                               (control & 0x0E) >> 1, (control & 0xE)>> 5);
+               } else switch (control & 0x0F) {
+               case RR:
+                       printk("RR(%d)", (control & 0xE0) >> 5);
+                       break;
+               case RNR:
+                       printk("RNR(%d)", (control & 0xE0) >> 5);
+                       break;
+               case REJ:
+                       printk("REJ(%d)", (control & 0xE0) >> 5);
+                       break;
+               default:
+                       printk(KERN_CONT "[%02X]", control);
+               }
+       }
+
+       if (control & PF)
+               printk(KERN_CONT "(P)");
+       else
+               printk(KERN_CONT "(F)");
+
+       if (dlen) {
+               int ct = 0;
+               while (dlen--) {
+                       if (ct % 8 == 0)
+                               printk(KERN_CONT "\n    ");
+                       printk(KERN_CONT "%02X ", *data++);
+                       ct++;
+               }
+       }
+       printk(KERN_CONT "\n");
+}
+
+
+/*
+ *     Link level transmission side
+ */
+
+/**
+ *     gsm_stuff_packet        -       bytestuff a packet
+ *     @ibuf: input
+ *     @obuf: output
+ *     @len: length of input
+ *
+ *     Expand a buffer by bytestuffing it. The worst case size change
+ *     is doubling and the caller is responsible for handing out
+ *     suitable sized buffers.
+ */
+
+static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
+{
+       int olen = 0;
+       while (len--) {
+               if (*input == GSM1_SOF || *input == GSM1_ESCAPE
+                   || *input == XON || *input == XOFF) {
+                       *output++ = GSM1_ESCAPE;
+                       *output++ = *input++ ^ GSM1_ESCAPE_BITS;
+                       olen++;
+               } else
+                       *output++ = *input++;
+               olen++;
+       }
+       return olen;
+}
+
+static void hex_packet(const unsigned char *p, int len)
+{
+       int i;
+       for (i = 0; i < len; i++) {
+               if (i && (i % 16) == 0)
+                       printk("\n");
+               printk("%02X ", *p++);
+       }
+       printk("\n");
+}
+
+/**
+ *     gsm_send        -       send a control frame
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @cr: command/response bit
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a control frame. These do not go via the
+ *     queueing logic as they should be transmitted ahead of data when
+ *     they are needed.
+ *
+ *     FIXME: Lock versus data TX path
+ */
+
+static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
+{
+       int len;
+       u8 cbuf[10];
+       u8 ibuf[3];
+
+       switch (gsm->encoding) {
+       case 0:
+               cbuf[0] = GSM0_SOF;
+               cbuf[1] = (addr << 2) | (cr << 1) | EA;
+               cbuf[2] = control;
+               cbuf[3] = EA;   /* Length of data = 0 */
+               cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
+               cbuf[5] = GSM0_SOF;
+               len = 6;
+               break;
+       case 1:
+       case 2:
+               /* Control frame + packing (but not frame stuffing) in mode 1 */
+               ibuf[0] = (addr << 2) | (cr << 1) | EA;
+               ibuf[1] = control;
+               ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
+               /* Stuffing may double the size worst case */
+               len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
+               /* Now add the SOF markers */
+               cbuf[0] = GSM1_SOF;
+               cbuf[len + 1] = GSM1_SOF;
+               /* FIXME: we can omit the lead one in many cases */
+               len += 2;
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+       gsm->output(gsm, cbuf, len);
+       gsm_print_packet("-->", addr, cr, control, NULL, 0);
+}
+
+/**
+ *     gsm_response    -       send a control response
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a link level response frame.
+ */
+
+static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
+{
+       gsm_send(gsm, addr, 0, control);
+}
+
+/**
+ *     gsm_command     -       send a control command
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a link level command frame.
+ */
+
+static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
+{
+       gsm_send(gsm, addr, 1, control);
+}
+
+/* Data transmission */
+
+#define HDR_LEN                6       /* ADDR CTRL [LEN.2] DATA FCS */
+
+/**
+ *     gsm_data_alloc          -       allocate data frame
+ *     @gsm: GSM mux
+ *     @addr: DLCI address
+ *     @len: length excluding header and FCS
+ *     @ctrl: control byte
+ *
+ *     Allocate a new data buffer for sending frames with data. Space is left
+ *     at the front for header bytes but that is treated as an implementation
+ *     detail and not for the high level code to use
+ */
+
+static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
+                                                               u8 ctrl)
+{
+       struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
+                                                               GFP_ATOMIC);
+       if (m == NULL)
+               return NULL;
+       m->data = m->buffer + HDR_LEN - 1;      /* Allow for FCS */
+       m->len = len;
+       m->addr = addr;
+       m->ctrl = ctrl;
+       m->next = NULL;
+       return m;
+}
+
+/**
+ *     gsm_data_kick           -       poke the queue
+ *     @gsm: GSM Mux
+ *
+ *     The tty device has called us to indicate that room has appeared in
+ *     the transmit queue. Ram more data into the pipe if we have any
+ *
+ *     FIXME: lock against link layer control transmissions
+ */
+
+static void gsm_data_kick(struct gsm_mux *gsm)
+{
+       struct gsm_msg *msg = gsm->tx_head;
+       int len;
+       int skip_sof = 0;
+
+       /* FIXME: We need to apply this solely to data messages */
+       if (gsm->constipated)
+               return;
+
+       while (gsm->tx_head != NULL) {
+               msg = gsm->tx_head;
+               if (gsm->encoding != 0) {
+                       gsm->txframe[0] = GSM1_SOF;
+                       len = gsm_stuff_frame(msg->data,
+                                               gsm->txframe + 1, msg->len);
+                       gsm->txframe[len + 1] = GSM1_SOF;
+                       len += 2;
+               } else {
+                       gsm->txframe[0] = GSM0_SOF;
+                       memcpy(gsm->txframe + 1 , msg->data, msg->len);
+                       gsm->txframe[msg->len + 1] = GSM0_SOF;
+                       len = msg->len + 2;
+               }
+
+               if (debug & 4) {
+                       printk("gsm_data_kick: \n");
+                       hex_packet(gsm->txframe, len);
+               }
+
+               if (gsm->output(gsm, gsm->txframe + skip_sof,
+                                               len - skip_sof) < 0)
+                       break;
+               /* FIXME: Can eliminate one SOF in many more cases */
+               gsm->tx_head = msg->next;
+               if (gsm->tx_head == NULL)
+                       gsm->tx_tail = NULL;
+               gsm->tx_bytes -= msg->len;
+               kfree(msg);
+               /* For a burst of frames skip the extra SOF within the
+                  burst */
+               skip_sof = 1;
+       }
+}
+
+/**
+ *     __gsm_data_queue                -       queue a UI or UIH frame
+ *     @dlci: DLCI sending the data
+ *     @msg: message queued
+ *
+ *     Add data to the transmit queue and try and get stuff moving
+ *     out of the mux tty if not already doing so. The Caller must hold
+ *     the gsm tx lock.
+ */
+
+static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       u8 *dp = msg->data;
+       u8 *fcs = dp + msg->len;
+
+       /* Fill in the header */
+       if (gsm->encoding == 0) {
+               if (msg->len < 128)
+                       *--dp = (msg->len << 1) | EA;
+               else {
+                       *--dp = ((msg->len & 127) << 1) | EA;
+                       *--dp = (msg->len >> 6) & 0xfe;
+               }
+       }
+
+       *--dp = msg->ctrl;
+       if (gsm->initiator)
+               *--dp = (msg->addr << 2) | 2 | EA;
+       else
+               *--dp = (msg->addr << 2) | EA;
+       *fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
+       /* Ugly protocol layering violation */
+       if (msg->ctrl == UI || msg->ctrl == (UI|PF))
+               *fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
+       *fcs = 0xFF - *fcs;
+
+       gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
+                                                       msg->data, msg->len);
+
+       /* Move the header back and adjust the length, also allow for the FCS
+          now tacked on the end */
+       msg->len += (msg->data - dp) + 1;
+       msg->data = dp;
+
+       /* Add to the actual output queue */
+       if (gsm->tx_tail)
+               gsm->tx_tail->next = msg;
+       else
+               gsm->tx_head = msg;
+       gsm->tx_tail = msg;
+       gsm->tx_bytes += msg->len;
+       gsm_data_kick(gsm);
+}
+
+/**
+ *     gsm_data_queue          -       queue a UI or UIH frame
+ *     @dlci: DLCI sending the data
+ *     @msg: message queued
+ *
+ *     Add data to the transmit queue and try and get stuff moving
+ *     out of the mux tty if not already doing so. Take the
+ *     the gsm tx lock and dlci lock.
+ */
+
+static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       __gsm_data_queue(dlci, msg);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+}
+
+/**
+ *     gsm_dlci_data_output    -       try and push data out of a DLCI
+ *     @gsm: mux
+ *     @dlci: the DLCI to pull data from
+ *
+ *     Pull data from a DLCI and send it into the transmit queue if there
+ *     is data. Keep to the MRU of the mux. This path handles the usual tty
+ *     interface which is a byte stream with optional modem data.
+ *
+ *     Caller must hold the tx_lock of the mux.
+ */
+
+static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
+{
+       struct gsm_msg *msg;
+       u8 *dp;
+       int len, size;
+       int h = dlci->adaption - 1;
+
+       len = kfifo_len(dlci->fifo);
+       if (len == 0)
+               return 0;
+
+       /* MTU/MRU count only the data bits */
+       if (len > gsm->mtu)
+               len = gsm->mtu;
+
+       size = len + h;
+
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+       if (msg == NULL)
+               return -ENOMEM;
+       dp = msg->data;
+       switch (dlci->adaption) {
+       case 1: /* Unstructured */
+               break;
+       case 2: /* Unstructed with modem bits. Always one byte as we never
+                  send inline break data */
+               *dp += gsm_encode_modem(dlci);
+               len--;
+               break;
+       }
+       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
+       __gsm_data_queue(dlci, msg);
+       /* Bytes of data we used up */
+       return size;
+}
+
+/**
+ *     gsm_dlci_data_output_framed  -  try and push data out of a DLCI
+ *     @gsm: mux
+ *     @dlci: the DLCI to pull data from
+ *
+ *     Pull data from a DLCI and send it into the transmit queue if there
+ *     is data. Keep to the MRU of the mux. This path handles framed data
+ *     queued as skbuffs to the DLCI.
+ *
+ *     Caller must hold the tx_lock of the mux.
+ */
+
+static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
+                                               struct gsm_dlci *dlci)
+{
+       struct gsm_msg *msg;
+       u8 *dp;
+       int len, size;
+       int last = 0, first = 0;
+       int overhead = 0;
+
+       /* One byte per frame is used for B/F flags */
+       if (dlci->adaption == 4)
+               overhead = 1;
+
+       /* dlci->skb is locked by tx_lock */
+       if (dlci->skb == NULL) {
+               dlci->skb = skb_dequeue(&dlci->skb_list);
+               if (dlci->skb == NULL)
+                       return 0;
+               first = 1;
+       }
+       len = dlci->skb->len + overhead;
+
+       /* MTU/MRU count only the data bits */
+       if (len > gsm->mtu) {
+               if (dlci->adaption == 3) {
+                       /* Over long frame, bin it */
+                       kfree_skb(dlci->skb);
+                       dlci->skb = NULL;
+                       return 0;
+               }
+               len = gsm->mtu;
+       } else
+               last = 1;
+
+       size = len + overhead;
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+       if (msg == NULL)
+               return -ENOMEM;
+       dp = msg->data;
+
+       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
+               /* Flag byte to carry the start/end info */
+               *dp++ = last << 7 | first << 6 | 1;     /* EA */
+               len--;
+       }
+       memcpy(dp, skb_pull(dlci->skb, len), len);
+       __gsm_data_queue(dlci, msg);
+       if (last)
+               dlci->skb = NULL;
+       return size;
+}
+
+/**
+ *     gsm_dlci_data_sweep             -       look for data to send
+ *     @gsm: the GSM mux
+ *
+ *     Sweep the GSM mux channels in priority order looking for ones with
+ *     data to send. We could do with optimising this scan a bit. We aim
+ *     to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
+ *     TX_THRESH_LO we get called again
+ *
+ *     FIXME: We should round robin between groups and in theory you can
+ *     renegotiate DLCI priorities with optional stuff. Needs optimising.
+ */
+
+static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
+{
+       int len;
+       /* Priority ordering: We should do priority with RR of the groups */
+       int i = 1;
+
+       while (i < NUM_DLCI) {
+               struct gsm_dlci *dlci;
+
+               if (gsm->tx_bytes > TX_THRESH_HI)
+                       break;
+               dlci = gsm->dlci[i];
+               if (dlci == NULL || dlci->constipated) {
+                       i++;
+                       continue;
+               }
+               if (dlci->adaption < 3)
+                       len = gsm_dlci_data_output(gsm, dlci);
+               else
+                       len = gsm_dlci_data_output_framed(gsm, dlci);
+               if (len < 0)
+                       break;
+               /* DLCI empty - try the next */
+               if (len == 0)
+                       i++;
+       }
+}
+
+/**
+ *     gsm_dlci_data_kick      -       transmit if possible
+ *     @dlci: DLCI to kick
+ *
+ *     Transmit data from this DLCI if the queue is empty. We can't rely on
+ *     a tty wakeup except when we filled the pipe so we need to fire off
+ *     new data ourselves in other cases.
+ */
+
+static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       /* If we have nothing running then we need to fire up */
+       if (dlci->gsm->tx_bytes == 0)
+               gsm_dlci_data_output(dlci->gsm, dlci);
+       else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
+               gsm_dlci_data_sweep(dlci->gsm);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+}
+
+/*
+ *     Control message processing
+ */
+
+
+/**
+ *     gsm_control_reply       -       send a response frame to a control
+ *     @gsm: gsm channel
+ *     @cmd: the command to use
+ *     @data: data to follow encoded info
+ *     @dlen: length of data
+ *
+ *     Encode up and queue a UI/UIH frame containing our response.
+ */
+
+static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
+                                       int dlen)
+{
+       struct gsm_msg *msg;
+       msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
+       msg->data[0] = (cmd & 0xFE) << 1 | EA;  /* Clear C/R */
+       msg->data[1] = (dlen << 1) | EA;
+       memcpy(msg->data + 2, data, dlen);
+       gsm_data_queue(gsm->dlci[0], msg);
+}
+
+/**
+ *     gsm_process_modem       -       process received modem status
+ *     @tty: virtual tty bound to the DLCI
+ *     @dlci: DLCI to affect
+ *     @modem: modem bits (full EA)
+ *
+ *     Used when a modem control message or line state inline in adaption
+ *     layer 2 is processed. Sort out the local modem state and throttles
+ */
+
+static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
+                                                       u32 modem)
+{
+       int  mlines = 0;
+       u8 brk = modem >> 6;
+
+       /* Flow control/ready to communicate */
+       if (modem & MDM_FC) {
+               /* Need to throttle our output on this device */
+               dlci->constipated = 1;
+       }
+       if (modem & MDM_RTC) {
+               mlines |= TIOCM_DSR | TIOCM_DTR;
+               dlci->constipated = 0;
+               gsm_dlci_data_kick(dlci);
+       }
+       /* Map modem bits */
+       if (modem & MDM_RTR)
+               mlines |= TIOCM_RTS | TIOCM_CTS;
+       if (modem & MDM_IC)
+               mlines |= TIOCM_RI;
+       if (modem & MDM_DV)
+               mlines |= TIOCM_CD;
+
+       /* Carrier drop -> hangup */
+       if (tty) {
+               if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
+                       if (!(tty->termios->c_cflag & CLOCAL))
+                               tty_hangup(tty);
+               if (brk & 0x01)
+                       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       }
+       dlci->modem_rx = mlines;
+}
+
+/**
+ *     gsm_control_modem       -       modem status received
+ *     @gsm: GSM channel
+ *     @data: data following command
+ *     @clen: command length
+ *
+ *     We have received a modem status control message. This is used by
+ *     the GSM mux protocol to pass virtual modem line status and optionally
+ *     to indicate break signals. Unpack it, convert to Linux representation
+ *     and if need be stuff a break message down the tty.
+ */
+
+static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
+{
+       unsigned int addr = 0;
+       unsigned int modem = 0;
+       struct gsm_dlci *dlci;
+       int len = clen;
+       u8 *dp = data;
+       struct tty_struct *tty;
+
+       while (gsm_read_ea(&addr, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       /* Must be at least one byte following the EA */
+       len--;
+       if (len <= 0)
+               return;
+
+       addr >>= 1;
+       /* Closed port, or invalid ? */
+       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
+               return;
+       dlci = gsm->dlci[addr];
+
+       while (gsm_read_ea(&modem, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       tty = tty_port_tty_get(&dlci->port);
+       gsm_process_modem(tty, dlci, modem);
+       if (tty) {
+               tty_wakeup(tty);
+               tty_kref_put(tty);
+       }
+       gsm_control_reply(gsm, CMD_MSC, data, clen);
+}
+
+/**
+ *     gsm_control_rls         -       remote line status
+ *     @gsm: GSM channel
+ *     @data: data bytes
+ *     @clen: data length
+ *
+ *     The modem sends us a two byte message on the control channel whenever
+ *     it wishes to send us an error state from the virtual link. Stuff
+ *     this into the uplink tty if present
+ */
+
+static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
+{
+       struct tty_struct *tty;
+       unsigned int addr = 0 ;
+       u8 bits;
+       int len = clen;
+       u8 *dp = data;
+
+       while (gsm_read_ea(&addr, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       /* Must be at least one byte following ea */
+       len--;
+       if (len <= 0)
+               return;
+       addr >>= 1;
+       /* Closed port, or invalid ? */
+       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
+               return;
+       /* No error ? */
+       bits = *dp;
+       if ((bits & 1) == 0)
+               return;
+       /* See if we have an uplink tty */
+       tty = tty_port_tty_get(&gsm->dlci[addr]->port);
+
+       if (tty) {
+               if (bits & 2)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               if (bits & 4)
+                       tty_insert_flip_char(tty, 0, TTY_PARITY);
+               if (bits & 8)
+                       tty_insert_flip_char(tty, 0, TTY_FRAME);
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
+       }
+       gsm_control_reply(gsm, CMD_RLS, data, clen);
+}
+
+static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
+
+/**
+ *     gsm_control_message     -       DLCI 0 control processing
+ *     @gsm: our GSM mux
+ *     @command:  the command EA
+ *     @data: data beyond the command/length EAs
+ *     @clen: length
+ *
+ *     Input processor for control messages from the other end of the link.
+ *     Processes the incoming request and queues a response frame or an
+ *     NSC response if not supported
+ */
+
+static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
+                                                       u8 *data, int clen)
+{
+       u8 buf[1];
+       switch (command) {
+       case CMD_CLD: {
+               struct gsm_dlci *dlci = gsm->dlci[0];
+               /* Modem wishes to close down */
+               if (dlci) {
+                       dlci->dead = 1;
+                       gsm->dead = 1;
+                       gsm_dlci_begin_close(dlci);
+               }
+               }
+               break;
+       case CMD_TEST:
+               /* Modem wishes to test, reply with the data */
+               gsm_control_reply(gsm, CMD_TEST, data, clen);
+               break;
+       case CMD_FCON:
+               /* Modem wants us to STFU */
+               gsm->constipated = 1;
+               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
+               break;
+       case CMD_FCOFF:
+               /* Modem can accept data again */
+               gsm->constipated = 0;
+               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+               /* Kick the link in case it is idling */
+               gsm_data_kick(gsm);
+               break;
+       case CMD_MSC:
+               /* Out of band modem line change indicator for a DLCI */
+               gsm_control_modem(gsm, data, clen);
+               break;
+       case CMD_RLS:
+               /* Out of band error reception for a DLCI */
+               gsm_control_rls(gsm, data, clen);
+               break;
+       case CMD_PSC:
+               /* Modem wishes to enter power saving state */
+               gsm_control_reply(gsm, CMD_PSC, NULL, 0);
+               break;
+               /* Optional unsupported commands */
+       case CMD_PN:    /* Parameter negotiation */
+       case CMD_RPN:   /* Remote port negotation */
+       case CMD_SNC:   /* Service negotation command */
+       default:
+               /* Reply to bad commands with an NSC */
+               buf[0] = command;
+               gsm_control_reply(gsm, CMD_NSC, buf, 1);
+               break;
+       }
+}
+
+/**
+ *     gsm_control_response    -       process a response to our control
+ *     @gsm: our GSM mux
+ *     @command: the command (response) EA
+ *     @data: data beyond the command/length EA
+ *     @clen: length
+ *
+ *     Process a response to an outstanding command. We only allow a single
+ *     control message in flight so this is fairly easy. All the clean up
+ *     is done by the caller, we just update the fields, flag it as done
+ *     and return
+ */
+
+static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
+                                                       u8 *data, int clen)
+{
+       struct gsm_control *ctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gsm->control_lock, flags);
+
+       ctrl = gsm->pending_cmd;
+       /* Does the reply match our command */
+       command |= 1;
+       if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
+               /* Our command was replied to, kill the retry timer */
+               del_timer(&gsm->t2_timer);
+               gsm->pending_cmd = NULL;
+               /* Rejected by the other end */
+               if (command == CMD_NSC)
+                       ctrl->error = -EOPNOTSUPP;
+               ctrl->done = 1;
+               wake_up(&gsm->event);
+       }
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ *     gsm_control_transmit    -       send control packet
+ *     @gsm: gsm mux
+ *     @ctrl: frame to send
+ *
+ *     Send out a pending control command (called under control lock)
+ */
+
+static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
+{
+       struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
+                                                       gsm->ftype|PF);
+       if (msg == NULL)
+               return;
+       msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
+       memcpy(msg->data + 1, ctrl->data, ctrl->len);
+       gsm_data_queue(gsm->dlci[0], msg);
+}
+
+/**
+ *     gsm_control_retransmit  -       retransmit a control frame
+ *     @data: pointer to our gsm object
+ *
+ *     Called off the T2 timer expiry in order to retransmit control frames
+ *     that have been lost in the system somewhere. The control_lock protects
+ *     us from colliding with another sender or a receive completion event.
+ *     In that situation the timer may still occur in a small window but
+ *     gsm->pending_cmd will be NULL and we just let the timer expire.
+ */
+
+static void gsm_control_retransmit(unsigned long data)
+{
+       struct gsm_mux *gsm = (struct gsm_mux *)data;
+       struct gsm_control *ctrl;
+       unsigned long flags;
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       ctrl = gsm->pending_cmd;
+       if (ctrl) {
+               gsm->cretries--;
+               if (gsm->cretries == 0) {
+                       gsm->pending_cmd = NULL;
+                       ctrl->error = -ETIMEDOUT;
+                       ctrl->done = 1;
+                       spin_unlock_irqrestore(&gsm->control_lock, flags);
+                       wake_up(&gsm->event);
+                       return;
+               }
+               gsm_control_transmit(gsm, ctrl);
+               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       }
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ *     gsm_control_send        -       send a control frame on DLCI 0
+ *     @gsm: the GSM channel
+ *     @command: command  to send including CR bit
+ *     @data: bytes of data (must be kmalloced)
+ *     @len: length of the block to send
+ *
+ *     Queue and dispatch a control command. Only one command can be
+ *     active at a time. In theory more can be outstanding but the matching
+ *     gets really complicated so for now stick to one outstanding.
+ */
+
+static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
+               unsigned int command, u8 *data, int clen)
+{
+       struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
+                                               GFP_KERNEL);
+       unsigned long flags;
+       if (ctrl == NULL)
+               return NULL;
+retry:
+       wait_event(gsm->event, gsm->pending_cmd == NULL);
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       if (gsm->pending_cmd != NULL) {
+               spin_unlock_irqrestore(&gsm->control_lock, flags);
+               goto retry;
+       }
+       ctrl->cmd = command;
+       ctrl->data = data;
+       ctrl->len = clen;
+       gsm->pending_cmd = ctrl;
+       gsm->cretries = gsm->n2;
+       mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       gsm_control_transmit(gsm, ctrl);
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+       return ctrl;
+}
+
+/**
+ *     gsm_control_wait        -       wait for a control to finish
+ *     @gsm: GSM mux
+ *     @control: control we are waiting on
+ *
+ *     Waits for the control to complete or time out. Frees any used
+ *     resources and returns 0 for success, or an error if the remote
+ *     rejected or ignored the request.
+ */
+
+static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
+{
+       int err;
+       wait_event(gsm->event, control->done == 1);
+       err = control->error;
+       kfree(control);
+       return err;
+}
+
+
+/*
+ *     DLCI level handling: Needs krefs
+ */
+
+/*
+ *     State transitions and timers
+ */
+
+/**
+ *     gsm_dlci_close          -       a DLCI has closed
+ *     @dlci: DLCI that closed
+ *
+ *     Perform processing when moving a DLCI into closed state. If there
+ *     is an attached tty this is hung up
+ */
+
+static void gsm_dlci_close(struct gsm_dlci *dlci)
+{
+       del_timer(&dlci->t1);
+       if (debug & 8)
+               printk("DLCI %d goes closed.\n", dlci->addr);
+       dlci->state = DLCI_CLOSED;
+       if (dlci->addr != 0) {
+               struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
+               if (tty) {
+                       tty_hangup(tty);
+                       tty_kref_put(tty);
+               }
+               kfifo_reset(dlci->fifo);
+       } else
+               dlci->gsm->dead = 1;
+       wake_up(&dlci->gsm->event);
+       /* A DLCI 0 close is a MUX termination so we need to kick that
+          back to userspace somehow */
+}
+
+/**
+ *     gsm_dlci_open           -       a DLCI has opened
+ *     @dlci: DLCI that opened
+ *
+ *     Perform processing when moving a DLCI into open state.
+ */
+
+static void gsm_dlci_open(struct gsm_dlci *dlci)
+{
+       /* Note that SABM UA .. SABM UA first UA lost can mean that we go
+          open -> open */
+       del_timer(&dlci->t1);
+       /* This will let a tty open continue */
+       dlci->state = DLCI_OPEN;
+       if (debug & 8)
+               printk("DLCI %d goes open.\n", dlci->addr);
+       wake_up(&dlci->gsm->event);
+}
+
+/**
+ *     gsm_dlci_t1             -       T1 timer expiry
+ *     @dlci: DLCI that opened
+ *
+ *     The T1 timer handles retransmits of control frames (essentially of
+ *     SABM and DISC). We resend the command until the retry count runs out
+ *     in which case an opening port goes back to closed and a closing port
+ *     is simply put into closed state (any further frames from the other
+ *     end will get a DM response)
+ */
+
+static void gsm_dlci_t1(unsigned long data)
+{
+       struct gsm_dlci *dlci = (struct gsm_dlci *)data;
+       struct gsm_mux *gsm = dlci->gsm;
+
+       switch (dlci->state) {
+       case DLCI_OPENING:
+               dlci->retries--;
+               if (dlci->retries) {
+                       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+               } else
+                       gsm_dlci_close(dlci);
+               break;
+       case DLCI_CLOSING:
+               dlci->retries--;
+               if (dlci->retries) {
+                       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
+                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+               } else
+                       gsm_dlci_close(dlci);
+               break;
+       }
+}
+
+/**
+ *     gsm_dlci_begin_open     -       start channel open procedure
+ *     @dlci: DLCI to open
+ *
+ *     Commence opening a DLCI from the Linux side. We issue SABM messages
+ *     to the modem which should then reply with a UA, at which point we
+ *     will move into open state. Opening is done asynchronously with retry
+ *     running off timers and the responses.
+ */
+
+static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
+               return;
+       dlci->retries = gsm->n2;
+       dlci->state = DLCI_OPENING;
+       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+}
+
+/**
+ *     gsm_dlci_begin_close    -       start channel open procedure
+ *     @dlci: DLCI to open
+ *
+ *     Commence closing a DLCI from the Linux side. We issue DISC messages
+ *     to the modem which should then reply with a UA, at which point we
+ *     will move into closed state. Closing is done asynchronously with retry
+ *     off timers. We may also receive a DM reply from the other end which
+ *     indicates the channel was already closed.
+ */
+
+static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
+               return;
+       dlci->retries = gsm->n2;
+       dlci->state = DLCI_CLOSING;
+       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
+       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+}
+
+/**
+ *     gsm_dlci_data           -       data arrived
+ *     @dlci: channel
+ *     @data: block of bytes received
+ *     @len: length of received block
+ *
+ *     A UI or UIH frame has arrived which contains data for a channel
+ *     other than the control channel. If the relevant virtual tty is
+ *     open we shovel the bits down it, if not we drop them.
+ */
+
+static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
+{
+       /* krefs .. */
+       struct tty_port *port = &dlci->port;
+       struct tty_struct *tty = tty_port_tty_get(port);
+       unsigned int modem = 0;
+
+       if (debug & 16)
+               printk("%d bytes for tty %p\n", len, tty);
+       if (tty) {
+               switch (dlci->adaption)  {
+                       /* Unsupported types */
+                       /* Packetised interruptible data */
+                       case 4:
+                               break;
+                       /* Packetised uininterruptible voice/data */
+                       case 3:
+                               break;
+                       /* Asynchronous serial with line state in each frame */
+                       case 2:
+                               while (gsm_read_ea(&modem, *data++) == 0) {
+                                       len--;
+                                       if (len == 0)
+                                               return;
+                               }
+                               gsm_process_modem(tty, dlci, modem);
+                       /* Line state will go via DLCI 0 controls only */
+                       case 1:
+                       default:
+                               tty_insert_flip_string(tty, data, len);
+                               tty_flip_buffer_push(tty);
+               }
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     gsm_dlci_control        -       data arrived on control channel
+ *     @dlci: channel
+ *     @data: block of bytes received
+ *     @len: length of received block
+ *
+ *     A UI or UIH frame has arrived which contains data for DLCI 0 the
+ *     control channel. This should contain a command EA followed by
+ *     control data bytes. The command EA contains a command/response bit
+ *     and we divide up the work accordingly.
+ */
+
+static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
+{
+       /* See what command is involved */
+       unsigned int command = 0;
+       while (len-- > 0) {
+               if (gsm_read_ea(&command, *data++) == 1) {
+                       int clen = *data++;
+                       len--;
+                       /* FIXME: this is properly an EA */
+                       clen >>= 1;
+                       /* Malformed command ? */
+                       if (clen > len)
+                               return;
+                       if (command & 1)
+                               gsm_control_message(dlci->gsm, command,
+                                                               data, clen);
+                       else
+                               gsm_control_response(dlci->gsm, command,
+                                                               data, clen);
+                       return;
+               }
+       }
+}
+
+/*
+ *     Allocate/Free DLCI channels
+ */
+
+/**
+ *     gsm_dlci_alloc          -       allocate a DLCI
+ *     @gsm: GSM mux
+ *     @addr: address of the DLCI
+ *
+ *     Allocate and install a new DLCI object into the GSM mux.
+ *
+ *     FIXME: review locking races
+ */
+
+static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
+{
+       struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
+       if (dlci == NULL)
+               return NULL;
+       spin_lock_init(&dlci->lock);
+       dlci->fifo = &dlci->_fifo;
+       if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
+               kfree(dlci);
+               return NULL;
+       }
+
+       skb_queue_head_init(&dlci->skb_list);
+       init_timer(&dlci->t1);
+       dlci->t1.function = gsm_dlci_t1;
+       dlci->t1.data = (unsigned long)dlci;
+       tty_port_init(&dlci->port);
+       dlci->port.ops = &gsm_port_ops;
+       dlci->gsm = gsm;
+       dlci->addr = addr;
+       dlci->adaption = gsm->adaption;
+       dlci->state = DLCI_CLOSED;
+       if (addr)
+               dlci->data = gsm_dlci_data;
+       else
+               dlci->data = gsm_dlci_command;
+       gsm->dlci[addr] = dlci;
+       return dlci;
+}
+
+/**
+ *     gsm_dlci_free           -       release DLCI
+ *     @dlci: DLCI to destroy
+ *
+ *     Free up a DLCI. Currently to keep the lifetime rules sane we only
+ *     clean up DLCI objects when the MUX closes rather than as the port
+ *     is closed down on both the tty and mux levels.
+ *
+ *     Can sleep.
+ */
+static void gsm_dlci_free(struct gsm_dlci *dlci)
+{
+       struct tty_struct *tty = tty_port_tty_get(&dlci->port);
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+       del_timer_sync(&dlci->t1);
+       dlci->gsm->dlci[dlci->addr] = NULL;
+       kfifo_free(dlci->fifo);
+       kfree(dlci);
+}
+
+
+/*
+ *     LAPBish link layer logic
+ */
+
+/**
+ *     gsm_queue               -       a GSM frame is ready to process
+ *     @gsm: pointer to our gsm mux
+ *
+ *     At this point in time a frame has arrived and been demangled from
+ *     the line encoding. All the differences between the encodings have
+ *     been handled below us and the frame is unpacked into the structures.
+ *     The fcs holds the header FCS but any data FCS must be added here.
+ */
+
+static void gsm_queue(struct gsm_mux *gsm)
+{
+       struct gsm_dlci *dlci;
+       u8 cr;
+       int address;
+       /* We have to sneak a look at the packet body to do the FCS.
+          A somewhat layering violation in the spec */
+
+       if ((gsm->control & ~PF) == UI)
+               gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+       if (gsm->fcs != GOOD_FCS) {
+               gsm->bad_fcs++;
+               if (debug & 4)
+                       printk("BAD FCS %02x\n", gsm->fcs);
+               return;
+       }
+       address = gsm->address >> 1;
+       if (address >= NUM_DLCI)
+               goto invalid;
+
+       cr = gsm->address & 1;          /* C/R bit */
+
+       gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
+
+       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
+       dlci = gsm->dlci[address];
+
+       switch (gsm->control) {
+       case SABM|PF:
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL)
+                       dlci = gsm_dlci_alloc(gsm, address);
+               if (dlci == NULL)
+                       return;
+               if (dlci->dead)
+                       gsm_response(gsm, address, DM);
+               else {
+                       gsm_response(gsm, address, UA);
+                       gsm_dlci_open(dlci);
+               }
+               break;
+       case DISC|PF:
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
+                       gsm_response(gsm, address, DM);
+                       return;
+               }
+               /* Real close complete */
+               gsm_response(gsm, address, UA);
+               gsm_dlci_close(dlci);
+               break;
+       case UA:
+       case UA|PF:
+               if (cr == 0 || dlci == NULL)
+                       break;
+               switch (dlci->state) {
+               case DLCI_CLOSING:
+                       gsm_dlci_close(dlci);
+                       break;
+               case DLCI_OPENING:
+                       gsm_dlci_open(dlci);
+                       break;
+               }
+               break;
+       case DM:        /* DM can be valid unsolicited */
+       case DM|PF:
+               if (cr)
+                       goto invalid;
+               if (dlci == NULL)
+                       return;
+               gsm_dlci_close(dlci);
+               break;
+       case UI:
+       case UI|PF:
+       case UIH:
+       case UIH|PF:
+#if 0
+               if (cr)
+                       goto invalid;
+#endif
+               if (dlci == NULL || dlci->state != DLCI_OPEN) {
+                       gsm_command(gsm, address, DM|PF);
+                       return;
+               }
+               dlci->data(dlci, gsm->buf, gsm->len);
+               break;
+       default:
+               goto invalid;
+       }
+       return;
+invalid:
+       gsm->malformed++;
+       return;
+}
+
+
+/**
+ *     gsm0_receive    -       perform processing for non-transparency
+ *     @gsm: gsm data for this ldisc instance
+ *     @c: character
+ *
+ *     Receive bytes in gsm mode 0
+ */
+
+static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
+{
+       switch (gsm->state) {
+       case GSM_SEARCH:        /* SOF marker */
+               if (c == GSM0_SOF) {
+                       gsm->state = GSM_ADDRESS;
+                       gsm->address = 0;
+                       gsm->len = 0;
+                       gsm->fcs = INIT_FCS;
+               }
+               break;          /* Address EA */
+       case GSM_ADDRESS:
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->address, c))
+                       gsm->state = GSM_CONTROL;
+               break;
+       case GSM_CONTROL:       /* Control Byte */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->control = c;
+               gsm->state = GSM_LEN;
+               break;
+       case GSM_LEN:           /* Length EA */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->len, c)) {
+                       if (gsm->len > gsm->mru) {
+                               gsm->bad_size++;
+                               gsm->state = GSM_SEARCH;
+                               break;
+                       }
+                       gsm->count = 0;
+                       gsm->state = GSM_DATA;
+               }
+               break;
+       case GSM_DATA:          /* Data */
+               gsm->buf[gsm->count++] = c;
+               if (gsm->count == gsm->len)
+                       gsm->state = GSM_FCS;
+               break;
+       case GSM_FCS:           /* FCS follows the packet */
+               gsm->fcs = c;
+               gsm_queue(gsm);
+               /* And then back for the next frame */
+               gsm->state = GSM_SEARCH;
+               break;
+       }
+}
+
+/**
+ *     gsm0_receive    -       perform processing for non-transparency
+ *     @gsm: gsm data for this ldisc instance
+ *     @c: character
+ *
+ *     Receive bytes in mode 1 (Advanced option)
+ */
+
+static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+{
+       if (c == GSM1_SOF) {
+               /* EOF is only valid in frame if we have got to the data state
+                  and received at least one byte (the FCS) */
+               if (gsm->state == GSM_DATA && gsm->count) {
+                       /* Extract the FCS */
+                       gsm->count--;
+                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+                       gsm->len = gsm->count;
+                       gsm_queue(gsm);
+                       gsm->state  = GSM_START;
+                       return;
+               }
+               /* Any partial frame was a runt so go back to start */
+               if (gsm->state != GSM_START) {
+                       gsm->malformed++;
+                       gsm->state = GSM_START;
+               }
+               /* A SOF in GSM_START means we are still reading idling or
+                  framing bytes */
+               return;
+       }
+
+       if (c == GSM1_ESCAPE) {
+               gsm->escape = 1;
+               return;
+       }
+
+       /* Only an unescaped SOF gets us out of GSM search */
+       if (gsm->state == GSM_SEARCH)
+               return;
+
+       if (gsm->escape) {
+               c ^= GSM1_ESCAPE_BITS;
+               gsm->escape = 0;
+       }
+       switch (gsm->state) {
+       case GSM_START:         /* First byte after SOF */
+               gsm->address = 0;
+               gsm->state = GSM_ADDRESS;
+               gsm->fcs = INIT_FCS;
+               /* Drop through */
+       case GSM_ADDRESS:       /* Address continuation */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->address, c))
+                       gsm->state = GSM_CONTROL;
+               break;
+       case GSM_CONTROL:       /* Control Byte */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->control = c;
+               gsm->count = 0;
+               gsm->state = GSM_DATA;
+               break;
+       case GSM_DATA:          /* Data */
+               if (gsm->count > gsm->mru ) {   /* Allow one for the FCS */
+                       gsm->state = GSM_OVERRUN;
+                       gsm->bad_size++;
+               } else
+                       gsm->buf[gsm->count++] = c;
+               break;
+       case GSM_OVERRUN:       /* Over-long - eg a dropped SOF */
+               break;
+       }
+}
+
+/**
+ *     gsm_error               -       handle tty error
+ *     @gsm: ldisc data
+ *     @data: byte received (may be invalid)
+ *     @flag: error received
+ *
+ *     Handle an error in the receipt of data for a frame. Currently we just
+ *     go back to hunting for a SOF.
+ *
+ *     FIXME: better diagnostics ?
+ */
+
+static void gsm_error(struct gsm_mux *gsm,
+                               unsigned char data, unsigned char flag)
+{
+       gsm->state = GSM_SEARCH;
+       gsm->io_error++;
+}
+
+/**
+ *     gsm_cleanup_mux         -       generic GSM protocol cleanup
+ *     @gsm: our mux
+ *
+ *     Clean up the bits of the mux which are the same for all framing
+ *     protocols. Remove the mux from the mux table, stop all the timers
+ *     and then shut down each device hanging up the channels as we go.
+ */
+
+void gsm_cleanup_mux(struct gsm_mux *gsm)
+{
+       int i;
+       struct gsm_dlci *dlci = gsm->dlci[0];
+       struct gsm_msg *txq;
+
+       gsm->dead = 1;
+
+       spin_lock(&gsm_mux_lock);
+       for (i = 0; i < MAX_MUX; i++) {
+               if (gsm_mux[i] == gsm) {
+                       gsm_mux[i] = NULL;
+                       break;
+               }
+       }
+       spin_unlock(&gsm_mux_lock);
+       WARN_ON(i == MAX_MUX);
+
+       del_timer_sync(&gsm->t2_timer);
+       /* Now we are sure T2 has stopped */
+       if (dlci) {
+               dlci->dead = 1;
+               gsm_dlci_begin_close(dlci);
+               wait_event_interruptible(gsm->event,
+                                       dlci->state == DLCI_CLOSED);
+       }
+       /* Free up any link layer users */
+       for (i = 0; i < NUM_DLCI; i++)
+               if (gsm->dlci[i])
+                       gsm_dlci_free(gsm->dlci[i]);
+       /* Now wipe the queues */
+       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
+               gsm->tx_head = txq->next;
+               kfree(txq);
+       }
+       gsm->tx_tail = NULL;
+}
+EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
+
+/**
+ *     gsm_activate_mux        -       generic GSM setup
+ *     @gsm: our mux
+ *
+ *     Set up the bits of the mux which are the same for all framing
+ *     protocols. Add the mux to the mux table so it can be opened and
+ *     finally kick off connecting to DLCI 0 on the modem.
+ */
+
+int gsm_activate_mux(struct gsm_mux *gsm)
+{
+       struct gsm_dlci *dlci;
+       int i = 0;
+
+       init_timer(&gsm->t2_timer);
+       gsm->t2_timer.function = gsm_control_retransmit;
+       gsm->t2_timer.data = (unsigned long)gsm;
+       init_waitqueue_head(&gsm->event);
+       spin_lock_init(&gsm->control_lock);
+       spin_lock_init(&gsm->tx_lock);
+
+       if (gsm->encoding == 0)
+               gsm->receive = gsm0_receive;
+       else
+               gsm->receive = gsm1_receive;
+       gsm->error = gsm_error;
+
+       spin_lock(&gsm_mux_lock);
+       for (i = 0; i < MAX_MUX; i++) {
+               if (gsm_mux[i] == NULL) {
+                       gsm_mux[i] = gsm;
+                       break;
+               }
+       }
+       spin_unlock(&gsm_mux_lock);
+       if (i == MAX_MUX)
+               return -EBUSY;
+
+       dlci = gsm_dlci_alloc(gsm, 0);
+       if (dlci == NULL)
+               return -ENOMEM;
+       gsm->dead = 0;          /* Tty opens are now permissible */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gsm_activate_mux);
+
+/**
+ *     gsm_free_mux            -       free up a mux
+ *     @mux: mux to free
+ *
+ *     Dispose of allocated resources for a dead mux. No refcounting
+ *     at present so the mux must be truely dead.
+ */
+void gsm_free_mux(struct gsm_mux *gsm)
+{
+       kfree(gsm->txframe);
+       kfree(gsm->buf);
+       kfree(gsm);
+}
+EXPORT_SYMBOL_GPL(gsm_free_mux);
+
+/**
+ *     gsm_alloc_mux           -       allocate a mux
+ *
+ *     Creates a new mux ready for activation.
+ */
+
+struct gsm_mux *gsm_alloc_mux(void)
+{
+       struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
+       if (gsm == NULL)
+               return NULL;
+       gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
+       if (gsm->buf == NULL) {
+               kfree(gsm);
+               return NULL;
+       }
+       gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
+       if (gsm->txframe == NULL) {
+               kfree(gsm->buf);
+               kfree(gsm);
+               return NULL;
+       }
+       spin_lock_init(&gsm->lock);
+
+       gsm->t1 = T1;
+       gsm->t2 = T2;
+       gsm->n2 = N2;
+       gsm->ftype = UIH;
+       gsm->initiator = 0;
+       gsm->adaption = 1;
+       gsm->encoding = 1;
+       gsm->mru = 64;  /* Default to encoding 1 so these should be 64 */
+       gsm->mtu = 64;
+       gsm->dead = 1;  /* Avoid early tty opens */
+
+       return gsm;
+}
+EXPORT_SYMBOL_GPL(gsm_alloc_mux);
+
+
+
+
+/**
+ *     gsmld_output            -       write to link
+ *     @gsm: our mux
+ *     @data: bytes to output
+ *     @len: size
+ *
+ *     Write a block of data from the GSM mux to the data channel. This
+ *     will eventually be serialized from above but at the moment isn't.
+ */
+
+static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
+{
+       if (tty_write_room(gsm->tty) < len) {
+               set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
+               return -ENOSPC;
+       }
+       if (debug & 4) {
+               printk("-->%d bytes out\n", len);
+               hex_packet(data, len);
+       }
+       gsm->tty->ops->write(gsm->tty, data, len);
+       return len;
+}
+
+/**
+ *     gsmld_attach_gsm        -       mode set up
+ *     @tty: our tty structure
+ *     @gsm: our mux
+ *
+ *     Set up the MUX for basic mode and commence connecting to the
+ *     modem. Currently called from the line discipline set up but
+ *     will need moving to an ioctl path.
+ */
+
+static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+{
+       int ret;
+
+       gsm->tty = tty_kref_get(tty);
+       gsm->output = gsmld_output;
+       ret =  gsm_activate_mux(gsm);
+       if (ret != 0)
+               tty_kref_put(gsm->tty);
+       return ret;
+}
+
+
+/**
+ *     gsmld_detach_gsm        -       stop doing 0710 mux
+ *     @tty: tty atttached to the mux
+ *     @gsm: mux
+ *
+ *     Shutdown and then clean up the resources used by the line discipline
+ */
+
+static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+{
+       WARN_ON(tty != gsm->tty);
+       gsm_cleanup_mux(gsm);
+       tty_kref_put(gsm->tty);
+       gsm->tty = NULL;
+}
+
+static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+       const unsigned char *dp;
+       char *f;
+       int i;
+       char buf[64];
+       char flags;
+
+       if (debug & 4) {
+               printk("Inbytes %dd\n", count);
+               hex_packet(cp, count);
+       }
+
+       for (i = count, dp = cp, f = fp; i; i--, dp++) {
+               flags = *f++;
+               switch (flags) {
+               case TTY_NORMAL:
+                       gsm->receive(gsm, *dp);
+                       break;
+               case TTY_OVERRUN:
+               case TTY_BREAK:
+               case TTY_PARITY:
+               case TTY_FRAME:
+                       gsm->error(gsm, *dp, flags);
+                       break;
+               default:
+                       printk(KERN_ERR "%s: unknown flag %d\n",
+                              tty_name(tty, buf), flags);
+                       break;
+               }
+       }
+       /* FASYNC if needed ? */
+       /* If clogged call tty_throttle(tty); */
+}
+
+/**
+ *     gsmld_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time.
+ *
+ *     Locking: gsm lock
+ */
+
+static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+/**
+ *     gsmld_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup).
+ */
+
+static void gsmld_flush_buffer(struct tty_struct *tty)
+{
+}
+
+/**
+ *     gsmld_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is
+ *     being shut down, either because of a close or becsuse of a
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+
+static void gsmld_close(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+
+       gsmld_detach_gsm(tty, gsm);
+
+       gsmld_flush_buffer(tty);
+       /* Do other clean up here */
+       gsm_free_mux(gsm);
+}
+
+/**
+ *     gsmld_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
+static int gsmld_open(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm;
+
+       if (tty->ops->write == NULL)
+               return -EINVAL;
+
+       /* Attach our ldisc data */
+       gsm = gsm_alloc_mux();
+       if (gsm == NULL)
+               return -ENOMEM;
+
+       tty->disc_data = gsm;
+       tty->receive_room = 65536;
+
+       /* Attach the initial passive connection */
+       gsm->encoding = 1;
+       return gsmld_attach_gsm(tty, gsm);
+}
+
+/**
+ *     gsmld_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
+ */
+
+static void gsmld_write_wakeup(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+       unsigned long flags;
+
+       /* Queue poll */
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       gsm_data_kick(gsm);
+       if (gsm->tx_bytes < TX_THRESH_LO) {
+               spin_lock_irqsave(&gsm->tx_lock, flags);
+               gsm_dlci_data_sweep(gsm);
+               spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       }
+}
+
+/**
+ *     gsmld_read              -       read function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Perform reads for the line discipline. We are guaranteed that the
+ *     line discipline will not be closed under us but we may get multiple
+ *     parallel readers and must handle this ourselves. We may also get
+ *     a hangup. Always called in user context, may sleep.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ */
+
+static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
+                        unsigned char __user *buf, size_t nr)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ *     gsmld_write             -       write function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Called when the owner of the device wants to send a frame
+ *     itself (or some other control data). The data is transferred
+ *     as-is and must be properly framed and checksummed as appropriate
+ *     by userspace. Frames are either sent whole or not at all as this
+ *     avoids pain user side.
+ */
+
+static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *buf, size_t nr)
+{
+       int space = tty_write_room(tty);
+       if (space >= nr)
+               return tty->ops->write(tty, buf, nr);
+       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       return -ENOBUFS;
+}
+
+/**
+ *     gsmld_poll              -       poll method for N_GSM0710
+ *     @tty: terminal device
+ *     @file: file accessing it
+ *     @wait: poll table
+ *
+ *     Called when the line discipline is asked to poll() for data or
+ *     for special events. This code is not serialized with respect to
+ *     other events save open/close.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *     Called without the kernel lock held - fine
+ */
+
+static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
+                                                       poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct gsm_mux *gsm = tty->disc_data;
+
+       poll_wait(file, &tty->read_wait, wait);
+       poll_wait(file, &tty->write_wait, wait);
+       if (tty_hung_up_p(file))
+               mask |= POLLHUP;
+       if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
+               mask |= POLLOUT | POLLWRNORM;
+       if (gsm->dead)
+               mask |= POLLHUP;
+       return mask;
+}
+
+static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
+                                                       struct gsm_config *c)
+{
+       int need_close = 0;
+       int need_restart = 0;
+
+       /* Stuff we don't support yet - UI or I frame transport, windowing */
+       if ((c->adaption !=1 && c->adaption != 2) || c->k)
+               return -EOPNOTSUPP;
+       /* Check the MRU/MTU range looks sane */
+       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
+               return -EINVAL;
+       if (c->n2 < 3)
+               return -EINVAL;
+       if (c->encapsulation > 1)       /* Basic, advanced, no I */
+               return -EINVAL;
+       if (c->initiator > 1)
+               return -EINVAL;
+       if (c->i == 0 || c->i > 2)      /* UIH and UI only */
+               return -EINVAL;
+       /*
+        *      See what is needed for reconfiguration
+        */
+
+       /* Timing fields */
+       if (c->t1 != 0 && c->t1 != gsm->t1)
+               need_restart = 1;
+       if (c->t2 != 0 && c->t2 != gsm->t2)
+               need_restart = 1;
+       if (c->encapsulation != gsm->encoding)
+               need_restart = 1;
+       if (c->adaption != gsm->adaption)
+               need_restart = 1;
+       /* Requires care */
+       if (c->initiator != gsm->initiator)
+               need_close = 1;
+       if (c->mru != gsm->mru)
+               need_restart = 1;
+       if (c->mtu != gsm->mtu)
+               need_restart = 1;
+
+       /*
+        *      Close down what is needed, restart and initiate the new
+        *      configuration
+        */
+
+       if (need_close || need_restart) {
+               gsm_dlci_begin_close(gsm->dlci[0]);
+               /* This will timeout if the link is down due to N2 expiring */
+               wait_event_interruptible(gsm->event,
+                               gsm->dlci[0]->state == DLCI_CLOSED);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+       if (need_restart)
+               gsm_cleanup_mux(gsm);
+
+       gsm->initiator = c->initiator;
+       gsm->mru = c->mru;
+       gsm->encoding = c->encapsulation;
+       gsm->adaption = c->adaption;
+       gsm->n2 = c->n2;
+
+       if (c->i == 1)
+               gsm->ftype = UIH;
+       else if (c->i == 2)
+               gsm->ftype = UI;
+
+       if (c->t1)
+               gsm->t1 = c->t1;
+       if (c->t2)
+               gsm->t2 = c->t2;
+
+       /* FIXME: We need to separate activation/deactivation from adding
+          and removing from the mux array */
+       if (need_restart)
+               gsm_activate_mux(gsm);
+       if (gsm->initiator && need_close)
+               gsm_dlci_begin_open(gsm->dlci[0]);
+       return 0;
+}
+
+static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       struct gsm_config c;
+       struct gsm_mux *gsm = tty->disc_data;
+
+       switch (cmd) {
+       case GSMIOC_GETCONF:
+               memset(&c, 0, sizeof(c));
+               c.adaption = gsm->adaption;
+               c.encapsulation = gsm->encoding;
+               c.initiator = gsm->initiator;
+               c.t1 = gsm->t1;
+               c.t2 = gsm->t2;
+               c.t3 = 0;       /* Not supported */
+               c.n2 = gsm->n2;
+               if (gsm->ftype == UIH)
+                       c.i = 1;
+               else
+                       c.i = 2;
+               printk("Ftype %d i %d\n", gsm->ftype, c.i);
+               c.mru = gsm->mru;
+               c.mtu = gsm->mtu;
+               c.k = 0;
+               if (copy_to_user((void *)arg, &c, sizeof(c)))
+                       return -EFAULT;
+               return 0;
+       case GSMIOC_SETCONF:
+               if (copy_from_user(&c, (void *)arg, sizeof(c)))
+                       return -EFAULT;
+               return gsmld_config(tty, gsm, &c);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
+
+/* Line discipline for real tty */
+struct tty_ldisc_ops tty_ldisc_packet = {
+       .owner           = THIS_MODULE,
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_gsm",
+       .open            = gsmld_open,
+       .close           = gsmld_close,
+       .flush_buffer    = gsmld_flush_buffer,
+       .chars_in_buffer = gsmld_chars_in_buffer,
+       .read            = gsmld_read,
+       .write           = gsmld_write,
+       .ioctl           = gsmld_ioctl,
+       .poll            = gsmld_poll,
+       .receive_buf     = gsmld_receive_buf,
+       .write_wakeup    = gsmld_write_wakeup
+};
+
+/*
+ *     Virtual tty side
+ */
+
+#define TX_SIZE                512
+
+static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
+{
+       u8 modembits[5];
+       struct gsm_control *ctrl;
+       int len = 2;
+
+       if (brk)
+               len++;
+
+       modembits[0] = len << 1 | EA;           /* Data bytes */
+       modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
+       modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
+       if (brk)
+               modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
+       ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
+       if (ctrl == NULL)
+               return -ENOMEM;
+       return gsm_control_wait(dlci->gsm, ctrl);
+}
+
+static int gsm_carrier_raised(struct tty_port *port)
+{
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+       /* Not yet open so no carrier info */
+       if (dlci->state != DLCI_OPEN)
+               return 0;
+       if (debug & 2)
+               return 1;
+       return dlci->modem_rx & TIOCM_CD;
+}
+
+static void gsm_dtr_rts(struct tty_port *port, int onoff)
+{
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+       unsigned int modem_tx = dlci->modem_tx;
+       if (onoff)
+               modem_tx |= TIOCM_DTR | TIOCM_RTS;
+       else
+               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+               gsmtty_modem_update(dlci, 0);
+       }
+}
+
+static const struct tty_port_operations gsm_port_ops = {
+       .carrier_raised = gsm_carrier_raised,
+       .dtr_rts = gsm_dtr_rts,
+};
+
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_mux *gsm;
+       struct gsm_dlci *dlci;
+       struct tty_port *port;
+       unsigned int line = tty->index;
+       unsigned int mux = line >> 6;
+
+       line = line & 0x3F;
+
+       if (mux >= MAX_MUX)
+               return -ENXIO;
+       /* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
+       if (gsm_mux[mux] == NULL)
+               return -EUNATCH;
+       if (line == 0 || line > 61)     /* 62/63 reserved */
+               return -ECHRNG;
+       gsm = gsm_mux[mux];
+       if (gsm->dead)
+               return -EL2HLT;
+       dlci = gsm->dlci[line];
+       if (dlci == NULL)
+               dlci = gsm_dlci_alloc(gsm, line);
+       if (dlci == NULL)
+               return -ENOMEM;
+       port = &dlci->port;
+       port->count++;
+       tty->driver_data = dlci;
+       tty_port_tty_set(port, tty);
+
+       dlci->modem_rx = 0;
+       /* We could in theory open and close before we wait - eg if we get
+          a DM straight back. This is ok as that will have caused a hangup */
+       set_bit(ASYNCB_INITIALIZED, &port->flags);
+       /* Start sending off SABM messages */
+       gsm_dlci_begin_open(dlci);
+       /* And wait for virtual carrier */
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+static void gsmtty_close(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (dlci == NULL)
+               return;
+       if (tty_port_close_start(&dlci->port, tty, filp) == 0)
+               return;
+       gsm_dlci_begin_close(dlci);
+       tty_port_close_end(&dlci->port, tty);
+       tty_port_tty_set(&dlci->port, NULL);
+}
+
+static void gsmtty_hangup(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       tty_port_hangup(&dlci->port);
+       gsm_dlci_begin_close(dlci);
+}
+
+static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
+                                                                   int len)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       /* Stuff the bytes into the fifo queue */
+       int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
+       /* Need to kick the channel */
+       gsm_dlci_data_kick(dlci);
+       return sent;
+}
+
+static int gsmtty_write_room(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return TX_SIZE - kfifo_len(dlci->fifo);
+}
+
+static int gsmtty_chars_in_buffer(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return kfifo_len(dlci->fifo);
+}
+
+static void gsmtty_flush_buffer(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       /* Caution needed: If we implement reliable transport classes
+          then the data being transmitted can't simply be junked once
+          it has first hit the stack. Until then we can just blow it
+          away */
+       kfifo_reset(dlci->fifo);
+       /* Need to unhook this DLCI from the transmit queue logic */
+}
+
+static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       /* The FIFO handles the queue so the kernel will do the right
+          thing waiting on chars_in_buffer before calling us. No work
+          to do here */
+}
+
+static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return dlci->modem_rx;
+}
+
+static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
+       unsigned int set, unsigned int clear)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       unsigned int modem_tx = dlci->modem_tx;
+
+       modem_tx &= clear;
+       modem_tx |= set;
+
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+               return gsmtty_modem_update(dlci, 0);
+       }
+       return 0;
+}
+
+
+static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
+                       unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       /* For the moment its fixed. In actual fact the speed information
+          for the virtual channel can be propogated in both directions by
+          the RPN control message. This however rapidly gets nasty as we
+          then have to remap modem signals each way according to whether
+          our virtual cable is null modem etc .. */
+       tty_termios_copy_hw(tty->termios, old);
+}
+
+static void gsmtty_throttle(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (tty->termios->c_cflag & CRTSCTS)
+               dlci->modem_tx &= ~TIOCM_DTR;
+       dlci->throttled = 1;
+       /* Send an MSC with DTR cleared */
+       gsmtty_modem_update(dlci, 0);
+}
+
+static void gsmtty_unthrottle(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (tty->termios->c_cflag & CRTSCTS)
+               dlci->modem_tx |= TIOCM_DTR;
+       dlci->throttled = 0;
+       /* Send an MSC with DTR set */
+       gsmtty_modem_update(dlci, 0);
+}
+
+static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       int encode = 0; /* Off */
+
+       if (state == -1)        /* "On indefinitely" - we can't encode this
+                                   properly */
+               encode = 0x0F;
+       else if (state > 0) {
+               encode = state / 200;   /* mS to encoding */
+               if (encode > 0x0F)
+                       encode = 0x0F;  /* Best effort */
+       }
+       return gsmtty_modem_update(dlci, encode);
+}
+
+static struct tty_driver *gsm_tty_driver;
+
+/* Virtual ttys for the demux */
+static const struct tty_operations gsmtty_ops = {
+       .open                   = gsmtty_open,
+       .close                  = gsmtty_close,
+       .write                  = gsmtty_write,
+       .write_room             = gsmtty_write_room,
+       .chars_in_buffer        = gsmtty_chars_in_buffer,
+       .flush_buffer           = gsmtty_flush_buffer,
+       .ioctl                  = gsmtty_ioctl,
+       .throttle               = gsmtty_throttle,
+       .unthrottle             = gsmtty_unthrottle,
+       .set_termios            = gsmtty_set_termios,
+       .hangup                 = gsmtty_hangup,
+       .wait_until_sent        = gsmtty_wait_until_sent,
+       .tiocmget               = gsmtty_tiocmget,
+       .tiocmset               = gsmtty_tiocmset,
+       .break_ctl              = gsmtty_break_ctl,
+};
+
+
+
+static int __init gsm_init(void)
+{
+       /* Fill in our line protocol discipline, and register it */
+       int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
+       if (status != 0) {
+               printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
+               return status;
+       }
+
+       gsm_tty_driver = alloc_tty_driver(256);
+       if (!gsm_tty_driver) {
+               tty_unregister_ldisc(N_GSM0710);
+               printk(KERN_ERR "gsm_init: tty allocation failed.\n");
+               return -EINVAL;
+       }
+       gsm_tty_driver->owner   = THIS_MODULE;
+       gsm_tty_driver->driver_name     = "gsmtty";
+       gsm_tty_driver->name            = "gsmtty";
+       gsm_tty_driver->major           = 0;    /* Dynamic */
+       gsm_tty_driver->minor_start     = 0;
+       gsm_tty_driver->type            = TTY_DRIVER_TYPE_SERIAL;
+       gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gsm_tty_driver->flags   = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
+                                                       | TTY_DRIVER_HARDWARE_BREAK;
+       gsm_tty_driver->init_termios    = tty_std_termios;
+       /* Fixme */
+       gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
+       tty_set_operations(gsm_tty_driver, &gsmtty_ops);
+
+       spin_lock_init(&gsm_mux_lock);
+
+       if (tty_register_driver(gsm_tty_driver)) {
+               put_tty_driver(gsm_tty_driver);
+               tty_unregister_ldisc(N_GSM0710);
+               printk(KERN_ERR "gsm_init: tty registration failed.\n");
+               return -EBUSY;
+       }
+       printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
+       return 0;
+}
+
+static void __exit gsm_exit(void)
+{
+       int status = tty_unregister_ldisc(N_GSM0710);
+       if (status != 0)
+               printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
+       tty_unregister_driver(gsm_tty_driver);
+       put_tty_driver(gsm_tty_driver);
+       printk(KERN_INFO "gsm_init: unloaded.\n");
+}
+
+module_init(gsm_init);
+module_exit(gsm_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
new file mode 100644 (file)
index 0000000..47d3228
--- /dev/null
@@ -0,0 +1,1007 @@
+/* generic HDLC line discipline for Linux
+ *
+ * Written by Paul Fulghum paulkf@microgate.com
+ * for Microgate Corporation
+ *
+ * Microgate and SyncLink are registered trademarks of Microgate Corporation
+ *
+ * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
+ *     Al Longyear <longyear@netcom.com>,
+ *     Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
+ *
+ * Original release 01/11/99
+ *
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * This module implements the tty line discipline N_HDLC for use with
+ * tty device drivers that support bit-synchronous HDLC communications.
+ *
+ * All HDLC data is frame oriented which means:
+ *
+ * 1. tty write calls represent one complete transmit frame of data
+ *    The device driver should accept the complete frame or none of 
+ *    the frame (busy) in the write method. Each write call should have
+ *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
+ *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
+ *    should include any crc bytes required. For example, when using
+ *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
+ *    the application may transmit is limited to 65531 bytes. For CCITT
+ *    CRC16, the maximum application frame size would be 65533.
+ *
+ *
+ * 2. receive callbacks from the device driver represents
+ *    one received frame. The device driver should bypass
+ *    the tty flip buffer and call the line discipline receive
+ *    callback directly to avoid fragmenting or concatenating
+ *    multiple frames into a single receive callback.
+ *
+ *    The HDLC line discipline queues the receive frames in separate
+ *    buffers so complete receive frames can be returned by the
+ *    tty read calls.
+ *
+ * 3. tty read calls returns an entire frame of data or nothing.
+ *    
+ * 4. all send and receive data is considered raw. No processing
+ *    or translation is performed by the line discipline, regardless
+ *    of the tty flags
+ *
+ * 5. When line discipline is queried for the amount of receive
+ *    data available (FIOC), 0 is returned if no data available,
+ *    otherwise the count of the next available frame is returned.
+ *    (instead of the sum of all received frame counts).
+ *
+ * These conventions allow the standard tty programming interface
+ * to be used for synchronous HDLC applications when used with
+ * this line discipline (or another line discipline that is frame
+ * oriented such as N_PPP).
+ *
+ * The SyncLink driver (synclink.c) implements both asynchronous
+ * (using standard line discipline N_TTY) and synchronous HDLC
+ * (using N_HDLC) communications, with the latter using the above
+ * conventions.
+ *
+ * This implementation is very basic and does not maintain
+ * any statistics. The main point is to enforce the raw data
+ * and frame orientation of HDLC communications.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ */
+
+#define HDLC_MAGIC 0x239e
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#undef VERSION
+#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
+
+#include <linux/poll.h>
+#include <linux/in.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/if.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/termios.h>
+#include <asm/uaccess.h>
+
+/*
+ * Buffers for individual HDLC frames
+ */
+#define MAX_HDLC_FRAME_SIZE 65535 
+#define DEFAULT_RX_BUF_COUNT 10
+#define MAX_RX_BUF_COUNT 60
+#define DEFAULT_TX_BUF_COUNT 3
+
+struct n_hdlc_buf {
+       struct n_hdlc_buf *link;
+       int               count;
+       char              buf[1];
+};
+
+#define        N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
+
+struct n_hdlc_buf_list {
+       struct n_hdlc_buf *head;
+       struct n_hdlc_buf *tail;
+       int               count;
+       spinlock_t        spinlock;
+};
+
+/**
+ * struct n_hdlc - per device instance data structure
+ * @magic - magic value for structure
+ * @flags - miscellaneous control flags
+ * @tty - ptr to TTY structure
+ * @backup_tty - TTY to use if tty gets closed
+ * @tbusy - reentrancy flag for tx wakeup code
+ * @woke_up - FIXME: describe this field
+ * @tbuf - currently transmitting tx buffer
+ * @tx_buf_list - list of pending transmit frame buffers
+ * @rx_buf_list - list of received frame buffers
+ * @tx_free_buf_list - list unused transmit frame buffers
+ * @rx_free_buf_list - list unused received frame buffers
+ */
+struct n_hdlc {
+       int                     magic;
+       __u32                   flags;
+       struct tty_struct       *tty;
+       struct tty_struct       *backup_tty;
+       int                     tbusy;
+       int                     woke_up;
+       struct n_hdlc_buf       *tbuf;
+       struct n_hdlc_buf_list  tx_buf_list;
+       struct n_hdlc_buf_list  rx_buf_list;
+       struct n_hdlc_buf_list  tx_free_buf_list;
+       struct n_hdlc_buf_list  rx_free_buf_list;
+};
+
+/*
+ * HDLC buffer list manipulation functions
+ */
+static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+                          struct n_hdlc_buf *buf);
+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
+
+/* Local functions */
+
+static struct n_hdlc *n_hdlc_alloc (void);
+
+/* debug level can be set by insmod for debugging purposes */
+#define DEBUG_LEVEL_INFO       1
+static int debuglevel;
+
+/* max frame size for memory allocations */
+static int maxframe = 4096;
+
+/* TTY callbacks */
+
+static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
+                          __u8 __user *buf, size_t nr);
+static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
+                           const unsigned char *buf, size_t nr);
+static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg);
+static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
+                                   poll_table *wait);
+static int n_hdlc_tty_open(struct tty_struct *tty);
+static void n_hdlc_tty_close(struct tty_struct *tty);
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
+                              char *fp, int count);
+static void n_hdlc_tty_wakeup(struct tty_struct *tty);
+
+#define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
+
+#define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
+#define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
+
+static void flush_rx_queue(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       struct n_hdlc_buf *buf;
+
+       while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
+               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
+}
+
+static void flush_tx_queue(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       struct n_hdlc_buf *buf;
+       unsigned long flags;
+
+       while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
+               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       if (n_hdlc->tbuf) {
+               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
+               n_hdlc->tbuf = NULL;
+       }
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+}
+
+static struct tty_ldisc_ops n_hdlc_ldisc = {
+       .owner          = THIS_MODULE,
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "hdlc",
+       .open           = n_hdlc_tty_open,
+       .close          = n_hdlc_tty_close,
+       .read           = n_hdlc_tty_read,
+       .write          = n_hdlc_tty_write,
+       .ioctl          = n_hdlc_tty_ioctl,
+       .poll           = n_hdlc_tty_poll,
+       .receive_buf    = n_hdlc_tty_receive,
+       .write_wakeup   = n_hdlc_tty_wakeup,
+       .flush_buffer   = flush_rx_queue,
+};
+
+/**
+ * n_hdlc_release - release an n_hdlc per device line discipline info structure
+ * @n_hdlc - per device line discipline info structure
+ */
+static void n_hdlc_release(struct n_hdlc *n_hdlc)
+{
+       struct tty_struct *tty = n_hdlc2tty (n_hdlc);
+       struct n_hdlc_buf *buf;
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
+               
+       /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
+       wake_up_interruptible (&tty->read_wait);
+       wake_up_interruptible (&tty->write_wait);
+
+       if (tty->disc_data == n_hdlc)
+               tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
+
+       /* Release transmit and receive buffers */
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       kfree(n_hdlc->tbuf);
+       kfree(n_hdlc);
+       
+}      /* end of n_hdlc_release() */
+
+/**
+ * n_hdlc_tty_close - line discipline close
+ * @tty - pointer to tty info structure
+ *
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
+ */
+static void n_hdlc_tty_close(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
+               
+       if (n_hdlc != NULL) {
+               if (n_hdlc->magic != HDLC_MAGIC) {
+                       printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
+                       return;
+               }
+#if defined(TTY_NO_WRITE_SPLIT)
+               clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+               tty->disc_data = NULL;
+               if (tty == n_hdlc->backup_tty)
+                       n_hdlc->backup_tty = NULL;
+               if (tty != n_hdlc->tty)
+                       return;
+               if (n_hdlc->backup_tty) {
+                       n_hdlc->tty = n_hdlc->backup_tty;
+               } else {
+                       n_hdlc_release (n_hdlc);
+               }
+       }
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
+               
+}      /* end of n_hdlc_tty_close() */
+
+/**
+ * n_hdlc_tty_open - called when line discipline changed to n_hdlc
+ * @tty - pointer to tty info structure
+ *
+ * Returns 0 if success, otherwise error code
+ */
+static int n_hdlc_tty_open (struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
+               __FILE__,__LINE__,
+               tty->name);
+               
+       /* There should not be an existing table for this slot. */
+       if (n_hdlc) {
+               printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
+               return -EEXIST;
+       }
+       
+       n_hdlc = n_hdlc_alloc();
+       if (!n_hdlc) {
+               printk (KERN_ERR "n_hdlc_alloc failed\n");
+               return -ENFILE;
+       }
+               
+       tty->disc_data = n_hdlc;
+       n_hdlc->tty    = tty;
+       tty->receive_room = 65536;
+       
+#if defined(TTY_NO_WRITE_SPLIT)
+       /* change tty_io write() to not split large writes into 8K chunks */
+       set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+       
+       /* flush receive data from driver */
+       tty_driver_flush_buffer(tty);
+               
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
+               
+       return 0;
+       
+}      /* end of n_tty_hdlc_open() */
+
+/**
+ * n_hdlc_send_frames - send frames on pending send buffer list
+ * @n_hdlc - pointer to ldisc instance data
+ * @tty - pointer to tty instance data
+ *
+ * Send frames on pending send buffer list until the driver does not accept a
+ * frame (busy) this function is called after adding a frame to the send buffer
+ * list and by the tty wakeup callback.
+ */
+static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
+{
+       register int actual;
+       unsigned long flags;
+       struct n_hdlc_buf *tbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
+ check_again:
+               
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       if (n_hdlc->tbusy) {
+               n_hdlc->woke_up = 1;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+               return;
+       }
+       n_hdlc->tbusy = 1;
+       n_hdlc->woke_up = 0;
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+
+       /* get current transmit buffer or get new transmit */
+       /* buffer from list of pending transmit buffers */
+               
+       tbuf = n_hdlc->tbuf;
+       if (!tbuf)
+               tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               
+       while (tbuf) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d)sending frame %p, count=%d\n",
+                               __FILE__,__LINE__,tbuf,tbuf->count);
+                       
+               /* Send the next block of data to device */
+               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+               actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
+
+               /* rollback was possible and has been done */
+               if (actual == -ERESTARTSYS) {
+                       n_hdlc->tbuf = tbuf;
+                       break;
+               }
+               /* if transmit error, throw frame away by */
+               /* pretending it was accepted by driver */
+               if (actual < 0)
+                       actual = tbuf->count;
+               
+               if (actual == tbuf->count) {
+                       if (debuglevel >= DEBUG_LEVEL_INFO)     
+                               printk("%s(%d)frame %p completed\n",
+                                       __FILE__,__LINE__,tbuf);
+                                       
+                       /* free current transmit buffer */
+                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
+                       
+                       /* this tx buffer is done */
+                       n_hdlc->tbuf = NULL;
+                       
+                       /* wait up sleeping writers */
+                       wake_up_interruptible(&tty->write_wait);
+       
+                       /* get next pending transmit buffer */
+                       tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               } else {
+                       if (debuglevel >= DEBUG_LEVEL_INFO)     
+                               printk("%s(%d)frame %p pending\n",
+                                       __FILE__,__LINE__,tbuf);
+                                       
+                       /* buffer not accepted by driver */
+                       /* set this buffer as pending buffer */
+                       n_hdlc->tbuf = tbuf;
+                       break;
+               }
+       }
+       
+       if (!tbuf)
+               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
+       
+       /* Clear the re-entry flag */
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       n_hdlc->tbusy = 0;
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
+       
+        if (n_hdlc->woke_up)
+         goto check_again;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
+               
+}      /* end of n_hdlc_send_frames() */
+
+/**
+ * n_hdlc_tty_wakeup - Callback for transmit wakeup
+ * @tty        - pointer to associated tty instance data
+ *
+ * Called when low level device driver can accept more send data.
+ */
+static void n_hdlc_tty_wakeup(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
+               
+       if (!n_hdlc)
+               return;
+
+       if (tty != n_hdlc->tty) {
+               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               return;
+       }
+
+       n_hdlc_send_frames (n_hdlc, tty);
+               
+}      /* end of n_hdlc_tty_wakeup() */
+
+/**
+ * n_hdlc_tty_receive - Called by tty driver when receive data is available
+ * @tty        - pointer to tty instance data
+ * @data - pointer to received data
+ * @flags - pointer to flags for data
+ * @count - count of received data in bytes
+ *
+ * Called by tty low level driver when receive data is available. Data is
+ * interpreted as one HDLC frame.
+ */
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
+                              char *flags, int count)
+{
+       register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       register struct n_hdlc_buf *buf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
+                       __FILE__,__LINE__, count);
+               
+       /* This can happen if stuff comes in on the backup tty */
+       if (!n_hdlc || tty != n_hdlc->tty)
+               return;
+               
+       /* verify line is using HDLC discipline */
+       if (n_hdlc->magic != HDLC_MAGIC) {
+               printk("%s(%d) line not using HDLC discipline\n",
+                       __FILE__,__LINE__);
+               return;
+       }
+       
+       if ( count>maxframe ) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d) rx count>maxframesize, data discarded\n",
+                              __FILE__,__LINE__);
+               return;
+       }
+
+       /* get a free HDLC buffer */    
+       buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
+       if (!buf) {
+               /* no buffers in free list, attempt to allocate another rx buffer */
+               /* unless the maximum count has been reached */
+               if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
+                       buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
+       }
+       
+       if (!buf) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d) no more rx buffers, data discarded\n",
+                              __FILE__,__LINE__);
+               return;
+       }
+               
+       /* copy received data to HDLC buffer */
+       memcpy(buf->buf,data,count);
+       buf->count=count;
+
+       /* add HDLC buffer to list of received frames */
+       n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
+       
+       /* wake up any blocked reads and perform async signalling */
+       wake_up_interruptible (&tty->read_wait);
+       if (n_hdlc->tty->fasync != NULL)
+               kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
+
+}      /* end of n_hdlc_tty_receive() */
+
+/**
+ * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
+ * @tty - pointer to tty instance data
+ * @file - pointer to open file object
+ * @buf - pointer to returned data buffer
+ * @nr - size of returned data buffer
+ *     
+ * Returns the number of bytes returned or error code.
+ */
+static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
+                          __u8 __user *buf, size_t nr)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       int ret;
+       struct n_hdlc_buf *rbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
+               
+       /* Validate the pointers */
+       if (!n_hdlc)
+               return -EIO;
+
+       /* verify user access to buffer */
+       if (!access_ok(VERIFY_WRITE, buf, nr)) {
+               printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
+               "buffer\n", __FILE__, __LINE__);
+               return -EFAULT;
+       }
+
+       tty_lock();
+
+       for (;;) {
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                       tty_unlock();
+                       return -EIO;
+               }
+
+               n_hdlc = tty2n_hdlc (tty);
+               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
+                        tty != n_hdlc->tty) {
+                       tty_unlock();
+                       return 0;
+               }
+
+               rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
+               if (rbuf)
+                       break;
+                       
+               /* no data */
+               if (file->f_flags & O_NONBLOCK) {
+                       tty_unlock();
+                       return -EAGAIN;
+               }
+                       
+               interruptible_sleep_on (&tty->read_wait);
+               if (signal_pending(current)) {
+                       tty_unlock();
+                       return -EINTR;
+               }
+       }
+               
+       if (rbuf->count > nr)
+               /* frame too large for caller's buffer (discard frame) */
+               ret = -EOVERFLOW;
+       else {
+               /* Copy the data to the caller's buffer */
+               if (copy_to_user(buf, rbuf->buf, rbuf->count))
+                       ret = -EFAULT;
+               else
+                       ret = rbuf->count;
+       }
+       
+       /* return HDLC buffer to free list unless the free list */
+       /* count has exceeded the default value, in which case the */
+       /* buffer is freed back to the OS to conserve memory */
+       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
+               kfree(rbuf);
+       else    
+               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
+       tty_unlock();
+       return ret;
+       
+}      /* end of n_hdlc_tty_read() */
+
+/**
+ * n_hdlc_tty_write - write a single frame of data to device
+ * @tty        - pointer to associated tty device instance data
+ * @file - pointer to file object data
+ * @data - pointer to transmit data (one frame)
+ * @count - size of transmit frame in bytes
+ *             
+ * Returns the number of bytes written (or error code).
+ */
+static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
+                           const unsigned char *data, size_t count)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       int error = 0;
+       DECLARE_WAITQUEUE(wait, current);
+       struct n_hdlc_buf *tbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
+                       __FILE__,__LINE__,count);
+               
+       /* Verify pointers */
+       if (!n_hdlc)
+               return -EIO;
+
+       if (n_hdlc->magic != HDLC_MAGIC)
+               return -EIO;
+
+       /* verify frame size */
+       if (count > maxframe ) {
+               if (debuglevel & DEBUG_LEVEL_INFO)
+                       printk (KERN_WARNING
+                               "n_hdlc_tty_write: truncating user packet "
+                               "from %lu to %d\n", (unsigned long) count,
+                               maxframe );
+               count = maxframe;
+       }
+       
+       tty_lock();
+
+       add_wait_queue(&tty->write_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       
+       /* Allocate transmit buffer */
+       /* sleep until transmit buffer available */             
+       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
+               if (file->f_flags & O_NONBLOCK) {
+                       error = -EAGAIN;
+                       break;
+               }
+               schedule();
+                       
+               n_hdlc = tty2n_hdlc (tty);
+               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
+                   tty != n_hdlc->tty) {
+                       printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
+                       error = -EIO;
+                       break;
+               }
+                       
+               if (signal_pending(current)) {
+                       error = -EINTR;
+                       break;
+               }
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+
+       if (!error) {           
+               /* Retrieve the user's buffer */
+               memcpy(tbuf->buf, data, count);
+
+               /* Send the data */
+               tbuf->count = error = count;
+               n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
+               n_hdlc_send_frames(n_hdlc,tty);
+       }
+       tty_unlock();
+       return error;
+       
+}      /* end of n_hdlc_tty_write() */
+
+/**
+ * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
+ * @tty - pointer to tty instance data
+ * @file - pointer to open file object for device
+ * @cmd - IOCTL command code
+ * @arg - argument for IOCTL call (cmd dependent)
+ *
+ * Returns command dependent result.
+ */
+static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       int error = 0;
+       int count;
+       unsigned long flags;
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
+                       __FILE__,__LINE__,cmd);
+               
+       /* Verify the status of the device */
+       if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
+               return -EBADF;
+
+       switch (cmd) {
+       case FIONREAD:
+               /* report count of read data available */
+               /* in next available frame (if any) */
+               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+               if (n_hdlc->rx_buf_list.head)
+                       count = n_hdlc->rx_buf_list.head->count;
+               else
+                       count = 0;
+               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+               error = put_user(count, (int __user *)arg);
+               break;
+
+       case TIOCOUTQ:
+               /* get the pending tx byte count in the driver */
+               count = tty_chars_in_buffer(tty);
+               /* add size of next output frame in queue */
+               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+               if (n_hdlc->tx_buf_list.head)
+                       count += n_hdlc->tx_buf_list.head->count;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+               error = put_user(count, (int __user *)arg);
+               break;
+
+       case TCFLSH:
+               switch (arg) {
+               case TCIOFLUSH:
+               case TCOFLUSH:
+                       flush_tx_queue(tty);
+               }
+               /* fall through to default */
+
+       default:
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
+               break;
+       }
+       return error;
+       
+}      /* end of n_hdlc_tty_ioctl() */
+
+/**
+ * n_hdlc_tty_poll - TTY callback for poll system call
+ * @tty - pointer to tty instance data
+ * @filp - pointer to open file object for device
+ * @poll_table - wait queue for operations
+ * 
+ * Determine which operations (read/write) will not block and return info
+ * to caller.
+ * Returns a bit mask containing info on which ops will not block.
+ */
+static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
+                                   poll_table *wait)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       unsigned int mask = 0;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
+               
+       if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
+               /* queue current process into any wait queue that */
+               /* may awaken in the future (read and write) */
+
+               poll_wait(filp, &tty->read_wait, wait);
+               poll_wait(filp, &tty->write_wait, wait);
+
+               /* set bits for operations that won't block */
+               if (n_hdlc->rx_buf_list.head)
+                       mask |= POLLIN | POLLRDNORM;    /* readable */
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+                       mask |= POLLHUP;
+               if (tty_hung_up_p(filp))
+                       mask |= POLLHUP;
+               if (!tty_is_writelocked(tty) &&
+                               n_hdlc->tx_free_buf_list.head)
+                       mask |= POLLOUT | POLLWRNORM;   /* writable */
+       }
+       return mask;
+}      /* end of n_hdlc_tty_poll() */
+
+/**
+ * n_hdlc_alloc - allocate an n_hdlc instance data structure
+ *
+ * Returns a pointer to newly created structure if success, otherwise %NULL
+ */
+static struct n_hdlc *n_hdlc_alloc(void)
+{
+       struct n_hdlc_buf *buf;
+       int i;
+       struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
+
+       if (!n_hdlc)
+               return NULL;
+
+       memset(n_hdlc, 0, sizeof(*n_hdlc));
+
+       n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
+       
+       /* allocate free rx buffer list */
+       for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
+               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
+               if (buf)
+                       n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
+               else if (debuglevel >= DEBUG_LEVEL_INFO)        
+                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
+       }
+       
+       /* allocate free tx buffer list */
+       for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
+               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
+               if (buf)
+                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
+               else if (debuglevel >= DEBUG_LEVEL_INFO)        
+                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
+       }
+       
+       /* Initialize the control block */
+       n_hdlc->magic  = HDLC_MAGIC;
+       n_hdlc->flags  = 0;
+       
+       return n_hdlc;
+       
+}      /* end of n_hdlc_alloc() */
+
+/**
+ * n_hdlc_buf_list_init - initialize specified HDLC buffer list
+ * @list - pointer to buffer list
+ */
+static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
+{
+       memset(list, 0, sizeof(*list));
+       spin_lock_init(&list->spinlock);
+}      /* end of n_hdlc_buf_list_init() */
+
+/**
+ * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
+ * @list - pointer to buffer list
+ * @buf        - pointer to buffer
+ */
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+                          struct n_hdlc_buf *buf)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&list->spinlock,flags);
+       
+       buf->link=NULL;
+       if (list->tail)
+               list->tail->link = buf;
+       else
+               list->head = buf;
+       list->tail = buf;
+       (list->count)++;
+       
+       spin_unlock_irqrestore(&list->spinlock,flags);
+       
+}      /* end of n_hdlc_buf_put() */
+
+/**
+ * n_hdlc_buf_get - remove and return an HDLC buffer from list
+ * @list - pointer to HDLC buffer list
+ * 
+ * Remove and return an HDLC buffer from the head of the specified HDLC buffer
+ * list.
+ * Returns a pointer to HDLC buffer if available, otherwise %NULL.
+ */
+static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
+{
+       unsigned long flags;
+       struct n_hdlc_buf *buf;
+       spin_lock_irqsave(&list->spinlock,flags);
+       
+       buf = list->head;
+       if (buf) {
+               list->head = buf->link;
+               (list->count)--;
+       }
+       if (!list->head)
+               list->tail = NULL;
+       
+       spin_unlock_irqrestore(&list->spinlock,flags);
+       return buf;
+       
+}      /* end of n_hdlc_buf_get() */
+
+static char hdlc_banner[] __initdata =
+       KERN_INFO "HDLC line discipline maxframe=%u\n";
+static char hdlc_register_ok[] __initdata =
+       KERN_INFO "N_HDLC line discipline registered.\n";
+static char hdlc_register_fail[] __initdata =
+       KERN_ERR "error registering line discipline: %d\n";
+static char hdlc_init_fail[] __initdata =
+       KERN_INFO "N_HDLC: init failure %d\n";
+
+static int __init n_hdlc_init(void)
+{
+       int status;
+
+       /* range check maxframe arg */
+       if (maxframe < 4096)
+               maxframe = 4096;
+       else if (maxframe > 65535)
+               maxframe = 65535;
+
+       printk(hdlc_banner, maxframe);
+
+       status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
+       if (!status)
+               printk(hdlc_register_ok);
+       else
+               printk(hdlc_register_fail, status);
+
+       if (status)
+               printk(hdlc_init_fail, status);
+       return status;
+       
+}      /* end of init_module() */
+
+static char hdlc_unregister_ok[] __exitdata =
+       KERN_INFO "N_HDLC: line discipline unregistered\n";
+static char hdlc_unregister_fail[] __exitdata =
+       KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
+
+static void __exit n_hdlc_exit(void)
+{
+       /* Release tty registration of line discipline */
+       int status = tty_unregister_ldisc(N_HDLC);
+
+       if (status)
+               printk(hdlc_unregister_fail, status);
+       else
+               printk(hdlc_unregister_ok);
+}
+
+module_init(n_hdlc_init);
+module_exit(n_hdlc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
+module_param(debuglevel, int, 0);
+module_param(maxframe, int, 0);
+MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
new file mode 100644 (file)
index 0000000..88dda0c
--- /dev/null
@@ -0,0 +1,1264 @@
+/* r3964 linediscipline for linux
+ *
+ * -----------------------------------------------------------
+ * Copyright by 
+ * Philips Automation Projects
+ * Kassel (Germany)
+ * -----------------------------------------------------------
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ *
+ * Author:
+ * L. Haag
+ *
+ * $Log: n_r3964.c,v $
+ * Revision 1.10  2001/03/18 13:02:24  dwmw2
+ * Fix timer usage, use spinlocks properly.
+ *
+ * Revision 1.9  2001/03/18 12:52:14  dwmw2
+ * Merge changes in 2.4.2
+ *
+ * Revision 1.8  2000/03/23 14:14:54  dwmw2
+ * Fix race in sleeping in r3964_read()
+ *
+ * Revision 1.7  1999/28/08 11:41:50  dwmw2
+ * Port to 2.3 kernel
+ *
+ * Revision 1.6  1998/09/30 00:40:40  dwmw2
+ * Fixed compilation on 2.0.x kernels
+ * Updated to newly registered tty-ldisc number 9
+ *
+ * Revision 1.5  1998/09/04 21:57:36  dwmw2
+ * Signal handling bug fixes, port to 2.1.x.
+ *
+ * Revision 1.4  1998/04/02 20:26:59  lhaag
+ * select, blocking, ...
+ *
+ * Revision 1.3  1998/02/12 18:58:43  root
+ * fixed some memory leaks
+ * calculation of checksum characters
+ *
+ * Revision 1.2  1998/02/07 13:03:34  root
+ * ioctl read_telegram
+ *
+ * Revision 1.1  1998/02/06 19:21:03  root
+ * Initial revision
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/ioctl.h>
+#include <linux/n_r3964.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+/*#define DEBUG_QUEUE*/
+
+/* Log successful handshake and protocol operations  */
+/*#define DEBUG_PROTO_S*/
+
+/* Log handshake and protocol errors: */
+/*#define DEBUG_PROTO_E*/
+
+/* Log Linediscipline operations (open, close, read, write...): */
+/*#define DEBUG_LDISC*/
+
+/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
+/*#define DEBUG_MODUL*/
+
+/* Macro helpers for debug output: */
+#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
+
+#ifdef DEBUG_MODUL
+#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_M(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_PROTO_S
+#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_PS(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_PROTO_E
+#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_PE(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_LDISC
+#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_L(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_QUEUE
+#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_Q(fmt, arg...) do {} while (0)
+#endif
+static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
+static void put_char(struct r3964_info *pInfo, unsigned char ch);
+static void trigger_transmit(struct r3964_info *pInfo);
+static void retry_transmit(struct r3964_info *pInfo);
+static void transmit_block(struct r3964_info *pInfo);
+static void receive_char(struct r3964_info *pInfo, const unsigned char c);
+static void receive_error(struct r3964_info *pInfo, const char flag);
+static void on_timeout(unsigned long priv);
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+               unsigned char __user * buf);
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+               int error_code, struct r3964_block_header *pBlock);
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+               struct r3964_client_info *pClient);
+static void remove_client_block(struct r3964_info *pInfo,
+               struct r3964_client_info *pClient);
+
+static int r3964_open(struct tty_struct *tty);
+static void r3964_close(struct tty_struct *tty);
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+               unsigned char __user * buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+               const unsigned char *buf, size_t nr);
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg);
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+               struct poll_table_struct *wait);
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+               char *fp, int count);
+
+static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
+       .owner = THIS_MODULE,
+       .magic = TTY_LDISC_MAGIC,
+       .name = "R3964",
+       .open = r3964_open,
+       .close = r3964_close,
+       .read = r3964_read,
+       .write = r3964_write,
+       .ioctl = r3964_ioctl,
+       .set_termios = r3964_set_termios,
+       .poll = r3964_poll,
+       .receive_buf = r3964_receive_buf,
+};
+
+static void dump_block(const unsigned char *block, unsigned int length)
+{
+       unsigned int i, j;
+       char linebuf[16 * 3 + 1];
+
+       for (i = 0; i < length; i += 16) {
+               for (j = 0; (j < 16) && (j + i < length); j++) {
+                       sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
+               }
+               linebuf[3 * j] = '\0';
+               TRACE_PS("%s", linebuf);
+       }
+}
+
+/*************************************************************
+ * Driver initialisation
+ *************************************************************/
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+static void __exit r3964_exit(void)
+{
+       int status;
+
+       TRACE_M("cleanup_module()");
+
+       status = tty_unregister_ldisc(N_R3964);
+
+       if (status != 0) {
+               printk(KERN_ERR "r3964: error unregistering linediscipline: "
+                               "%d\n", status);
+       } else {
+               TRACE_L("linediscipline successfully unregistered");
+       }
+}
+
+static int __init r3964_init(void)
+{
+       int status;
+
+       printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
+
+       /*
+        * Register the tty line discipline
+        */
+
+       status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
+       if (status == 0) {
+               TRACE_L("line discipline %d registered", N_R3964);
+               TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
+                       tty_ldisc_N_R3964.num);
+               TRACE_L("open=%p", tty_ldisc_N_R3964.open);
+               TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
+       } else {
+               printk(KERN_ERR "r3964: error registering line discipline: "
+                               "%d\n", status);
+       }
+       return status;
+}
+
+module_init(r3964_init);
+module_exit(r3964_exit);
+
+/*************************************************************
+ * Protocol implementation routines
+ *************************************************************/
+
+static void add_tx_queue(struct r3964_info *pInfo,
+                        struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pHeader->next = NULL;
+
+       if (pInfo->tx_last == NULL) {
+               pInfo->tx_first = pInfo->tx_last = pHeader;
+       } else {
+               pInfo->tx_last->next = pHeader;
+               pInfo->tx_last = pHeader;
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
+               pHeader, pHeader->length, pInfo->tx_first);
+}
+
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
+{
+       struct r3964_block_header *pHeader;
+       unsigned long flags;
+#ifdef DEBUG_QUEUE
+       struct r3964_block_header *pDump;
+#endif
+
+       pHeader = pInfo->tx_first;
+
+       if (pHeader == NULL)
+               return;
+
+#ifdef DEBUG_QUEUE
+       printk("r3964: remove_from_tx_queue: %p, length %u - ",
+               pHeader, pHeader->length);
+       for (pDump = pHeader; pDump; pDump = pDump->next)
+               printk("%p ", pDump);
+       printk("\n");
+#endif
+
+       if (pHeader->owner) {
+               if (error_code) {
+                       add_msg(pHeader->owner, R3964_MSG_ACK, 0,
+                               error_code, NULL);
+               } else {
+                       add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
+                               error_code, NULL);
+               }
+               wake_up_interruptible(&pInfo->read_wait);
+       }
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pInfo->tx_first = pHeader->next;
+       if (pInfo->tx_first == NULL) {
+               pInfo->tx_last = NULL;
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       kfree(pHeader);
+       TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
+
+       TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
+               pInfo->tx_first, pInfo->tx_last);
+}
+
+static void add_rx_queue(struct r3964_info *pInfo,
+                        struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pHeader->next = NULL;
+
+       if (pInfo->rx_last == NULL) {
+               pInfo->rx_first = pInfo->rx_last = pHeader;
+       } else {
+               pInfo->rx_last->next = pHeader;
+               pInfo->rx_last = pHeader;
+       }
+       pInfo->blocks_in_rx_queue++;
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
+               pHeader, pHeader->length,
+               pInfo->rx_first, pInfo->blocks_in_rx_queue);
+}
+
+static void remove_from_rx_queue(struct r3964_info *pInfo,
+                                struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+       struct r3964_block_header *pFind;
+
+       if (pHeader == NULL)
+               return;
+
+       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+       TRACE_Q("remove_from_rx_queue: %p, length %u",
+               pHeader, pHeader->length);
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       if (pInfo->rx_first == pHeader) {
+               /* Remove the first block in the linked list: */
+               pInfo->rx_first = pHeader->next;
+
+               if (pInfo->rx_first == NULL) {
+                       pInfo->rx_last = NULL;
+               }
+               pInfo->blocks_in_rx_queue--;
+       } else {
+               /* Find block to remove: */
+               for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
+                       if (pFind->next == pHeader) {
+                               /* Got it. */
+                               pFind->next = pHeader->next;
+                               pInfo->blocks_in_rx_queue--;
+                               if (pFind->next == NULL) {
+                                       /* Oh, removed the last one! */
+                                       pInfo->rx_last = pFind;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       kfree(pHeader);
+       TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
+
+       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+}
+
+static void put_char(struct r3964_info *pInfo, unsigned char ch)
+{
+       struct tty_struct *tty = pInfo->tty;
+       /* FIXME: put_char should not be called from an IRQ */
+       tty_put_char(tty, ch);
+       pInfo->bcc ^= ch;
+}
+
+static void flush(struct r3964_info *pInfo)
+{
+       struct tty_struct *tty = pInfo->tty;
+
+       if (tty == NULL || tty->ops->flush_chars == NULL)
+               return;
+       tty->ops->flush_chars(tty);
+}
+
+static void trigger_transmit(struct r3964_info *pInfo)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
+               pInfo->state = R3964_TX_REQUEST;
+               pInfo->nRetry = 0;
+               pInfo->flags &= ~R3964_ERROR;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+
+               TRACE_PS("trigger_transmit - sent STX");
+
+               put_char(pInfo, STX);
+               flush(pInfo);
+
+               pInfo->bcc = 0;
+       } else {
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+       }
+}
+
+static void retry_transmit(struct r3964_info *pInfo)
+{
+       if (pInfo->nRetry < R3964_MAX_RETRIES) {
+               TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
+               pInfo->bcc = 0;
+               put_char(pInfo, STX);
+               flush(pInfo);
+               pInfo->state = R3964_TX_REQUEST;
+               pInfo->nRetry++;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+       } else {
+               TRACE_PE("transmission failed after %d retries",
+                        R3964_MAX_RETRIES);
+
+               remove_from_tx_queue(pInfo, R3964_TX_FAIL);
+
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+
+               trigger_transmit(pInfo);
+       }
+}
+
+static void transmit_block(struct r3964_info *pInfo)
+{
+       struct tty_struct *tty = pInfo->tty;
+       struct r3964_block_header *pBlock = pInfo->tx_first;
+       int room = 0;
+
+       if (tty == NULL || pBlock == NULL) {
+               return;
+       }
+
+       room = tty_write_room(tty);
+
+       TRACE_PS("transmit_block %p, room %d, length %d",
+                pBlock, room, pBlock->length);
+
+       while (pInfo->tx_position < pBlock->length) {
+               if (room < 2)
+                       break;
+
+               if (pBlock->data[pInfo->tx_position] == DLE) {
+                       /* send additional DLE char: */
+                       put_char(pInfo, DLE);
+               }
+               put_char(pInfo, pBlock->data[pInfo->tx_position++]);
+
+               room--;
+       }
+
+       if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
+               put_char(pInfo, DLE);
+               put_char(pInfo, ETX);
+               if (pInfo->flags & R3964_BCC) {
+                       put_char(pInfo, pInfo->bcc);
+               }
+               pInfo->state = R3964_WAIT_FOR_TX_ACK;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+       }
+       flush(pInfo);
+}
+
+static void on_receive_block(struct r3964_info *pInfo)
+{
+       unsigned int length;
+       struct r3964_client_info *pClient;
+       struct r3964_block_header *pBlock;
+
+       length = pInfo->rx_position;
+
+       /* compare byte checksum characters: */
+       if (pInfo->flags & R3964_BCC) {
+               if (pInfo->bcc != pInfo->last_rx) {
+                       TRACE_PE("checksum error - got %x but expected %x",
+                                pInfo->last_rx, pInfo->bcc);
+                       pInfo->flags |= R3964_CHECKSUM;
+               }
+       }
+
+       /* check for errors (parity, overrun,...): */
+       if (pInfo->flags & R3964_ERROR) {
+               TRACE_PE("on_receive_block - transmission failed error %x",
+                        pInfo->flags & R3964_ERROR);
+
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               if (pInfo->nRetry < R3964_MAX_RETRIES) {
+                       pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
+                       pInfo->nRetry++;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
+               } else {
+                       TRACE_PE("on_receive_block - failed after max retries");
+                       pInfo->state = R3964_IDLE;
+               }
+               return;
+       }
+
+       /* received block; submit DLE: */
+       put_char(pInfo, DLE);
+       flush(pInfo);
+       del_timer_sync(&pInfo->tmr);
+       TRACE_PS(" rx success: got %d chars", length);
+
+       /* prepare struct r3964_block_header: */
+       pBlock = kmalloc(length + sizeof(struct r3964_block_header),
+                       GFP_KERNEL);
+       TRACE_M("on_receive_block - kmalloc %p", pBlock);
+
+       if (pBlock == NULL)
+               return;
+
+       pBlock->length = length;
+       pBlock->data = ((unsigned char *)pBlock) +
+                       sizeof(struct r3964_block_header);
+       pBlock->locks = 0;
+       pBlock->next = NULL;
+       pBlock->owner = NULL;
+
+       memcpy(pBlock->data, pInfo->rx_buf, length);
+
+       /* queue block into rx_queue: */
+       add_rx_queue(pInfo, pBlock);
+
+       /* notify attached client processes: */
+       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+               if (pClient->sig_flags & R3964_SIG_DATA) {
+                       add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
+                               pBlock);
+               }
+       }
+       wake_up_interruptible(&pInfo->read_wait);
+
+       pInfo->state = R3964_IDLE;
+
+       trigger_transmit(pInfo);
+}
+
+static void receive_char(struct r3964_info *pInfo, const unsigned char c)
+{
+       switch (pInfo->state) {
+       case R3964_TX_REQUEST:
+               if (c == DLE) {
+                       TRACE_PS("TX_REQUEST - got DLE");
+
+                       pInfo->state = R3964_TRANSMITTING;
+                       pInfo->tx_position = 0;
+
+                       transmit_block(pInfo);
+               } else if (c == STX) {
+                       if (pInfo->nRetry == 0) {
+                               TRACE_PE("TX_REQUEST - init conflict");
+                               if (pInfo->priority == R3964_SLAVE) {
+                                       goto start_receiving;
+                               }
+                       } else {
+                               TRACE_PE("TX_REQUEST - secondary init "
+                                       "conflict!? Switching to SLAVE mode "
+                                       "for next rx.");
+                               goto start_receiving;
+                       }
+               } else {
+                       TRACE_PE("TX_REQUEST - char != DLE: %x", c);
+                       retry_transmit(pInfo);
+               }
+               break;
+       case R3964_TRANSMITTING:
+               if (c == NAK) {
+                       TRACE_PE("TRANSMITTING - got NAK");
+                       retry_transmit(pInfo);
+               } else {
+                       TRACE_PE("TRANSMITTING - got invalid char");
+
+                       pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+               }
+               break;
+       case R3964_WAIT_FOR_TX_ACK:
+               if (c == DLE) {
+                       TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
+                       remove_from_tx_queue(pInfo, R3964_OK);
+
+                       pInfo->state = R3964_IDLE;
+                       trigger_transmit(pInfo);
+               } else {
+                       retry_transmit(pInfo);
+               }
+               break;
+       case R3964_WAIT_FOR_RX_REPEAT:
+               /* FALLTHROUGH */
+       case R3964_IDLE:
+               if (c == STX) {
+                       /* Prevent rx_queue from overflow: */
+                       if (pInfo->blocks_in_rx_queue >=
+                           R3964_MAX_BLOCKS_IN_RX_QUEUE) {
+                               TRACE_PE("IDLE - got STX but no space in "
+                                               "rx_queue!");
+                               pInfo->state = R3964_WAIT_FOR_RX_BUF;
+                               mod_timer(&pInfo->tmr,
+                                         jiffies + R3964_TO_NO_BUF);
+                               break;
+                       }
+start_receiving:
+                       /* Ok, start receiving: */
+                       TRACE_PS("IDLE - got STX");
+                       pInfo->rx_position = 0;
+                       pInfo->last_rx = 0;
+                       pInfo->flags &= ~R3964_ERROR;
+                       pInfo->state = R3964_RECEIVING;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+                       pInfo->nRetry = 0;
+                       put_char(pInfo, DLE);
+                       flush(pInfo);
+                       pInfo->bcc = 0;
+               }
+               break;
+       case R3964_RECEIVING:
+               if (pInfo->rx_position < RX_BUF_SIZE) {
+                       pInfo->bcc ^= c;
+
+                       if (c == DLE) {
+                               if (pInfo->last_rx == DLE) {
+                                       pInfo->last_rx = 0;
+                                       goto char_to_buf;
+                               }
+                               pInfo->last_rx = DLE;
+                               break;
+                       } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
+                               if (pInfo->flags & R3964_BCC) {
+                                       pInfo->state = R3964_WAIT_FOR_BCC;
+                                       mod_timer(&pInfo->tmr,
+                                                 jiffies + R3964_TO_ZVZ);
+                               } else {
+                                       on_receive_block(pInfo);
+                               }
+                       } else {
+                               pInfo->last_rx = c;
+char_to_buf:
+                               pInfo->rx_buf[pInfo->rx_position++] = c;
+                               mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+                       }
+               }
+               /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
+               break;
+       case R3964_WAIT_FOR_BCC:
+               pInfo->last_rx = c;
+               on_receive_block(pInfo);
+               break;
+       }
+}
+
+static void receive_error(struct r3964_info *pInfo, const char flag)
+{
+       switch (flag) {
+       case TTY_NORMAL:
+               break;
+       case TTY_BREAK:
+               TRACE_PE("received break");
+               pInfo->flags |= R3964_BREAK;
+               break;
+       case TTY_PARITY:
+               TRACE_PE("parity error");
+               pInfo->flags |= R3964_PARITY;
+               break;
+       case TTY_FRAME:
+               TRACE_PE("frame error");
+               pInfo->flags |= R3964_FRAME;
+               break;
+       case TTY_OVERRUN:
+               TRACE_PE("frame overrun");
+               pInfo->flags |= R3964_OVERRUN;
+               break;
+       default:
+               TRACE_PE("receive_error - unknown flag %d", flag);
+               pInfo->flags |= R3964_UNKNOWN;
+               break;
+       }
+}
+
+static void on_timeout(unsigned long priv)
+{
+       struct r3964_info *pInfo = (void *)priv;
+
+       switch (pInfo->state) {
+       case R3964_TX_REQUEST:
+               TRACE_PE("TX_REQUEST - timeout");
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_FOR_TX_ACK:
+               TRACE_PE("WAIT_FOR_TX_ACK - timeout");
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_FOR_RX_BUF:
+               TRACE_PE("WAIT_FOR_RX_BUF - timeout");
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_RECEIVING:
+               TRACE_PE("RECEIVING - timeout after %d chars",
+                        pInfo->rx_position);
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_WAIT_FOR_RX_REPEAT:
+               TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_WAIT_FOR_BCC:
+               TRACE_PE("WAIT_FOR_BCC - timeout");
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       }
+}
+
+static struct r3964_client_info *findClient(struct r3964_info *pInfo,
+               struct pid *pid)
+{
+       struct r3964_client_info *pClient;
+
+       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+               if (pClient->pid == pid) {
+                       return pClient;
+               }
+       }
+       return NULL;
+}
+
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
+{
+       struct r3964_client_info *pClient;
+       struct r3964_client_info **ppClient;
+       struct r3964_message *pMsg;
+
+       if ((arg & R3964_SIG_ALL) == 0) {
+               /* Remove client from client list */
+               for (ppClient = &pInfo->firstClient; *ppClient;
+                    ppClient = &(*ppClient)->next) {
+                       pClient = *ppClient;
+
+                       if (pClient->pid == pid) {
+                               TRACE_PS("removing client %d from client list",
+                                        pid_nr(pid));
+                               *ppClient = pClient->next;
+                               while (pClient->msg_count) {
+                                       pMsg = remove_msg(pInfo, pClient);
+                                       if (pMsg) {
+                                               kfree(pMsg);
+                                               TRACE_M("enable_signals - msg "
+                                                       "kfree %p", pMsg);
+                                       }
+                               }
+                               put_pid(pClient->pid);
+                               kfree(pClient);
+                               TRACE_M("enable_signals - kfree %p", pClient);
+                               return 0;
+                       }
+               }
+               return -EINVAL;
+       } else {
+               pClient = findClient(pInfo, pid);
+               if (pClient) {
+                       /* update signal options */
+                       pClient->sig_flags = arg;
+               } else {
+                       /* add client to client list */
+                       pClient = kmalloc(sizeof(struct r3964_client_info),
+                                       GFP_KERNEL);
+                       TRACE_M("enable_signals - kmalloc %p", pClient);
+                       if (pClient == NULL)
+                               return -ENOMEM;
+
+                       TRACE_PS("add client %d to client list", pid_nr(pid));
+                       spin_lock_init(&pClient->lock);
+                       pClient->sig_flags = arg;
+                       pClient->pid = get_pid(pid);
+                       pClient->next = pInfo->firstClient;
+                       pClient->first_msg = NULL;
+                       pClient->last_msg = NULL;
+                       pClient->next_block_to_read = NULL;
+                       pClient->msg_count = 0;
+                       pInfo->firstClient = pClient;
+               }
+       }
+
+       return 0;
+}
+
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+                        unsigned char __user * buf)
+{
+       struct r3964_client_info *pClient;
+       struct r3964_block_header *block;
+
+       if (!buf) {
+               return -EINVAL;
+       }
+
+       pClient = findClient(pInfo, pid);
+       if (pClient == NULL) {
+               return -EINVAL;
+       }
+
+       block = pClient->next_block_to_read;
+       if (!block) {
+               return 0;
+       } else {
+               if (copy_to_user(buf, block->data, block->length))
+                       return -EFAULT;
+
+               remove_client_block(pInfo, pClient);
+               return block->length;
+       }
+
+       return -EINVAL;
+}
+
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+               int error_code, struct r3964_block_header *pBlock)
+{
+       struct r3964_message *pMsg;
+       unsigned long flags;
+
+       if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
+queue_the_message:
+
+               pMsg = kmalloc(sizeof(struct r3964_message),
+                               error_code ? GFP_ATOMIC : GFP_KERNEL);
+               TRACE_M("add_msg - kmalloc %p", pMsg);
+               if (pMsg == NULL) {
+                       return;
+               }
+
+               spin_lock_irqsave(&pClient->lock, flags);
+
+               pMsg->msg_id = msg_id;
+               pMsg->arg = arg;
+               pMsg->error_code = error_code;
+               pMsg->block = pBlock;
+               pMsg->next = NULL;
+
+               if (pClient->last_msg == NULL) {
+                       pClient->first_msg = pClient->last_msg = pMsg;
+               } else {
+                       pClient->last_msg->next = pMsg;
+                       pClient->last_msg = pMsg;
+               }
+
+               pClient->msg_count++;
+
+               if (pBlock != NULL) {
+                       pBlock->locks++;
+               }
+               spin_unlock_irqrestore(&pClient->lock, flags);
+       } else {
+               if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
+                   && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
+                       pClient->last_msg->arg++;
+                       TRACE_PE("add_msg - inc prev OVERFLOW-msg");
+               } else {
+                       msg_id = R3964_MSG_ACK;
+                       arg = 0;
+                       error_code = R3964_OVERFLOW;
+                       pBlock = NULL;
+                       TRACE_PE("add_msg - queue OVERFLOW-msg");
+                       goto queue_the_message;
+               }
+       }
+       /* Send SIGIO signal to client process: */
+       if (pClient->sig_flags & R3964_USE_SIGIO) {
+               kill_pid(pClient->pid, SIGIO, 1);
+       }
+}
+
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+                                       struct r3964_client_info *pClient)
+{
+       struct r3964_message *pMsg = NULL;
+       unsigned long flags;
+
+       if (pClient->first_msg) {
+               spin_lock_irqsave(&pClient->lock, flags);
+
+               pMsg = pClient->first_msg;
+               pClient->first_msg = pMsg->next;
+               if (pClient->first_msg == NULL) {
+                       pClient->last_msg = NULL;
+               }
+
+               pClient->msg_count--;
+               if (pMsg->block) {
+                       remove_client_block(pInfo, pClient);
+                       pClient->next_block_to_read = pMsg->block;
+               }
+               spin_unlock_irqrestore(&pClient->lock, flags);
+       }
+       return pMsg;
+}
+
+static void remove_client_block(struct r3964_info *pInfo,
+                               struct r3964_client_info *pClient)
+{
+       struct r3964_block_header *block;
+
+       TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
+
+       block = pClient->next_block_to_read;
+       if (block) {
+               block->locks--;
+               if (block->locks == 0) {
+                       remove_from_rx_queue(pInfo, block);
+               }
+       }
+       pClient->next_block_to_read = NULL;
+}
+
+/*************************************************************
+ * Line discipline routines
+ *************************************************************/
+
+static int r3964_open(struct tty_struct *tty)
+{
+       struct r3964_info *pInfo;
+
+       TRACE_L("open");
+       TRACE_L("tty=%p, PID=%d, disc_data=%p",
+               tty, current->pid, tty->disc_data);
+
+       pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
+       TRACE_M("r3964_open - info kmalloc %p", pInfo);
+
+       if (!pInfo) {
+               printk(KERN_ERR "r3964: failed to alloc info structure\n");
+               return -ENOMEM;
+       }
+
+       pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+       TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
+
+       if (!pInfo->rx_buf) {
+               printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
+               kfree(pInfo);
+               TRACE_M("r3964_open - info kfree %p", pInfo);
+               return -ENOMEM;
+       }
+
+       pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
+       TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
+
+       if (!pInfo->tx_buf) {
+               printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
+               kfree(pInfo->rx_buf);
+               TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
+               kfree(pInfo);
+               TRACE_M("r3964_open - info kfree %p", pInfo);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&pInfo->lock);
+       pInfo->tty = tty;
+       init_waitqueue_head(&pInfo->read_wait);
+       pInfo->priority = R3964_MASTER;
+       pInfo->rx_first = pInfo->rx_last = NULL;
+       pInfo->tx_first = pInfo->tx_last = NULL;
+       pInfo->rx_position = 0;
+       pInfo->tx_position = 0;
+       pInfo->last_rx = 0;
+       pInfo->blocks_in_rx_queue = 0;
+       pInfo->firstClient = NULL;
+       pInfo->state = R3964_IDLE;
+       pInfo->flags = R3964_DEBUG;
+       pInfo->nRetry = 0;
+
+       tty->disc_data = pInfo;
+       tty->receive_room = 65536;
+
+       setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
+
+       return 0;
+}
+
+static void r3964_close(struct tty_struct *tty)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient, *pNext;
+       struct r3964_message *pMsg;
+       struct r3964_block_header *pHeader, *pNextHeader;
+       unsigned long flags;
+
+       TRACE_L("close");
+
+       /*
+        * Make sure that our task queue isn't activated.  If it
+        * is, take it out of the linked list.
+        */
+       del_timer_sync(&pInfo->tmr);
+
+       /* Remove client-structs and message queues: */
+       pClient = pInfo->firstClient;
+       while (pClient) {
+               pNext = pClient->next;
+               while (pClient->msg_count) {
+                       pMsg = remove_msg(pInfo, pClient);
+                       if (pMsg) {
+                               kfree(pMsg);
+                               TRACE_M("r3964_close - msg kfree %p", pMsg);
+                       }
+               }
+               put_pid(pClient->pid);
+               kfree(pClient);
+               TRACE_M("r3964_close - client kfree %p", pClient);
+               pClient = pNext;
+       }
+       /* Remove jobs from tx_queue: */
+       spin_lock_irqsave(&pInfo->lock, flags);
+       pHeader = pInfo->tx_first;
+       pInfo->tx_first = pInfo->tx_last = NULL;
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       while (pHeader) {
+               pNextHeader = pHeader->next;
+               kfree(pHeader);
+               pHeader = pNextHeader;
+       }
+
+       /* Free buffers: */
+       wake_up_interruptible(&pInfo->read_wait);
+       kfree(pInfo->rx_buf);
+       TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
+       kfree(pInfo->tx_buf);
+       TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
+       kfree(pInfo);
+       TRACE_M("r3964_close - info kfree %p", pInfo);
+}
+
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+                         unsigned char __user * buf, size_t nr)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg;
+       struct r3964_client_message theMsg;
+       int ret;
+
+       TRACE_L("read()");
+
+       tty_lock();
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               pMsg = remove_msg(pInfo, pClient);
+               if (pMsg == NULL) {
+                       /* no messages available. */
+                       if (file->f_flags & O_NONBLOCK) {
+                               ret = -EAGAIN;
+                               goto unlock;
+                       }
+                       /* block until there is a message: */
+                       wait_event_interruptible_tty(pInfo->read_wait,
+                                       (pMsg = remove_msg(pInfo, pClient)));
+               }
+
+               /* If we still haven't got a message, we must have been signalled */
+
+               if (!pMsg) {
+                       ret = -EINTR;
+                       goto unlock;
+               }
+
+               /* deliver msg to client process: */
+               theMsg.msg_id = pMsg->msg_id;
+               theMsg.arg = pMsg->arg;
+               theMsg.error_code = pMsg->error_code;
+               ret = sizeof(struct r3964_client_message);
+
+               kfree(pMsg);
+               TRACE_M("r3964_read - msg kfree %p", pMsg);
+
+               if (copy_to_user(buf, &theMsg, ret)) {
+                       ret = -EFAULT;
+                       goto unlock;
+               }
+
+               TRACE_PS("read - return %d", ret);
+               goto unlock;
+       }
+       ret = -EPERM;
+unlock:
+       tty_unlock();
+       return ret;
+}
+
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *data, size_t count)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_block_header *pHeader;
+       struct r3964_client_info *pClient;
+       unsigned char *new_data;
+
+       TRACE_L("write request, %d characters", count);
+/* 
+ * Verify the pointers 
+ */
+
+       if (!pInfo)
+               return -EIO;
+
+/*
+ * Ensure that the caller does not wish to send too much.
+ */
+       if (count > R3964_MTU) {
+               if (pInfo->flags & R3964_DEBUG) {
+                       TRACE_L(KERN_WARNING "r3964_write: truncating user "
+                               "packet from %u to mtu %d", count, R3964_MTU);
+               }
+               count = R3964_MTU;
+       }
+/*
+ * Allocate a buffer for the data and copy it from the buffer with header prepended
+ */
+       new_data = kmalloc(count + sizeof(struct r3964_block_header),
+                       GFP_KERNEL);
+       TRACE_M("r3964_write - kmalloc %p", new_data);
+       if (new_data == NULL) {
+               if (pInfo->flags & R3964_DEBUG) {
+                       printk(KERN_ERR "r3964_write: no memory\n");
+               }
+               return -ENOSPC;
+       }
+
+       pHeader = (struct r3964_block_header *)new_data;
+       pHeader->data = new_data + sizeof(struct r3964_block_header);
+       pHeader->length = count;
+       pHeader->locks = 0;
+       pHeader->owner = NULL;
+
+       tty_lock();
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               pHeader->owner = pClient;
+       }
+
+       memcpy(pHeader->data, data, count);     /* We already verified this */
+
+       if (pInfo->flags & R3964_DEBUG) {
+               dump_block(pHeader->data, count);
+       }
+
+/*
+ * Add buffer to transmit-queue:
+ */
+       add_tx_queue(pInfo, pHeader);
+       trigger_transmit(pInfo);
+
+       tty_unlock();
+
+       return 0;
+}
+
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       if (pInfo == NULL)
+               return -EINVAL;
+       switch (cmd) {
+       case R3964_ENABLE_SIGNALS:
+               return enable_signals(pInfo, task_pid(current), arg);
+       case R3964_SETPRIORITY:
+               if (arg < R3964_MASTER || arg > R3964_SLAVE)
+                       return -EINVAL;
+               pInfo->priority = arg & 0xff;
+               return 0;
+       case R3964_USE_BCC:
+               if (arg)
+                       pInfo->flags |= R3964_BCC;
+               else
+                       pInfo->flags &= ~R3964_BCC;
+               return 0;
+       case R3964_READ_TELEGRAM:
+               return read_telegram(pInfo, task_pid(current),
+                               (unsigned char __user *)arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       TRACE_L("set_termios");
+}
+
+/* Called without the kernel lock held - fine */
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+                       struct poll_table_struct *wait)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg = NULL;
+       unsigned long flags;
+       int result = POLLOUT;
+
+       TRACE_L("POLL");
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               poll_wait(file, &pInfo->read_wait, wait);
+               spin_lock_irqsave(&pInfo->lock, flags);
+               pMsg = pClient->first_msg;
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+               if (pMsg)
+                       result |= POLLIN | POLLRDNORM;
+       } else {
+               result = -EINVAL;
+       }
+       return result;
+}
+
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                       char *fp, int count)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       const unsigned char *p;
+       char *f, flags = 0;
+       int i;
+
+       for (i = count, p = cp, f = fp; i; i--, p++) {
+               if (f)
+                       flags = *f++;
+               if (flags == TTY_NORMAL) {
+                       receive_char(pInfo, *p);
+               } else {
+                       receive_error(pInfo, flags);
+               }
+
+       }
+}
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
new file mode 100644 (file)
index 0000000..428f4fe
--- /dev/null
@@ -0,0 +1,2121 @@
+/*
+ * n_tty.c --- implements the N_TTY line discipline.
+ *
+ * This code used to be in tty_io.c, but things are getting hairy
+ * enough that it made sense to split things off.  (The N_TTY
+ * processing has changed so much that it's hardly recognizable,
+ * anyway...)
+ *
+ * Note that the open routine for N_TTY is guaranteed never to return
+ * an error.  This is because Linux will fall back to setting a line
+ * to N_TTY if it can not switch to any other line discipline.
+ *
+ * Written by Theodore Ts'o, Copyright 1994.
+ *
+ * This file also contains code originally written by Linus Torvalds,
+ * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
+ *
+ * This file may be redistributed under the terms of the GNU General Public
+ * License.
+ *
+ * Reduced memory usage for older ARM systems  - Russell King.
+ *
+ * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
+ *             the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
+ *             who actually finally proved there really was a race.
+ *
+ * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
+ *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
+ *             Also fixed a bug in BLOCKING mode where n_tty_write returns
+ *             EAGAIN
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/audit.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+
+/* number of characters left in xmit buffer before select has we have room */
+#define WAKEUP_CHARS 256
+
+/*
+ * This defines the low- and high-watermarks for throttling and
+ * unthrottling the TTY driver.  These watermarks are used for
+ * controlling the space in the read buffer.
+ */
+#define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
+#define TTY_THRESHOLD_UNTHROTTLE       128
+
+/*
+ * Special byte codes used in the echo buffer to represent operations
+ * or special handling of characters.  Bytes in the echo buffer that
+ * are not part of such special blocks are treated as normal character
+ * codes.
+ */
+#define ECHO_OP_START 0xff
+#define ECHO_OP_MOVE_BACK_COL 0x80
+#define ECHO_OP_SET_CANON_COL 0x81
+#define ECHO_OP_ERASE_TAB 0x82
+
+static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
+                              unsigned char __user *ptr)
+{
+       tty_audit_add_data(tty, &x, 1);
+       return put_user(x, ptr);
+}
+
+/**
+ *     n_tty_set__room -       receive space
+ *     @tty: terminal
+ *
+ *     Called by the driver to find out how much data it is
+ *     permitted to feed to the line discipline without any being lost
+ *     and thus to manage flow control. Not serialized. Answers for the
+ *     "instant".
+ */
+
+static void n_tty_set_room(struct tty_struct *tty)
+{
+       /* tty->read_cnt is not read locked ? */
+       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+       /*
+        * If we are doing input canonicalization, and there are no
+        * pending newlines, let characters through without limit, so
+        * that erase characters will be handled.  Other excess
+        * characters will be beeped.
+        */
+       if (left <= 0)
+               left = tty->icanon && !tty->canon_data;
+       tty->receive_room = left;
+}
+
+static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
+{
+       if (tty->read_cnt < N_TTY_BUF_SIZE) {
+               tty->read_buf[tty->read_head] = c;
+               tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt++;
+       }
+}
+
+/**
+ *     put_tty_queue           -       add character to tty
+ *     @c: character
+ *     @tty: tty device
+ *
+ *     Add a character to the tty read_buf queue. This is done under the
+ *     read_lock to serialize character addition and also to protect us
+ *     against parallel reads or flushes
+ */
+
+static void put_tty_queue(unsigned char c, struct tty_struct *tty)
+{
+       unsigned long flags;
+       /*
+        *      The problem of stomping on the buffers ends here.
+        *      Why didn't anyone see this one coming? --AJK
+       */
+       spin_lock_irqsave(&tty->read_lock, flags);
+       put_tty_queue_nolock(c, tty);
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+}
+
+/**
+ *     check_unthrottle        -       allow new receive data
+ *     @tty; tty device
+ *
+ *     Check whether to call the driver unthrottle functions
+ *
+ *     Can sleep, may be called under the atomic_read_lock mutex but
+ *     this is not guaranteed.
+ */
+static void check_unthrottle(struct tty_struct *tty)
+{
+       if (tty->count)
+               tty_unthrottle(tty);
+}
+
+/**
+ *     reset_buffer_flags      -       reset buffer state
+ *     @tty: terminal to reset
+ *
+ *     Reset the read buffer counters, clear the flags,
+ *     and make sure the driver is unthrottled. Called
+ *     from n_tty_open() and n_tty_flush_buffer().
+ *
+ *     Locking: tty_read_lock for read fields.
+ */
+
+static void reset_buffer_flags(struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->read_lock, flags);
+       tty->read_head = tty->read_tail = tty->read_cnt = 0;
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+
+       mutex_lock(&tty->echo_lock);
+       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
+       mutex_unlock(&tty->echo_lock);
+
+       tty->canon_head = tty->canon_data = tty->erasing = 0;
+       memset(&tty->read_flags, 0, sizeof tty->read_flags);
+       n_tty_set_room(tty);
+       check_unthrottle(tty);
+}
+
+/**
+ *     n_tty_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup) or when the N_TTY line discipline internally has to
+ *     clean the pending queue (for example some signals).
+ *
+ *     Locking: ctrl_lock, read_lock.
+ */
+
+static void n_tty_flush_buffer(struct tty_struct *tty)
+{
+       unsigned long flags;
+       /* clear everything and unthrottle the driver */
+       reset_buffer_flags(tty);
+
+       if (!tty->link)
+               return;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->link->packet) {
+               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+               wake_up_interruptible(&tty->link->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+}
+
+/**
+ *     n_tty_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time.
+ *
+ *     Locking: read_lock
+ */
+
+static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       unsigned long flags;
+       ssize_t n = 0;
+
+       spin_lock_irqsave(&tty->read_lock, flags);
+       if (!tty->icanon) {
+               n = tty->read_cnt;
+       } else if (tty->canon_data) {
+               n = (tty->canon_head > tty->read_tail) ?
+                       tty->canon_head - tty->read_tail :
+                       tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
+       }
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+       return n;
+}
+
+/**
+ *     is_utf8_continuation    -       utf8 multibyte check
+ *     @c: byte to check
+ *
+ *     Returns true if the utf8 character 'c' is a multibyte continuation
+ *     character. We use this to correctly compute the on screen size
+ *     of the character when printing
+ */
+
+static inline int is_utf8_continuation(unsigned char c)
+{
+       return (c & 0xc0) == 0x80;
+}
+
+/**
+ *     is_continuation         -       multibyte check
+ *     @c: byte to check
+ *
+ *     Returns true if the utf8 character 'c' is a multibyte continuation
+ *     character and the terminal is in unicode mode.
+ */
+
+static inline int is_continuation(unsigned char c, struct tty_struct *tty)
+{
+       return I_IUTF8(tty) && is_utf8_continuation(c);
+}
+
+/**
+ *     do_output_char                  -       output one character
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *     @space: space available in tty driver write buffer
+ *
+ *     This is a helper function that handles one output character
+ *     (including special characters like TAB, CR, LF, etc.),
+ *     doing OPOST processing and putting the results in the
+ *     tty driver's write buffer.
+ *
+ *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
+ *     and NLDLY.  They simply aren't relevant in the world today.
+ *     If you ever need them, add them here.
+ *
+ *     Returns the number of bytes of buffer space used or -1 if
+ *     no space left.
+ *
+ *     Locking: should be called under the output_lock to protect
+ *              the column state and space left in the buffer
+ */
+
+static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
+{
+       int     spaces;
+
+       if (!space)
+               return -1;
+
+       switch (c) {
+       case '\n':
+               if (O_ONLRET(tty))
+                       tty->column = 0;
+               if (O_ONLCR(tty)) {
+                       if (space < 2)
+                               return -1;
+                       tty->canon_column = tty->column = 0;
+                       tty->ops->write(tty, "\r\n", 2);
+                       return 2;
+               }
+               tty->canon_column = tty->column;
+               break;
+       case '\r':
+               if (O_ONOCR(tty) && tty->column == 0)
+                       return 0;
+               if (O_OCRNL(tty)) {
+                       c = '\n';
+                       if (O_ONLRET(tty))
+                               tty->canon_column = tty->column = 0;
+                       break;
+               }
+               tty->canon_column = tty->column = 0;
+               break;
+       case '\t':
+               spaces = 8 - (tty->column & 7);
+               if (O_TABDLY(tty) == XTABS) {
+                       if (space < spaces)
+                               return -1;
+                       tty->column += spaces;
+                       tty->ops->write(tty, "        ", spaces);
+                       return spaces;
+               }
+               tty->column += spaces;
+               break;
+       case '\b':
+               if (tty->column > 0)
+                       tty->column--;
+               break;
+       default:
+               if (!iscntrl(c)) {
+                       if (O_OLCUC(tty))
+                               c = toupper(c);
+                       if (!is_continuation(c, tty))
+                               tty->column++;
+               }
+               break;
+       }
+
+       tty_put_char(tty, c);
+       return 1;
+}
+
+/**
+ *     process_output                  -       output post processor
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *
+ *     Output one character with OPOST processing.
+ *     Returns -1 when the output device is full and the character
+ *     must be retried.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static int process_output(unsigned char c, struct tty_struct *tty)
+{
+       int     space, retval;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       retval = do_output_char(c, tty, space);
+
+       mutex_unlock(&tty->output_lock);
+       if (retval < 0)
+               return -1;
+       else
+               return 0;
+}
+
+/**
+ *     process_output_block            -       block post processor
+ *     @tty: terminal device
+ *     @buf: character buffer
+ *     @nr: number of bytes to output
+ *
+ *     Output a block of characters with OPOST processing.
+ *     Returns the number of characters output.
+ *
+ *     This path is used to speed up block console writes, among other
+ *     things when processing blocks of output data. It handles only
+ *     the simple cases normally found and helps to generate blocks of
+ *     symbols for the console driver and thus improve performance.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static ssize_t process_output_block(struct tty_struct *tty,
+                                   const unsigned char *buf, unsigned int nr)
+{
+       int     space;
+       int     i;
+       const unsigned char *cp;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       if (!space) {
+               mutex_unlock(&tty->output_lock);
+               return 0;
+       }
+       if (nr > space)
+               nr = space;
+
+       for (i = 0, cp = buf; i < nr; i++, cp++) {
+               unsigned char c = *cp;
+
+               switch (c) {
+               case '\n':
+                       if (O_ONLRET(tty))
+                               tty->column = 0;
+                       if (O_ONLCR(tty))
+                               goto break_out;
+                       tty->canon_column = tty->column;
+                       break;
+               case '\r':
+                       if (O_ONOCR(tty) && tty->column == 0)
+                               goto break_out;
+                       if (O_OCRNL(tty))
+                               goto break_out;
+                       tty->canon_column = tty->column = 0;
+                       break;
+               case '\t':
+                       goto break_out;
+               case '\b':
+                       if (tty->column > 0)
+                               tty->column--;
+                       break;
+               default:
+                       if (!iscntrl(c)) {
+                               if (O_OLCUC(tty))
+                                       goto break_out;
+                               if (!is_continuation(c, tty))
+                                       tty->column++;
+                       }
+                       break;
+               }
+       }
+break_out:
+       i = tty->ops->write(tty, buf, i);
+
+       mutex_unlock(&tty->output_lock);
+       return i;
+}
+
+/**
+ *     process_echoes  -       write pending echo characters
+ *     @tty: terminal device
+ *
+ *     Write previously buffered echo (and other ldisc-generated)
+ *     characters to the tty.
+ *
+ *     Characters generated by the ldisc (including echoes) need to
+ *     be buffered because the driver's write buffer can fill during
+ *     heavy program output.  Echoing straight to the driver will
+ *     often fail under these conditions, causing lost characters and
+ *     resulting mismatches of ldisc state information.
+ *
+ *     Since the ldisc state must represent the characters actually sent
+ *     to the driver at the time of the write, operations like certain
+ *     changes in column state are also saved in the buffer and executed
+ *     here.
+ *
+ *     A circular fifo buffer is used so that the most recent characters
+ *     are prioritized.  Also, when control characters are echoed with a
+ *     prefixed "^", the pair is treated atomically and thus not separated.
+ *
+ *     Locking: output_lock to protect column state and space left,
+ *              echo_lock to protect the echo buffer
+ */
+
+static void process_echoes(struct tty_struct *tty)
+{
+       int     space, nr;
+       unsigned char c;
+       unsigned char *cp, *buf_end;
+
+       if (!tty->echo_cnt)
+               return;
+
+       mutex_lock(&tty->output_lock);
+       mutex_lock(&tty->echo_lock);
+
+       space = tty_write_room(tty);
+
+       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
+       cp = tty->echo_buf + tty->echo_pos;
+       nr = tty->echo_cnt;
+       while (nr > 0) {
+               c = *cp;
+               if (c == ECHO_OP_START) {
+                       unsigned char op;
+                       unsigned char *opp;
+                       int no_space_left = 0;
+
+                       /*
+                        * If the buffer byte is the start of a multi-byte
+                        * operation, get the next byte, which is either the
+                        * op code or a control character value.
+                        */
+                       opp = cp + 1;
+                       if (opp == buf_end)
+                               opp -= N_TTY_BUF_SIZE;
+                       op = *opp;
+
+                       switch (op) {
+                               unsigned int num_chars, num_bs;
+
+                       case ECHO_OP_ERASE_TAB:
+                               if (++opp == buf_end)
+                                       opp -= N_TTY_BUF_SIZE;
+                               num_chars = *opp;
+
+                               /*
+                                * Determine how many columns to go back
+                                * in order to erase the tab.
+                                * This depends on the number of columns
+                                * used by other characters within the tab
+                                * area.  If this (modulo 8) count is from
+                                * the start of input rather than from a
+                                * previous tab, we offset by canon column.
+                                * Otherwise, tab spacing is normal.
+                                */
+                               if (!(num_chars & 0x80))
+                                       num_chars += tty->canon_column;
+                               num_bs = 8 - (num_chars & 7);
+
+                               if (num_bs > space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               space -= num_bs;
+                               while (num_bs--) {
+                                       tty_put_char(tty, '\b');
+                                       if (tty->column > 0)
+                                               tty->column--;
+                               }
+                               cp += 3;
+                               nr -= 3;
+                               break;
+
+                       case ECHO_OP_SET_CANON_COL:
+                               tty->canon_column = tty->column;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_MOVE_BACK_COL:
+                               if (tty->column > 0)
+                                       tty->column--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_START:
+                               /* This is an escaped echo op start code */
+                               if (!space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, ECHO_OP_START);
+                               tty->column++;
+                               space--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       default:
+                               /*
+                                * If the op is not a special byte code,
+                                * it is a ctrl char tagged to be echoed
+                                * as "^X" (where X is the letter
+                                * representing the control char).
+                                * Note that we must ensure there is
+                                * enough space for the whole ctrl pair.
+                                *
+                                */
+                               if (space < 2) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, '^');
+                               tty_put_char(tty, op ^ 0100);
+                               tty->column += 2;
+                               space -= 2;
+                               cp += 2;
+                               nr -= 2;
+                       }
+
+                       if (no_space_left)
+                               break;
+               } else {
+                       if (O_OPOST(tty) &&
+                           !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                               int retval = do_output_char(c, tty, space);
+                               if (retval < 0)
+                                       break;
+                               space -= retval;
+                       } else {
+                               if (!space)
+                                       break;
+                               tty_put_char(tty, c);
+                               space -= 1;
+                       }
+                       cp += 1;
+                       nr -= 1;
+               }
+
+               /* When end of circular buffer reached, wrap around */
+               if (cp >= buf_end)
+                       cp -= N_TTY_BUF_SIZE;
+       }
+
+       if (nr == 0) {
+               tty->echo_pos = 0;
+               tty->echo_cnt = 0;
+               tty->echo_overrun = 0;
+       } else {
+               int num_processed = tty->echo_cnt - nr;
+               tty->echo_pos += num_processed;
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt = nr;
+               if (num_processed > 0)
+                       tty->echo_overrun = 0;
+       }
+
+       mutex_unlock(&tty->echo_lock);
+       mutex_unlock(&tty->output_lock);
+
+       if (tty->ops->flush_chars)
+               tty->ops->flush_chars(tty);
+}
+
+/**
+ *     add_echo_byte   -       add a byte to the echo buffer
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Add a character or operation byte to the echo buffer.
+ *
+ *     Should be called under the echo lock to protect the echo buffer.
+ */
+
+static void add_echo_byte(unsigned char c, struct tty_struct *tty)
+{
+       int     new_byte_pos;
+
+       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
+               /* Circular buffer is already at capacity */
+               new_byte_pos = tty->echo_pos;
+
+               /*
+                * Since the buffer start position needs to be advanced,
+                * be sure to step by a whole operation byte group.
+                */
+               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
+                       if (tty->echo_buf[(tty->echo_pos + 1) &
+                                         (N_TTY_BUF_SIZE - 1)] ==
+                                               ECHO_OP_ERASE_TAB) {
+                               tty->echo_pos += 3;
+                               tty->echo_cnt -= 2;
+                       } else {
+                               tty->echo_pos += 2;
+                               tty->echo_cnt -= 1;
+                       }
+               } else {
+                       tty->echo_pos++;
+               }
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+
+               tty->echo_overrun = 1;
+       } else {
+               new_byte_pos = tty->echo_pos + tty->echo_cnt;
+               new_byte_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt++;
+       }
+
+       tty->echo_buf[new_byte_pos] = c;
+}
+
+/**
+ *     echo_move_back_col      -       add operation to move back a column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to move back one column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_move_back_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_set_canon_col      -       add operation to set the canon column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to set the canon column
+ *     to the current column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_set_canon_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_erase_tab  -       add operation to erase a tab
+ *     @num_chars: number of character columns already used
+ *     @after_tab: true if num_chars starts after a previous tab
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to erase a tab.
+ *
+ *     Called by the eraser function, which knows how many character
+ *     columns have been used since either a previous tab or the start
+ *     of input.  This information will be used later, along with
+ *     canon column (if applicable), to go back the correct number
+ *     of columns.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_erase_tab(unsigned int num_chars, int after_tab,
+                          struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
+
+       /* We only need to know this modulo 8 (tab spacing) */
+       num_chars &= 7;
+
+       /* Set the high bit as a flag if num_chars is after a previous tab */
+       if (after_tab)
+               num_chars |= 0x80;
+
+       add_echo_byte(num_chars, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char_raw   -       echo a character raw
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant does not treat control characters specially.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char_raw(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char       -       echo a character
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant tags control characters to be echoed as "^X"
+ *     (where X is the letter representing the control char).
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
+                       add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     finish_erasing          -       complete erase
+ *     @tty: tty doing the erase
+ */
+
+static inline void finish_erasing(struct tty_struct *tty)
+{
+       if (tty->erasing) {
+               echo_char_raw('/', tty);
+               tty->erasing = 0;
+       }
+}
+
+/**
+ *     eraser          -       handle erase function
+ *     @c: character input
+ *     @tty: terminal device
+ *
+ *     Perform erase and necessary output when an erase character is
+ *     present in the stream from the driver layer. Handles the complexities
+ *     of UTF-8 multibyte symbols.
+ *
+ *     Locking: read_lock for tty buffers
+ */
+
+static void eraser(unsigned char c, struct tty_struct *tty)
+{
+       enum { ERASE, WERASE, KILL } kill_type;
+       int head, seen_alnums, cnt;
+       unsigned long flags;
+
+       /* FIXME: locking needed ? */
+       if (tty->read_head == tty->canon_head) {
+               /* process_output('\a', tty); */ /* what do you think? */
+               return;
+       }
+       if (c == ERASE_CHAR(tty))
+               kill_type = ERASE;
+       else if (c == WERASE_CHAR(tty))
+               kill_type = WERASE;
+       else {
+               if (!L_ECHO(tty)) {
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+                                         (N_TTY_BUF_SIZE - 1));
+                       tty->read_head = tty->canon_head;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       return;
+               }
+               if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+                                         (N_TTY_BUF_SIZE - 1));
+                       tty->read_head = tty->canon_head;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       finish_erasing(tty);
+                       echo_char(KILL_CHAR(tty), tty);
+                       /* Add a newline if ECHOK is on and ECHOKE is off. */
+                       if (L_ECHOK(tty))
+                               echo_char_raw('\n', tty);
+                       return;
+               }
+               kill_type = KILL;
+       }
+
+       seen_alnums = 0;
+       /* FIXME: Locking ?? */
+       while (tty->read_head != tty->canon_head) {
+               head = tty->read_head;
+
+               /* erase a single possibly multibyte character */
+               do {
+                       head = (head - 1) & (N_TTY_BUF_SIZE-1);
+                       c = tty->read_buf[head];
+               } while (is_continuation(c, tty) && head != tty->canon_head);
+
+               /* do not partially erase */
+               if (is_continuation(c, tty))
+                       break;
+
+               if (kill_type == WERASE) {
+                       /* Equivalent to BSD's ALTWERASE. */
+                       if (isalnum(c) || c == '_')
+                               seen_alnums++;
+                       else if (seen_alnums)
+                               break;
+               }
+               cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
+               spin_lock_irqsave(&tty->read_lock, flags);
+               tty->read_head = head;
+               tty->read_cnt -= cnt;
+               spin_unlock_irqrestore(&tty->read_lock, flags);
+               if (L_ECHO(tty)) {
+                       if (L_ECHOPRT(tty)) {
+                               if (!tty->erasing) {
+                                       echo_char_raw('\\', tty);
+                                       tty->erasing = 1;
+                               }
+                               /* if cnt > 1, output a multi-byte character */
+                               echo_char(c, tty);
+                               while (--cnt > 0) {
+                                       head = (head+1) & (N_TTY_BUF_SIZE-1);
+                                       echo_char_raw(tty->read_buf[head], tty);
+                                       echo_move_back_col(tty);
+                               }
+                       } else if (kill_type == ERASE && !L_ECHOE(tty)) {
+                               echo_char(ERASE_CHAR(tty), tty);
+                       } else if (c == '\t') {
+                               unsigned int num_chars = 0;
+                               int after_tab = 0;
+                               unsigned long tail = tty->read_head;
+
+                               /*
+                                * Count the columns used for characters
+                                * since the start of input or after a
+                                * previous tab.
+                                * This info is used to go back the correct
+                                * number of columns.
+                                */
+                               while (tail != tty->canon_head) {
+                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
+                                       c = tty->read_buf[tail];
+                                       if (c == '\t') {
+                                               after_tab = 1;
+                                               break;
+                                       } else if (iscntrl(c)) {
+                                               if (L_ECHOCTL(tty))
+                                                       num_chars += 2;
+                                       } else if (!is_continuation(c, tty)) {
+                                               num_chars++;
+                                       }
+                               }
+                               echo_erase_tab(num_chars, after_tab, tty);
+                       } else {
+                               if (iscntrl(c) && L_ECHOCTL(tty)) {
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
+                               }
+                               if (!iscntrl(c) || L_ECHOCTL(tty)) {
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
+                               }
+                       }
+               }
+               if (kill_type == ERASE)
+                       break;
+       }
+       if (tty->read_head == tty->canon_head && L_ECHO(tty))
+               finish_erasing(tty);
+}
+
+/**
+ *     isig            -       handle the ISIG optio
+ *     @sig: signal
+ *     @tty: terminal
+ *     @flush: force flush
+ *
+ *     Called when a signal is being sent due to terminal input. This
+ *     may caus terminal flushing to take place according to the termios
+ *     settings and character used. Called from the driver receive_buf
+ *     path so serialized.
+ *
+ *     Locking: ctrl_lock, read_lock (both via flush buffer)
+ */
+
+static inline void isig(int sig, struct tty_struct *tty, int flush)
+{
+       if (tty->pgrp)
+               kill_pgrp(tty->pgrp, sig, 1);
+       if (flush || !L_NOFLSH(tty)) {
+               n_tty_flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+       }
+}
+
+/**
+ *     n_tty_receive_break     -       handle break
+ *     @tty: terminal
+ *
+ *     An RS232 break event has been hit in the incoming bitstream. This
+ *     can cause a variety of events depending upon the termios settings.
+ *
+ *     Called from the receive_buf path so single threaded.
+ */
+
+static inline void n_tty_receive_break(struct tty_struct *tty)
+{
+       if (I_IGNBRK(tty))
+               return;
+       if (I_BRKINT(tty)) {
+               isig(SIGINT, tty, 1);
+               return;
+       }
+       if (I_PARMRK(tty)) {
+               put_tty_queue('\377', tty);
+               put_tty_queue('\0', tty);
+       }
+       put_tty_queue('\0', tty);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_receive_overrun   -       handle overrun reporting
+ *     @tty: terminal
+ *
+ *     Data arrived faster than we could process it. While the tty
+ *     driver has flagged this the bits that were missed are gone
+ *     forever.
+ *
+ *     Called from the receive_buf path so single threaded. Does not
+ *     need locking as num_overrun and overrun_time are function
+ *     private.
+ */
+
+static inline void n_tty_receive_overrun(struct tty_struct *tty)
+{
+       char buf[64];
+
+       tty->num_overrun++;
+       if (time_before(tty->overrun_time, jiffies - HZ) ||
+                       time_after(tty->overrun_time, jiffies)) {
+               printk(KERN_WARNING "%s: %d input overrun(s)\n",
+                       tty_name(tty, buf),
+                       tty->num_overrun);
+               tty->overrun_time = jiffies;
+               tty->num_overrun = 0;
+       }
+}
+
+/**
+ *     n_tty_receive_parity_error      -       error notifier
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process a parity error and queue the right data to indicate
+ *     the error case if necessary. Locking as per n_tty_receive_buf.
+ */
+static inline void n_tty_receive_parity_error(struct tty_struct *tty,
+                                             unsigned char c)
+{
+       if (I_IGNPAR(tty))
+               return;
+       if (I_PARMRK(tty)) {
+               put_tty_queue('\377', tty);
+               put_tty_queue('\0', tty);
+               put_tty_queue(c, tty);
+       } else  if (I_INPCK(tty))
+               put_tty_queue('\0', tty);
+       else
+               put_tty_queue(c, tty);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_receive_char      -       perform processing
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process an individual character of input received from the driver.
+ *     This is serialized with respect to itself by the rules for the
+ *     driver above.
+ */
+
+static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+{
+       unsigned long flags;
+       int parmrk;
+
+       if (tty->raw) {
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (I_ISTRIP(tty))
+               c &= 0x7f;
+       if (I_IUCLC(tty) && L_IEXTEN(tty))
+               c = tolower(c);
+
+       if (L_EXTPROC(tty)) {
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
+           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
+               start_tty(tty);
+               process_echoes(tty);
+       }
+
+       if (tty->closing) {
+               if (I_IXON(tty)) {
+                       if (c == START_CHAR(tty)) {
+                               start_tty(tty);
+                               process_echoes(tty);
+                       } else if (c == STOP_CHAR(tty))
+                               stop_tty(tty);
+               }
+               return;
+       }
+
+       /*
+        * If the previous character was LNEXT, or we know that this
+        * character is not one of the characters that we'll have to
+        * handle specially, do shortcut processing to speed things
+        * up.
+        */
+       if (!test_bit(c, tty->process_char_map) || tty->lnext) {
+               tty->lnext = 0;
+               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+                       /* beep if no space */
+                       if (L_ECHO(tty))
+                               process_output('\a', tty);
+                       return;
+               }
+               if (L_ECHO(tty)) {
+                       finish_erasing(tty);
+                       /* Record the column of first canon char. */
+                       if (tty->canon_head == tty->read_head)
+                               echo_set_canon_col(tty);
+                       echo_char(c, tty);
+                       process_echoes(tty);
+               }
+               if (parmrk)
+                       put_tty_queue(c, tty);
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (I_IXON(tty)) {
+               if (c == START_CHAR(tty)) {
+                       start_tty(tty);
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == STOP_CHAR(tty)) {
+                       stop_tty(tty);
+                       return;
+               }
+       }
+
+       if (L_ISIG(tty)) {
+               int signal;
+               signal = SIGINT;
+               if (c == INTR_CHAR(tty))
+                       goto send_signal;
+               signal = SIGQUIT;
+               if (c == QUIT_CHAR(tty))
+                       goto send_signal;
+               signal = SIGTSTP;
+               if (c == SUSP_CHAR(tty)) {
+send_signal:
+                       /*
+                        * Note that we do not use isig() here because we want
+                        * the order to be:
+                        * 1) flush, 2) echo, 3) signal
+                        */
+                       if (!L_NOFLSH(tty)) {
+                               n_tty_flush_buffer(tty);
+                               tty_driver_flush_buffer(tty);
+                       }
+                       if (I_IXON(tty))
+                               start_tty(tty);
+                       if (L_ECHO(tty)) {
+                               echo_char(c, tty);
+                               process_echoes(tty);
+                       }
+                       if (tty->pgrp)
+                               kill_pgrp(tty->pgrp, signal, 1);
+                       return;
+               }
+       }
+
+       if (c == '\r') {
+               if (I_IGNCR(tty))
+                       return;
+               if (I_ICRNL(tty))
+                       c = '\n';
+       } else if (c == '\n' && I_INLCR(tty))
+               c = '\r';
+
+       if (tty->icanon) {
+               if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
+                   (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
+                       eraser(c, tty);
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
+                       tty->lnext = 1;
+                       if (L_ECHO(tty)) {
+                               finish_erasing(tty);
+                               if (L_ECHOCTL(tty)) {
+                                       echo_char_raw('^', tty);
+                                       echo_char_raw('\b', tty);
+                                       process_echoes(tty);
+                               }
+                       }
+                       return;
+               }
+               if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
+                   L_IEXTEN(tty)) {
+                       unsigned long tail = tty->canon_head;
+
+                       finish_erasing(tty);
+                       echo_char(c, tty);
+                       echo_char_raw('\n', tty);
+                       while (tail != tty->read_head) {
+                               echo_char(tty->read_buf[tail], tty);
+                               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+                       }
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == '\n') {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
+                       if (L_ECHO(tty) || L_ECHONL(tty)) {
+                               echo_char_raw('\n', tty);
+                               process_echoes(tty);
+                       }
+                       goto handle_newline;
+               }
+               if (c == EOF_CHAR(tty)) {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
+                               return;
+                       if (tty->canon_head != tty->read_head)
+                               set_bit(TTY_PUSH, &tty->flags);
+                       c = __DISABLED_CHAR;
+                       goto handle_newline;
+               }
+               if ((c == EOL_CHAR(tty)) ||
+                   (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
+                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
+                                ? 1 : 0;
+                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
+                       /*
+                        * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
+                        */
+                       if (L_ECHO(tty)) {
+                               /* Record the column of first canon char. */
+                               if (tty->canon_head == tty->read_head)
+                                       echo_set_canon_col(tty);
+                               echo_char(c, tty);
+                               process_echoes(tty);
+                       }
+                       /*
+                        * XXX does PARMRK doubling happen for
+                        * EOL_CHAR and EOL2_CHAR?
+                        */
+                       if (parmrk)
+                               put_tty_queue(c, tty);
+
+handle_newline:
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       set_bit(tty->read_head, tty->read_flags);
+                       put_tty_queue_nolock(c, tty);
+                       tty->canon_head = tty->read_head;
+                       tty->canon_data++;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       kill_fasync(&tty->fasync, SIGIO, POLL_IN);
+                       if (waitqueue_active(&tty->read_wait))
+                               wake_up_interruptible(&tty->read_wait);
+                       return;
+               }
+       }
+
+       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+               /* beep if no space */
+               if (L_ECHO(tty))
+                       process_output('\a', tty);
+               return;
+       }
+       if (L_ECHO(tty)) {
+               finish_erasing(tty);
+               if (c == '\n')
+                       echo_char_raw('\n', tty);
+               else {
+                       /* Record the column of first canon char. */
+                       if (tty->canon_head == tty->read_head)
+                               echo_set_canon_col(tty);
+                       echo_char(c, tty);
+               }
+               process_echoes(tty);
+       }
+
+       if (parmrk)
+               put_tty_queue(c, tty);
+
+       put_tty_queue(c, tty);
+}
+
+
+/**
+ *     n_tty_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
+ */
+
+static void n_tty_write_wakeup(struct tty_struct *tty)
+{
+       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
+               kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+}
+
+/**
+ *     n_tty_receive_buf       -       data receive
+ *     @tty: terminal device
+ *     @cp: buffer
+ *     @fp: flag buffer
+ *     @count: characters
+ *
+ *     Called by the terminal driver when a block of characters has
+ *     been received. This function must be called from soft contexts
+ *     not from interrupt context. The driver is responsible for making
+ *     calls one at a time and in order (or using flush_to_ldisc)
+ */
+
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       const unsigned char *p;
+       char *f, flags = TTY_NORMAL;
+       int     i;
+       char    buf[64];
+       unsigned long cpuflags;
+
+       if (!tty->read_buf)
+               return;
+
+       if (tty->real_raw) {
+               spin_lock_irqsave(&tty->read_lock, cpuflags);
+               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
+                       N_TTY_BUF_SIZE - tty->read_head);
+               i = min(count, i);
+               memcpy(tty->read_buf + tty->read_head, cp, i);
+               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt += i;
+               cp += i;
+               count -= i;
+
+               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
+                       N_TTY_BUF_SIZE - tty->read_head);
+               i = min(count, i);
+               memcpy(tty->read_buf + tty->read_head, cp, i);
+               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt += i;
+               spin_unlock_irqrestore(&tty->read_lock, cpuflags);
+       } else {
+               for (i = count, p = cp, f = fp; i; i--, p++) {
+                       if (f)
+                               flags = *f++;
+                       switch (flags) {
+                       case TTY_NORMAL:
+                               n_tty_receive_char(tty, *p);
+                               break;
+                       case TTY_BREAK:
+                               n_tty_receive_break(tty);
+                               break;
+                       case TTY_PARITY:
+                       case TTY_FRAME:
+                               n_tty_receive_parity_error(tty, *p);
+                               break;
+                       case TTY_OVERRUN:
+                               n_tty_receive_overrun(tty);
+                               break;
+                       default:
+                               printk(KERN_ERR "%s: unknown flag %d\n",
+                                      tty_name(tty, buf), flags);
+                               break;
+                       }
+               }
+               if (tty->ops->flush_chars)
+                       tty->ops->flush_chars(tty);
+       }
+
+       n_tty_set_room(tty);
+
+       if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
+               L_EXTPROC(tty)) {
+               kill_fasync(&tty->fasync, SIGIO, POLL_IN);
+               if (waitqueue_active(&tty->read_wait))
+                       wake_up_interruptible(&tty->read_wait);
+       }
+
+       /*
+        * Check the remaining room for the input canonicalization
+        * mode.  We don't want to throttle the driver if we're in
+        * canonical mode and don't have a newline yet!
+        */
+       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+               tty_throttle(tty);
+}
+
+int is_ignored(int sig)
+{
+       return (sigismember(&current->blocked, sig) ||
+               current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
+}
+
+/**
+ *     n_tty_set_termios       -       termios data changed
+ *     @tty: terminal
+ *     @old: previous data
+ *
+ *     Called by the tty layer when the user changes termios flags so
+ *     that the line discipline can plan ahead. This function cannot sleep
+ *     and is protected from re-entry by the tty layer. The user is
+ *     guaranteed that this function will not be re-entered or in progress
+ *     when the ldisc is closed.
+ *
+ *     Locking: Caller holds tty->termios_mutex
+ */
+
+static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       int canon_change = 1;
+       BUG_ON(!tty);
+
+       if (old)
+               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+       if (canon_change) {
+               memset(&tty->read_flags, 0, sizeof tty->read_flags);
+               tty->canon_head = tty->read_tail;
+               tty->canon_data = 0;
+               tty->erasing = 0;
+       }
+
+       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+               wake_up_interruptible(&tty->read_wait);
+
+       tty->icanon = (L_ICANON(tty) != 0);
+       if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
+               tty->raw = 1;
+               tty->real_raw = 1;
+               n_tty_set_room(tty);
+               return;
+       }
+       if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
+           I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
+           I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
+           I_PARMRK(tty)) {
+               memset(tty->process_char_map, 0, 256/8);
+
+               if (I_IGNCR(tty) || I_ICRNL(tty))
+                       set_bit('\r', tty->process_char_map);
+               if (I_INLCR(tty))
+                       set_bit('\n', tty->process_char_map);
+
+               if (L_ICANON(tty)) {
+                       set_bit(ERASE_CHAR(tty), tty->process_char_map);
+                       set_bit(KILL_CHAR(tty), tty->process_char_map);
+                       set_bit(EOF_CHAR(tty), tty->process_char_map);
+                       set_bit('\n', tty->process_char_map);
+                       set_bit(EOL_CHAR(tty), tty->process_char_map);
+                       if (L_IEXTEN(tty)) {
+                               set_bit(WERASE_CHAR(tty),
+                                       tty->process_char_map);
+                               set_bit(LNEXT_CHAR(tty),
+                                       tty->process_char_map);
+                               set_bit(EOL2_CHAR(tty),
+                                       tty->process_char_map);
+                               if (L_ECHO(tty))
+                                       set_bit(REPRINT_CHAR(tty),
+                                               tty->process_char_map);
+                       }
+               }
+               if (I_IXON(tty)) {
+                       set_bit(START_CHAR(tty), tty->process_char_map);
+                       set_bit(STOP_CHAR(tty), tty->process_char_map);
+               }
+               if (L_ISIG(tty)) {
+                       set_bit(INTR_CHAR(tty), tty->process_char_map);
+                       set_bit(QUIT_CHAR(tty), tty->process_char_map);
+                       set_bit(SUSP_CHAR(tty), tty->process_char_map);
+               }
+               clear_bit(__DISABLED_CHAR, tty->process_char_map);
+               tty->raw = 0;
+               tty->real_raw = 0;
+       } else {
+               tty->raw = 1;
+               if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
+                   (I_IGNPAR(tty) || !I_INPCK(tty)) &&
+                   (tty->driver->flags & TTY_DRIVER_REAL_RAW))
+                       tty->real_raw = 1;
+               else
+                       tty->real_raw = 0;
+       }
+       n_tty_set_room(tty);
+       /* The termios change make the tty ready for I/O */
+       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is
+ *     being shut down, either because of a close or becsuse of a
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+
+static void n_tty_close(struct tty_struct *tty)
+{
+       n_tty_flush_buffer(tty);
+       if (tty->read_buf) {
+               kfree(tty->read_buf);
+               tty->read_buf = NULL;
+       }
+       if (tty->echo_buf) {
+               kfree(tty->echo_buf);
+               tty->echo_buf = NULL;
+       }
+}
+
+/**
+ *     n_tty_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
+static int n_tty_open(struct tty_struct *tty)
+{
+       if (!tty)
+               return -EINVAL;
+
+       /* These are ugly. Currently a malloc failure here can panic */
+       if (!tty->read_buf) {
+               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+               if (!tty->read_buf)
+                       return -ENOMEM;
+       }
+       if (!tty->echo_buf) {
+               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+
+               if (!tty->echo_buf)
+                       return -ENOMEM;
+       }
+       reset_buffer_flags(tty);
+       tty->column = 0;
+       n_tty_set_termios(tty, NULL);
+       tty->minimum_to_wake = 1;
+       tty->closing = 0;
+       return 0;
+}
+
+static inline int input_available_p(struct tty_struct *tty, int amt)
+{
+       tty_flush_to_ldisc(tty);
+       if (tty->icanon && !L_EXTPROC(tty)) {
+               if (tty->canon_data)
+                       return 1;
+       } else if (tty->read_cnt >= (amt ? amt : 1))
+               return 1;
+
+       return 0;
+}
+
+/**
+ *     copy_from_read_buf      -       copy read data directly
+ *     @tty: terminal device
+ *     @b: user data
+ *     @nr: size of data
+ *
+ *     Helper function to speed up n_tty_read.  It is only called when
+ *     ICANON is off; it copies characters straight from the tty queue to
+ *     user space directly.  It can be profitably called twice; once to
+ *     drain the space from the tail pointer to the (physical) end of the
+ *     buffer, and once to drain the space from the (physical) beginning of
+ *     the buffer to head pointer.
+ *
+ *     Called under the tty->atomic_read_lock sem
+ *
+ */
+
+static int copy_from_read_buf(struct tty_struct *tty,
+                                     unsigned char __user **b,
+                                     size_t *nr)
+
+{
+       int retval;
+       size_t n;
+       unsigned long flags;
+
+       retval = 0;
+       spin_lock_irqsave(&tty->read_lock, flags);
+       n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
+       n = min(*nr, n);
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+       if (n) {
+               retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+               n -= retval;
+               tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
+               spin_lock_irqsave(&tty->read_lock, flags);
+               tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt -= n;
+               /* Turn single EOF into zero-length read */
+               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
+                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
+                               n--;
+               }
+               spin_unlock_irqrestore(&tty->read_lock, flags);
+               *b += n;
+               *nr -= n;
+       }
+       return retval;
+}
+
+extern ssize_t redirected_tty_write(struct file *, const char __user *,
+                                                       size_t, loff_t *);
+
+/**
+ *     job_control             -       check job control
+ *     @tty: tty
+ *     @file: file handle
+ *
+ *     Perform job control management checks on this file/tty descriptor
+ *     and if appropriate send any needed signals and return a negative
+ *     error code if action should be taken.
+ *
+ *     FIXME:
+ *     Locking: None - redirected write test is safe, testing
+ *     current->signal should possibly lock current->sighand
+ *     pgrp locking ?
+ */
+
+static int job_control(struct tty_struct *tty, struct file *file)
+{
+       /* Job control check -- must be done at start and after
+          every sleep (POSIX.1 7.1.1.4). */
+       /* NOTE: not yet done after every sleep pending a thorough
+          check of the logic of this change. -- jlc */
+       /* don't stop on /dev/console */
+       if (file->f_op->write != redirected_tty_write &&
+           current->signal->tty == tty) {
+               if (!tty->pgrp)
+                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
+               else if (task_pgrp(current) != tty->pgrp) {
+                       if (is_ignored(SIGTTIN) ||
+                           is_current_pgrp_orphaned())
+                               return -EIO;
+                       kill_pgrp(task_pgrp(current), SIGTTIN, 1);
+                       set_thread_flag(TIF_SIGPENDING);
+                       return -ERESTARTSYS;
+               }
+       }
+       return 0;
+}
+
+
+/**
+ *     n_tty_read              -       read function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Perform reads for the line discipline. We are guaranteed that the
+ *     line discipline will not be closed under us but we may get multiple
+ *     parallel readers and must handle this ourselves. We may also get
+ *     a hangup. Always called in user context, may sleep.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ */
+
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+                        unsigned char __user *buf, size_t nr)
+{
+       unsigned char __user *b = buf;
+       DECLARE_WAITQUEUE(wait, current);
+       int c;
+       int minimum, time;
+       ssize_t retval = 0;
+       ssize_t size;
+       long timeout;
+       unsigned long flags;
+       int packet;
+
+do_it_again:
+
+       BUG_ON(!tty->read_buf);
+
+       c = job_control(tty, file);
+       if (c < 0)
+               return c;
+
+       minimum = time = 0;
+       timeout = MAX_SCHEDULE_TIMEOUT;
+       if (!tty->icanon) {
+               time = (HZ / 10) * TIME_CHAR(tty);
+               minimum = MIN_CHAR(tty);
+               if (minimum) {
+                       if (time)
+                               tty->minimum_to_wake = 1;
+                       else if (!waitqueue_active(&tty->read_wait) ||
+                                (tty->minimum_to_wake > minimum))
+                               tty->minimum_to_wake = minimum;
+               } else {
+                       timeout = 0;
+                       if (time) {
+                               timeout = time;
+                               time = 0;
+                       }
+                       tty->minimum_to_wake = minimum = 1;
+               }
+       }
+
+       /*
+        *      Internal serialization of reads.
+        */
+       if (file->f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&tty->atomic_read_lock))
+                       return -EAGAIN;
+       } else {
+               if (mutex_lock_interruptible(&tty->atomic_read_lock))
+                       return -ERESTARTSYS;
+       }
+       packet = tty->packet;
+
+       add_wait_queue(&tty->read_wait, &wait);
+       while (nr) {
+               /* First test for status change. */
+               if (packet && tty->link->ctrl_status) {
+                       unsigned char cs;
+                       if (b != buf)
+                               break;
+                       spin_lock_irqsave(&tty->link->ctrl_lock, flags);
+                       cs = tty->link->ctrl_status;
+                       tty->link->ctrl_status = 0;
+                       spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+                       if (tty_put_user(tty, cs, b++)) {
+                               retval = -EFAULT;
+                               b--;
+                               break;
+                       }
+                       nr--;
+                       break;
+               }
+               /* This statement must be first before checking for input
+                  so that any interrupt will set the state back to
+                  TASK_RUNNING. */
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
+                   ((minimum - (b - buf)) >= 1))
+                       tty->minimum_to_wake = (minimum - (b - buf));
+
+               if (!input_available_p(tty, 0)) {
+                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                               retval = -EIO;
+                               break;
+                       }
+                       if (tty_hung_up_p(file))
+                               break;
+                       if (!timeout)
+                               break;
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       /* FIXME: does n_tty_set_room need locking ? */
+                       n_tty_set_room(tty);
+                       timeout = schedule_timeout(timeout);
+                       continue;
+               }
+               __set_current_state(TASK_RUNNING);
+
+               /* Deal with packet mode. */
+               if (packet && b == buf) {
+                       if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
+                               retval = -EFAULT;
+                               b--;
+                               break;
+                       }
+                       nr--;
+               }
+
+               if (tty->icanon && !L_EXTPROC(tty)) {
+                       /* N.B. avoid overrun if nr == 0 */
+                       while (nr && tty->read_cnt) {
+                               int eol;
+
+                               eol = test_and_clear_bit(tty->read_tail,
+                                               tty->read_flags);
+                               c = tty->read_buf[tty->read_tail];
+                               spin_lock_irqsave(&tty->read_lock, flags);
+                               tty->read_tail = ((tty->read_tail+1) &
+                                                 (N_TTY_BUF_SIZE-1));
+                               tty->read_cnt--;
+                               if (eol) {
+                                       /* this test should be redundant:
+                                        * we shouldn't be reading data if
+                                        * canon_data is 0
+                                        */
+                                       if (--tty->canon_data < 0)
+                                               tty->canon_data = 0;
+                               }
+                               spin_unlock_irqrestore(&tty->read_lock, flags);
+
+                               if (!eol || (c != __DISABLED_CHAR)) {
+                                       if (tty_put_user(tty, c, b++)) {
+                                               retval = -EFAULT;
+                                               b--;
+                                               break;
+                                       }
+                                       nr--;
+                               }
+                               if (eol) {
+                                       tty_audit_push(tty);
+                                       break;
+                               }
+                       }
+                       if (retval)
+                               break;
+               } else {
+                       int uncopied;
+                       /* The copy function takes the read lock and handles
+                          locking internally for this case */
+                       uncopied = copy_from_read_buf(tty, &b, &nr);
+                       uncopied += copy_from_read_buf(tty, &b, &nr);
+                       if (uncopied) {
+                               retval = -EFAULT;
+                               break;
+                       }
+               }
+
+               /* If there is enough space in the read buffer now, let the
+                * low-level driver know. We use n_tty_chars_in_buffer() to
+                * check the buffer, as it now knows about canonical mode.
+                * Otherwise, if the driver is throttled and the line is
+                * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+                * we won't get any more characters.
+                */
+               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+                       n_tty_set_room(tty);
+                       check_unthrottle(tty);
+               }
+
+               if (b - buf >= minimum)
+                       break;
+               if (time)
+                       timeout = time;
+       }
+       mutex_unlock(&tty->atomic_read_lock);
+       remove_wait_queue(&tty->read_wait, &wait);
+
+       if (!waitqueue_active(&tty->read_wait))
+               tty->minimum_to_wake = minimum;
+
+       __set_current_state(TASK_RUNNING);
+       size = b - buf;
+       if (size) {
+               retval = size;
+               if (nr)
+                       clear_bit(TTY_PUSH, &tty->flags);
+       } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
+                goto do_it_again;
+
+       n_tty_set_room(tty);
+       return retval;
+}
+
+/**
+ *     n_tty_write             -       write function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Write function of the terminal device.  This is serialized with
+ *     respect to other write callers but not to termios changes, reads
+ *     and other such events.  Since the receive code will echo characters,
+ *     thus calling driver write methods, the output_lock is used in
+ *     the output processing functions called here as well as in the
+ *     echo processing function to protect the column state and space
+ *     left in the buffer.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (note that the process_output*() functions take this
+ *               lock themselves)
+ */
+
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *buf, size_t nr)
+{
+       const unsigned char *b = buf;
+       DECLARE_WAITQUEUE(wait, current);
+       int c;
+       ssize_t retval = 0;
+
+       /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+       }
+
+       /* Write out any echoed characters that are still pending */
+       process_echoes(tty);
+
+       add_wait_queue(&tty->write_wait, &wait);
+       while (1) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
+                       retval = -EIO;
+                       break;
+               }
+               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                       while (nr > 0) {
+                               ssize_t num = process_output_block(tty, b, nr);
+                               if (num < 0) {
+                                       if (num == -EAGAIN)
+                                               break;
+                                       retval = num;
+                                       goto break_out;
+                               }
+                               b += num;
+                               nr -= num;
+                               if (nr == 0)
+                                       break;
+                               c = *b;
+                               if (process_output(c, tty) < 0)
+                                       break;
+                               b++; nr--;
+                       }
+                       if (tty->ops->flush_chars)
+                               tty->ops->flush_chars(tty);
+               } else {
+                       while (nr > 0) {
+                               c = tty->ops->write(tty, b, nr);
+                               if (c < 0) {
+                                       retval = c;
+                                       goto break_out;
+                               }
+                               if (!c)
+                                       break;
+                               b += c;
+                               nr -= c;
+                       }
+               }
+               if (!nr)
+                       break;
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       break;
+               }
+               schedule();
+       }
+break_out:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+       if (b - buf != nr && tty->fasync)
+               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       return (b - buf) ? b - buf : retval;
+}
+
+/**
+ *     n_tty_poll              -       poll method for N_TTY
+ *     @tty: terminal device
+ *     @file: file accessing it
+ *     @wait: poll table
+ *
+ *     Called when the line discipline is asked to poll() for data or
+ *     for special events. This code is not serialized with respect to
+ *     other events save open/close.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *     Called without the kernel lock held - fine
+ */
+
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
+                                                       poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &tty->read_wait, wait);
+       poll_wait(file, &tty->write_wait, wait);
+       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
+               mask |= POLLIN | POLLRDNORM;
+       if (tty->packet && tty->link->ctrl_status)
+               mask |= POLLPRI | POLLIN | POLLRDNORM;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               mask |= POLLHUP;
+       if (tty_hung_up_p(file))
+               mask |= POLLHUP;
+       if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
+               if (MIN_CHAR(tty) && !TIME_CHAR(tty))
+                       tty->minimum_to_wake = MIN_CHAR(tty);
+               else
+                       tty->minimum_to_wake = 1;
+       }
+       if (tty->ops->write && !tty_is_writelocked(tty) &&
+                       tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
+                       tty_write_room(tty) > 0)
+               mask |= POLLOUT | POLLWRNORM;
+       return mask;
+}
+
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+       int nr, head, tail;
+
+       if (!tty->canon_data)
+               return 0;
+       head = tty->canon_head;
+       tail = tty->read_tail;
+       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+       /* Skip EOF-chars.. */
+       while (head != tail) {
+               if (test_bit(tail, tty->read_flags) &&
+                   tty->read_buf[tail] == __DISABLED_CHAR)
+                       nr--;
+               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       }
+       return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       int retval;
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+       case TIOCINQ:
+               /* FIXME: Locking */
+               retval = tty->read_cnt;
+               if (L_ICANON(tty))
+                       retval = inq_canon(tty);
+               return put_user(retval, (unsigned int __user *) arg);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
+struct tty_ldisc_ops tty_ldisc_N_TTY = {
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_tty",
+       .open            = n_tty_open,
+       .close           = n_tty_close,
+       .flush_buffer    = n_tty_flush_buffer,
+       .chars_in_buffer = n_tty_chars_in_buffer,
+       .read            = n_tty_read,
+       .write           = n_tty_write,
+       .ioctl           = n_tty_ioctl,
+       .set_termios     = n_tty_set_termios,
+       .poll            = n_tty_poll,
+       .receive_buf     = n_tty_receive_buf,
+       .write_wakeup    = n_tty_write_wakeup
+};
+
+/**
+ *     n_tty_inherit_ops       -       inherit N_TTY methods
+ *     @ops: struct tty_ldisc_ops where to save N_TTY methods
+ *
+ *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
+ *     methods.
+ */
+
+void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
+{
+       *ops = tty_ldisc_N_TTY;
+       ops->owner = NULL;
+       ops->refcount = ops->flags = 0;
+}
+EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
new file mode 100644 (file)
index 0000000..923a485
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ *  linux/drivers/char/pty.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added support for a Unix98-style ptmx device.
+ *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
+ */
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/sysctl.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/devpts_fs.h>
+#include <linux/slab.h>
+
+#include <asm/system.h>
+
+#ifdef CONFIG_UNIX98_PTYS
+static struct tty_driver *ptm_driver;
+static struct tty_driver *pts_driver;
+#endif
+
+static void pty_close(struct tty_struct *tty, struct file *filp)
+{
+       BUG_ON(!tty);
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               WARN_ON(tty->count > 1);
+       else {
+               if (tty->count > 2)
+                       return;
+       }
+       wake_up_interruptible(&tty->read_wait);
+       wake_up_interruptible(&tty->write_wait);
+       tty->packet = 0;
+       if (!tty->link)
+               return;
+       tty->link->packet = 0;
+       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       wake_up_interruptible(&tty->link->read_wait);
+       wake_up_interruptible(&tty->link->write_wait);
+       if (tty->driver->subtype == PTY_TYPE_MASTER) {
+               set_bit(TTY_OTHER_CLOSED, &tty->flags);
+#ifdef CONFIG_UNIX98_PTYS
+               if (tty->driver == ptm_driver)
+                       devpts_pty_kill(tty->link);
+#endif
+               tty_unlock();
+               tty_vhangup(tty->link);
+               tty_lock();
+       }
+}
+
+/*
+ * The unthrottle routine is called by the line discipline to signal
+ * that it can receive more characters.  For PTY's, the TTY_THROTTLED
+ * flag is always set, to force the line discipline to always call the
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
+ * characters in the queue.  This is necessary since each time this
+ * happens, we need to wake up any sleeping processes that could be
+ * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
+ * for the pty buffer to be drained.
+ */
+static void pty_unthrottle(struct tty_struct *tty)
+{
+       tty_wakeup(tty->link);
+       set_bit(TTY_THROTTLED, &tty->flags);
+}
+
+/**
+ *     pty_space       -       report space left for writing
+ *     @to: tty we are writing into
+ *
+ *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
+ *     allows a lot of overspill room for echo and other fun messes to
+ *     be handled properly
+ */
+
+static int pty_space(struct tty_struct *to)
+{
+       int n = 8192 - to->buf.memory_used;
+       if (n < 0)
+               return 0;
+       return n;
+}
+
+/**
+ *     pty_write               -       write to a pty
+ *     @tty: the tty we write from
+ *     @buf: kernel buffer of data
+ *     @count: bytes to write
+ *
+ *     Our "hardware" write method. Data is coming from the ldisc which
+ *     may be in a non sleeping state. We simply throw this at the other
+ *     end of the link as if we were an IRQ handler receiving stuff for
+ *     the other side of the pty/tty pair.
+ */
+
+static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
+{
+       struct tty_struct *to = tty->link;
+
+       if (tty->stopped)
+               return 0;
+
+       if (c > 0) {
+               /* Stuff the data into the input queue of the other end */
+               c = tty_insert_flip_string(to, buf, c);
+               /* And shovel */
+               if (c) {
+                       tty_flip_buffer_push(to);
+                       tty_wakeup(tty);
+               }
+       }
+       return c;
+}
+
+/**
+ *     pty_write_room  -       write space
+ *     @tty: tty we are writing from
+ *
+ *     Report how many bytes the ldisc can send into the queue for
+ *     the other device.
+ */
+
+static int pty_write_room(struct tty_struct *tty)
+{
+       if (tty->stopped)
+               return 0;
+       return pty_space(tty->link);
+}
+
+/**
+ *     pty_chars_in_buffer     -       characters currently in our tx queue
+ *     @tty: our tty
+ *
+ *     Report how much we have in the transmit queue. As everything is
+ *     instantly at the other end this is easy to implement.
+ */
+
+static int pty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+/* Set the lock flag on a pty */
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
+{
+       int val;
+       if (get_user(val, arg))
+               return -EFAULT;
+       if (val)
+               set_bit(TTY_PTY_LOCK, &tty->flags);
+       else
+               clear_bit(TTY_PTY_LOCK, &tty->flags);
+       return 0;
+}
+
+/* Send a signal to the slave */
+static int pty_signal(struct tty_struct *tty, int sig)
+{
+       unsigned long flags;
+       struct pid *pgrp;
+
+       if (tty->link) {
+               spin_lock_irqsave(&tty->link->ctrl_lock, flags);
+               pgrp = get_pid(tty->link->pgrp);
+               spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+
+               kill_pgrp(pgrp, sig, 1);
+               put_pid(pgrp);
+       }
+       return 0;
+}
+
+static void pty_flush_buffer(struct tty_struct *tty)
+{
+       struct tty_struct *to = tty->link;
+       unsigned long flags;
+
+       if (!to)
+               return;
+       /* tty_buffer_flush(to); FIXME */
+       if (to->packet) {
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+               wake_up_interruptible(&to->read_wait);
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       }
+}
+
+static int pty_open(struct tty_struct *tty, struct file *filp)
+{
+       int     retval = -ENODEV;
+
+       if (!tty || !tty->link)
+               goto out;
+
+       retval = -EIO;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               goto out;
+       if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
+               goto out;
+       if (tty->link->count != 1)
+               goto out;
+
+       clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       set_bit(TTY_THROTTLED, &tty->flags);
+       retval = 0;
+out:
+       return retval;
+}
+
+static void pty_set_termios(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
+{
+       tty->termios->c_cflag &= ~(CSIZE | PARENB);
+       tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+/**
+ *     pty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @ws: window size being set.
+ *
+ *     Update the termios variables and send the necessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int pty_resize(struct tty_struct *tty,  struct winsize *ws)
+{
+       struct pid *pgrp, *rpgrp;
+       unsigned long flags;
+       struct tty_struct *pty = tty->link;
+
+       /* For a PTY we need to lock the tty side */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals.
+          We need to lock these individually however. */
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       spin_lock_irqsave(&pty->ctrl_lock, flags);
+       rpgrp = get_pid(pty->pgrp);
+       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       if (rpgrp != pgrp && rpgrp)
+               kill_pgrp(rpgrp, SIGWINCH, 1);
+
+       put_pid(pgrp);
+       put_pid(rpgrp);
+
+       tty->winsize = *ws;
+       pty->winsize = *ws;     /* Never used so will go away soon */
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+       int retval;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       /* We always use new tty termios data so we can do this
+          the easy way .. */
+       retval = tty_init_termios(tty);
+       if (retval)
+               goto free_mem_out;
+
+       retval = tty_init_termios(o_tty);
+       if (retval) {
+               tty_free_termios(tty);
+               goto free_mem_out;
+       }
+
+       /*
+        * Everything allocated ... set up the o_tty structure.
+        */
+       driver->other->ttys[idx] = o_tty;
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[idx] = tty;
+       return 0;
+free_mem_out:
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       return -ENOMEM;
+}
+
+static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+               return pty_set_lock(tty, (int __user *) arg);
+       case TIOCSIG:    /* Send signal to other side of pty */
+               return pty_signal(tty, (int) arg);
+       }
+       return -ENOIOCTLCMD;
+}
+
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
+/*
+ * The master side of a pty can do TIOCSPTLCK and thus
+ * has pty_bsd_ioctl.
+ */
+static const struct tty_operations master_pty_ops_bsd = {
+       .install = pty_install,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_bsd_ioctl,
+       .resize = pty_resize
+};
+
+static const struct tty_operations slave_pty_ops_bsd = {
+       .install = pty_install,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .resize = pty_resize
+};
+
+static void __init legacy_pty_init(void)
+{
+       struct tty_driver *pty_driver, *pty_slave_driver;
+
+       if (legacy_count <= 0)
+               return;
+
+       pty_driver = alloc_tty_driver(legacy_count);
+       if (!pty_driver)
+               panic("Couldn't allocate pty driver");
+
+       pty_slave_driver = alloc_tty_driver(legacy_count);
+       if (!pty_slave_driver)
+               panic("Couldn't allocate pty slave driver");
+
+       pty_driver->owner = THIS_MODULE;
+       pty_driver->driver_name = "pty_master";
+       pty_driver->name = "pty";
+       pty_driver->major = PTY_MASTER_MAJOR;
+       pty_driver->minor_start = 0;
+       pty_driver->type = TTY_DRIVER_TYPE_PTY;
+       pty_driver->subtype = PTY_TYPE_MASTER;
+       pty_driver->init_termios = tty_std_termios;
+       pty_driver->init_termios.c_iflag = 0;
+       pty_driver->init_termios.c_oflag = 0;
+       pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pty_driver->init_termios.c_lflag = 0;
+       pty_driver->init_termios.c_ispeed = 38400;
+       pty_driver->init_termios.c_ospeed = 38400;
+       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
+       pty_driver->other = pty_slave_driver;
+       tty_set_operations(pty_driver, &master_pty_ops_bsd);
+
+       pty_slave_driver->owner = THIS_MODULE;
+       pty_slave_driver->driver_name = "pty_slave";
+       pty_slave_driver->name = "ttyp";
+       pty_slave_driver->major = PTY_SLAVE_MAJOR;
+       pty_slave_driver->minor_start = 0;
+       pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
+       pty_slave_driver->subtype = PTY_TYPE_SLAVE;
+       pty_slave_driver->init_termios = tty_std_termios;
+       pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pty_slave_driver->init_termios.c_ispeed = 38400;
+       pty_slave_driver->init_termios.c_ospeed = 38400;
+       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+                                       TTY_DRIVER_REAL_RAW;
+       pty_slave_driver->other = pty_driver;
+       tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
+
+       if (tty_register_driver(pty_driver))
+               panic("Couldn't register pty driver");
+       if (tty_register_driver(pty_slave_driver))
+               panic("Couldn't register pty slave driver");
+}
+#else
+static inline void legacy_pty_init(void) { }
+#endif
+
+/* Unix98 devices */
+#ifdef CONFIG_UNIX98_PTYS
+/*
+ * sysctl support for setting limits on the number of Unix98 ptys allocated.
+ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
+ */
+int pty_limit = NR_UNIX98_PTY_DEFAULT;
+static int pty_limit_min;
+static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
+
+static struct ctl_table pty_table[] = {
+       {
+               .procname       = "max",
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .data           = &pty_limit,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &pty_limit_min,
+               .extra2         = &pty_limit_max,
+       }, {
+               .procname       = "nr",
+               .maxlen         = sizeof(int),
+               .mode           = 0444,
+               .data           = &pty_count,
+               .proc_handler   = proc_dointvec,
+       }, 
+       {}
+};
+
+static struct ctl_table pty_kern_table[] = {
+       {
+               .procname       = "pty",
+               .mode           = 0555,
+               .child          = pty_table,
+       },
+       {}
+};
+
+static struct ctl_table pty_root_table[] = {
+       {
+               .procname       = "kernel",
+               .mode           = 0555,
+               .child          = pty_kern_table,
+       },
+       {}
+};
+
+
+static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+               return pty_set_lock(tty, (int __user *)arg);
+       case TIOCGPTN: /* Get PT Number */
+               return put_user(tty->index, (unsigned int __user *)arg);
+       case TIOCSIG:    /* Send signal to other side of pty */
+               return pty_signal(tty, (int) arg);
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+/**
+ *     ptm_unix98_lookup       -       find a pty master
+ *     @driver: ptm driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+               struct inode *ptm_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+       if (tty)
+               tty = tty->link;
+       return tty;
+}
+
+/**
+ *     pts_unix98_lookup       -       find a pty slave
+ *     @driver: pts driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+               struct inode *pts_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+       /* Master must be open before slave */
+       if (!tty)
+               return ERR_PTR(-EIO);
+       return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+       /* We have our own method as we don't use the tty index */
+       kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (tty->termios == NULL)
+               goto free_mem_out;
+       *tty->termios = driver->init_termios;
+       tty->termios_locked = tty->termios + 1;
+
+       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (o_tty->termios == NULL)
+               goto free_mem_out;
+       *o_tty->termios = driver->other->init_termios;
+       o_tty->termios_locked = o_tty->termios + 1;
+
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+       /*
+        * All structures have been allocated, so now we install them.
+        * Failures after this point use release_tty to clean up, so
+        * there's no need to null out the local pointers.
+        */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       pty_count++;
+       return 0;
+free_mem_out:
+       kfree(o_tty->termios);
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       kfree(tty->termios);
+       return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+       .lookup = ptm_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_unix98_ioctl,
+       .shutdown = pty_unix98_shutdown,
+       .resize = pty_resize
+};
+
+static const struct tty_operations pty_unix98_ops = {
+       .lookup = pts_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .shutdown = pty_unix98_shutdown
+};
+
+/**
+ *     ptmx_open               -       open a unix 98 pty master
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *     Locking: tty_mutex protects the init_dev work. tty->count should
+ *             protect the rest.
+ *             allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty;
+       int retval;
+       int index;
+
+       nonseekable_open(inode, filp);
+
+       /* find a device that is not in use. */
+       tty_lock();
+       index = devpts_new_index(inode);
+       tty_unlock();
+       if (index < 0)
+               return index;
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+       tty = tty_init_dev(ptm_driver, index, 1);
+       mutex_unlock(&tty_mutex);
+
+       if (IS_ERR(tty)) {
+               retval = PTR_ERR(tty);
+               goto out;
+       }
+
+       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+
+       retval = tty_add_file(tty, filp);
+       if (retval)
+               goto out;
+
+       retval = devpts_pty_new(inode, tty->link);
+       if (retval)
+               goto out1;
+
+       retval = ptm_driver->ops->open(tty, filp);
+       if (retval)
+               goto out2;
+out1:
+       tty_unlock();
+       return retval;
+out2:
+       tty_unlock();
+       tty_release(inode, filp);
+       return retval;
+out:
+       devpts_kill_index(inode, index);
+       tty_unlock();
+       return retval;
+}
+
+static struct file_operations ptmx_fops;
+
+static void __init unix98_pty_init(void)
+{
+       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+       if (!ptm_driver)
+               panic("Couldn't allocate Unix98 ptm driver");
+       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+       if (!pts_driver)
+               panic("Couldn't allocate Unix98 pts driver");
+
+       ptm_driver->owner = THIS_MODULE;
+       ptm_driver->driver_name = "pty_master";
+       ptm_driver->name = "ptm";
+       ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
+       ptm_driver->minor_start = 0;
+       ptm_driver->type = TTY_DRIVER_TYPE_PTY;
+       ptm_driver->subtype = PTY_TYPE_MASTER;
+       ptm_driver->init_termios = tty_std_termios;
+       ptm_driver->init_termios.c_iflag = 0;
+       ptm_driver->init_termios.c_oflag = 0;
+       ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       ptm_driver->init_termios.c_lflag = 0;
+       ptm_driver->init_termios.c_ispeed = 38400;
+       ptm_driver->init_termios.c_ospeed = 38400;
+       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
+       ptm_driver->other = pts_driver;
+       tty_set_operations(ptm_driver, &ptm_unix98_ops);
+
+       pts_driver->owner = THIS_MODULE;
+       pts_driver->driver_name = "pty_slave";
+       pts_driver->name = "pts";
+       pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
+       pts_driver->minor_start = 0;
+       pts_driver->type = TTY_DRIVER_TYPE_PTY;
+       pts_driver->subtype = PTY_TYPE_SLAVE;
+       pts_driver->init_termios = tty_std_termios;
+       pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pts_driver->init_termios.c_ispeed = 38400;
+       pts_driver->init_termios.c_ospeed = 38400;
+       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
+       pts_driver->other = ptm_driver;
+       tty_set_operations(pts_driver, &pty_unix98_ops);
+
+       if (tty_register_driver(ptm_driver))
+               panic("Couldn't register Unix98 ptm driver");
+       if (tty_register_driver(pts_driver))
+               panic("Couldn't register Unix98 pts driver");
+
+       register_sysctl_table(pty_root_table);
+
+       /* Now create the /dev/ptmx special device */
+       tty_default_fops(&ptmx_fops);
+       ptmx_fops.open = ptmx_open;
+
+       cdev_init(&ptmx_cdev, &ptmx_fops);
+       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+               panic("Couldn't register /dev/ptmx driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
+}
+
+#else
+static inline void unix98_pty_init(void) { }
+#endif
+
+static int __init pty_init(void)
+{
+       legacy_pty_init();
+       unix98_pty_init();
+       return 0;
+}
+module_init(pty_init);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
new file mode 100644 (file)
index 0000000..c556ed9
--- /dev/null
@@ -0,0 +1,890 @@
+/*
+ *     Linux Magic System Request Key Hacks
+ *
+ *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ *     overhauled to use key registration
+ *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
+ *
+ *     Copyright (c) 2010 Dmitry Torokhov
+ *     Input handler conversion
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/kbd_kern.h>
+#include <linux/proc_fs.h>
+#include <linux/nmi.h>
+#include <linux/quotaops.h>
+#include <linux/perf_event.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>         /* for fsync_bdev() */
+#include <linux/swap.h>
+#include <linux/spinlock.h>
+#include <linux/vt_kern.h>
+#include <linux/workqueue.h>
+#include <linux/hrtimer.h>
+#include <linux/oom.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
+
+/* Whether we react on sysrq keys or just ignore them */
+static int __read_mostly sysrq_enabled = 1;
+static bool __read_mostly sysrq_always_enabled;
+
+static bool sysrq_on(void)
+{
+       return sysrq_enabled || sysrq_always_enabled;
+}
+
+/*
+ * A value of 1 means 'all', other nonzero values are an op mask:
+ */
+static bool sysrq_on_mask(int mask)
+{
+       return sysrq_always_enabled ||
+              sysrq_enabled == 1 ||
+              (sysrq_enabled & mask);
+}
+
+static int __init sysrq_always_enabled_setup(char *str)
+{
+       sysrq_always_enabled = true;
+       pr_info("sysrq always enabled.\n");
+
+       return 1;
+}
+
+__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
+
+
+static void sysrq_handle_loglevel(int key)
+{
+       int i;
+
+       i = key - '0';
+       console_loglevel = 7;
+       printk("Loglevel set to %d\n", i);
+       console_loglevel = i;
+}
+static struct sysrq_key_op sysrq_loglevel_op = {
+       .handler        = sysrq_handle_loglevel,
+       .help_msg       = "loglevel(0-9)",
+       .action_msg     = "Changing Loglevel",
+       .enable_mask    = SYSRQ_ENABLE_LOG,
+};
+
+#ifdef CONFIG_VT
+static void sysrq_handle_SAK(int key)
+{
+       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+       schedule_work(SAK_work);
+}
+static struct sysrq_key_op sysrq_SAK_op = {
+       .handler        = sysrq_handle_SAK,
+       .help_msg       = "saK",
+       .action_msg     = "SAK",
+       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
+};
+#else
+#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+#ifdef CONFIG_VT
+static void sysrq_handle_unraw(int key)
+{
+       struct kbd_struct *kbd = &kbd_table[fg_console];
+
+       if (kbd)
+               kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+}
+static struct sysrq_key_op sysrq_unraw_op = {
+       .handler        = sysrq_handle_unraw,
+       .help_msg       = "unRaw",
+       .action_msg     = "Keyboard mode set to system default",
+       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
+};
+#else
+#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
+#endif /* CONFIG_VT */
+
+static void sysrq_handle_crash(int key)
+{
+       char *killer = NULL;
+
+       panic_on_oops = 1;      /* force panic */
+       wmb();
+       *killer = 1;
+}
+static struct sysrq_key_op sysrq_crash_op = {
+       .handler        = sysrq_handle_crash,
+       .help_msg       = "Crash",
+       .action_msg     = "Trigger a crash",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_reboot(int key)
+{
+       lockdep_off();
+       local_irq_enable();
+       emergency_restart();
+}
+static struct sysrq_key_op sysrq_reboot_op = {
+       .handler        = sysrq_handle_reboot,
+       .help_msg       = "reBoot",
+       .action_msg     = "Resetting",
+       .enable_mask    = SYSRQ_ENABLE_BOOT,
+};
+
+static void sysrq_handle_sync(int key)
+{
+       emergency_sync();
+}
+static struct sysrq_key_op sysrq_sync_op = {
+       .handler        = sysrq_handle_sync,
+       .help_msg       = "Sync",
+       .action_msg     = "Emergency Sync",
+       .enable_mask    = SYSRQ_ENABLE_SYNC,
+};
+
+static void sysrq_handle_show_timers(int key)
+{
+       sysrq_timer_list_show();
+}
+
+static struct sysrq_key_op sysrq_show_timers_op = {
+       .handler        = sysrq_handle_show_timers,
+       .help_msg       = "show-all-timers(Q)",
+       .action_msg     = "Show clockevent devices & pending hrtimers (no others)",
+};
+
+static void sysrq_handle_mountro(int key)
+{
+       emergency_remount();
+}
+static struct sysrq_key_op sysrq_mountro_op = {
+       .handler        = sysrq_handle_mountro,
+       .help_msg       = "Unmount",
+       .action_msg     = "Emergency Remount R/O",
+       .enable_mask    = SYSRQ_ENABLE_REMOUNT,
+};
+
+#ifdef CONFIG_LOCKDEP
+static void sysrq_handle_showlocks(int key)
+{
+       debug_show_all_locks();
+}
+
+static struct sysrq_key_op sysrq_showlocks_op = {
+       .handler        = sysrq_handle_showlocks,
+       .help_msg       = "show-all-locks(D)",
+       .action_msg     = "Show Locks Held",
+};
+#else
+#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(show_lock);
+
+static void showacpu(void *dummy)
+{
+       unsigned long flags;
+
+       /* Idle CPUs have no interesting backtrace. */
+       if (idle_cpu(smp_processor_id()))
+               return;
+
+       spin_lock_irqsave(&show_lock, flags);
+       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+       show_stack(NULL, NULL);
+       spin_unlock_irqrestore(&show_lock, flags);
+}
+
+static void sysrq_showregs_othercpus(struct work_struct *dummy)
+{
+       smp_call_function(showacpu, NULL, 0);
+}
+
+static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
+
+static void sysrq_handle_showallcpus(int key)
+{
+       /*
+        * Fall back to the workqueue based printing if the
+        * backtrace printing did not succeed or the
+        * architecture has no support for it:
+        */
+       if (!trigger_all_cpu_backtrace()) {
+               struct pt_regs *regs = get_irq_regs();
+
+               if (regs) {
+                       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+                       show_regs(regs);
+               }
+               schedule_work(&sysrq_showallcpus);
+       }
+}
+
+static struct sysrq_key_op sysrq_showallcpus_op = {
+       .handler        = sysrq_handle_showallcpus,
+       .help_msg       = "show-backtrace-all-active-cpus(L)",
+       .action_msg     = "Show backtrace of all active CPUs",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
+static void sysrq_handle_showregs(int key)
+{
+       struct pt_regs *regs = get_irq_regs();
+       if (regs)
+               show_regs(regs);
+       perf_event_print_debug();
+}
+static struct sysrq_key_op sysrq_showregs_op = {
+       .handler        = sysrq_handle_showregs,
+       .help_msg       = "show-registers(P)",
+       .action_msg     = "Show Regs",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_showstate(int key)
+{
+       show_state();
+}
+static struct sysrq_key_op sysrq_showstate_op = {
+       .handler        = sysrq_handle_showstate,
+       .help_msg       = "show-task-states(T)",
+       .action_msg     = "Show State",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_showstate_blocked(int key)
+{
+       show_state_filter(TASK_UNINTERRUPTIBLE);
+}
+static struct sysrq_key_op sysrq_showstate_blocked_op = {
+       .handler        = sysrq_handle_showstate_blocked,
+       .help_msg       = "show-blocked-tasks(W)",
+       .action_msg     = "Show Blocked State",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+#ifdef CONFIG_TRACING
+#include <linux/ftrace.h>
+
+static void sysrq_ftrace_dump(int key)
+{
+       ftrace_dump(DUMP_ALL);
+}
+static struct sysrq_key_op sysrq_ftrace_dump_op = {
+       .handler        = sysrq_ftrace_dump,
+       .help_msg       = "dump-ftrace-buffer(Z)",
+       .action_msg     = "Dump ftrace buffer",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#else
+#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+static void sysrq_handle_showmem(int key)
+{
+       show_mem();
+}
+static struct sysrq_key_op sysrq_showmem_op = {
+       .handler        = sysrq_handle_showmem,
+       .help_msg       = "show-memory-usage(M)",
+       .action_msg     = "Show Memory",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+/*
+ * Signal sysrq helper function.  Sends a signal to all user processes.
+ */
+static void send_sig_all(int sig)
+{
+       struct task_struct *p;
+
+       for_each_process(p) {
+               if (p->mm && !is_global_init(p))
+                       /* Not swapper, init nor kernel thread */
+                       force_sig(sig, p);
+       }
+}
+
+static void sysrq_handle_term(int key)
+{
+       send_sig_all(SIGTERM);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_term_op = {
+       .handler        = sysrq_handle_term,
+       .help_msg       = "terminate-all-tasks(E)",
+       .action_msg     = "Terminate All Tasks",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void moom_callback(struct work_struct *ignored)
+{
+       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
+}
+
+static DECLARE_WORK(moom_work, moom_callback);
+
+static void sysrq_handle_moom(int key)
+{
+       schedule_work(&moom_work);
+}
+static struct sysrq_key_op sysrq_moom_op = {
+       .handler        = sysrq_handle_moom,
+       .help_msg       = "memory-full-oom-kill(F)",
+       .action_msg     = "Manual OOM execution",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+#ifdef CONFIG_BLOCK
+static void sysrq_handle_thaw(int key)
+{
+       emergency_thaw_all();
+}
+static struct sysrq_key_op sysrq_thaw_op = {
+       .handler        = sysrq_handle_thaw,
+       .help_msg       = "thaw-filesystems(J)",
+       .action_msg     = "Emergency Thaw of all frozen filesystems",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+#endif
+
+static void sysrq_handle_kill(int key)
+{
+       send_sig_all(SIGKILL);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_kill_op = {
+       .handler        = sysrq_handle_kill,
+       .help_msg       = "kill-all-tasks(I)",
+       .action_msg     = "Kill All Tasks",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void sysrq_handle_unrt(int key)
+{
+       normalize_rt_tasks();
+}
+static struct sysrq_key_op sysrq_unrt_op = {
+       .handler        = sysrq_handle_unrt,
+       .help_msg       = "nice-all-RT-tasks(N)",
+       .action_msg     = "Nice All RT Tasks",
+       .enable_mask    = SYSRQ_ENABLE_RTNICE,
+};
+
+/* Key Operations table and lock */
+static DEFINE_SPINLOCK(sysrq_key_table_lock);
+
+static struct sysrq_key_op *sysrq_key_table[36] = {
+       &sysrq_loglevel_op,             /* 0 */
+       &sysrq_loglevel_op,             /* 1 */
+       &sysrq_loglevel_op,             /* 2 */
+       &sysrq_loglevel_op,             /* 3 */
+       &sysrq_loglevel_op,             /* 4 */
+       &sysrq_loglevel_op,             /* 5 */
+       &sysrq_loglevel_op,             /* 6 */
+       &sysrq_loglevel_op,             /* 7 */
+       &sysrq_loglevel_op,             /* 8 */
+       &sysrq_loglevel_op,             /* 9 */
+
+       /*
+        * a: Don't use for system provided sysrqs, it is handled specially on
+        * sparc and will never arrive.
+        */
+       NULL,                           /* a */
+       &sysrq_reboot_op,               /* b */
+       &sysrq_crash_op,                /* c & ibm_emac driver debug */
+       &sysrq_showlocks_op,            /* d */
+       &sysrq_term_op,                 /* e */
+       &sysrq_moom_op,                 /* f */
+       /* g: May be registered for the kernel debugger */
+       NULL,                           /* g */
+       NULL,                           /* h - reserved for help */
+       &sysrq_kill_op,                 /* i */
+#ifdef CONFIG_BLOCK
+       &sysrq_thaw_op,                 /* j */
+#else
+       NULL,                           /* j */
+#endif
+       &sysrq_SAK_op,                  /* k */
+#ifdef CONFIG_SMP
+       &sysrq_showallcpus_op,          /* l */
+#else
+       NULL,                           /* l */
+#endif
+       &sysrq_showmem_op,              /* m */
+       &sysrq_unrt_op,                 /* n */
+       /* o: This will often be registered as 'Off' at init time */
+       NULL,                           /* o */
+       &sysrq_showregs_op,             /* p */
+       &sysrq_show_timers_op,          /* q */
+       &sysrq_unraw_op,                /* r */
+       &sysrq_sync_op,                 /* s */
+       &sysrq_showstate_op,            /* t */
+       &sysrq_mountro_op,              /* u */
+       /* v: May be registered for frame buffer console restore */
+       NULL,                           /* v */
+       &sysrq_showstate_blocked_op,    /* w */
+       /* x: May be registered on ppc/powerpc for xmon */
+       NULL,                           /* x */
+       /* y: May be registered on sparc64 for global register dump */
+       NULL,                           /* y */
+       &sysrq_ftrace_dump_op,          /* z */
+};
+
+/* key2index calculation, -1 on invalid index */
+static int sysrq_key_table_key2index(int key)
+{
+       int retval;
+
+       if ((key >= '0') && (key <= '9'))
+               retval = key - '0';
+       else if ((key >= 'a') && (key <= 'z'))
+               retval = key + 10 - 'a';
+       else
+               retval = -1;
+       return retval;
+}
+
+/*
+ * get and put functions for the table, exposed to modules.
+ */
+struct sysrq_key_op *__sysrq_get_key_op(int key)
+{
+        struct sysrq_key_op *op_p = NULL;
+        int i;
+
+       i = sysrq_key_table_key2index(key);
+       if (i != -1)
+               op_p = sysrq_key_table[i];
+
+        return op_p;
+}
+
+static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
+{
+        int i = sysrq_key_table_key2index(key);
+
+        if (i != -1)
+                sysrq_key_table[i] = op_p;
+}
+
+void __handle_sysrq(int key, bool check_mask)
+{
+       struct sysrq_key_op *op_p;
+       int orig_log_level;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sysrq_key_table_lock, flags);
+       /*
+        * Raise the apparent loglevel to maximum so that the sysrq header
+        * is shown to provide the user with positive feedback.  We do not
+        * simply emit this at KERN_EMERG as that would change message
+        * routing in the consumers of /proc/kmsg.
+        */
+       orig_log_level = console_loglevel;
+       console_loglevel = 7;
+       printk(KERN_INFO "SysRq : ");
+
+        op_p = __sysrq_get_key_op(key);
+        if (op_p) {
+               /*
+                * Should we check for enabled operations (/proc/sysrq-trigger
+                * should not) and is the invoked operation enabled?
+                */
+               if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
+                       printk("%s\n", op_p->action_msg);
+                       console_loglevel = orig_log_level;
+                       op_p->handler(key);
+               } else {
+                       printk("This sysrq operation is disabled.\n");
+               }
+       } else {
+               printk("HELP : ");
+               /* Only print the help msg once per handler */
+               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
+                       if (sysrq_key_table[i]) {
+                               int j;
+
+                               for (j = 0; sysrq_key_table[i] !=
+                                               sysrq_key_table[j]; j++)
+                                       ;
+                               if (j != i)
+                                       continue;
+                               printk("%s ", sysrq_key_table[i]->help_msg);
+                       }
+               }
+               printk("\n");
+               console_loglevel = orig_log_level;
+       }
+       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+}
+
+void handle_sysrq(int key)
+{
+       if (sysrq_on())
+               __handle_sysrq(key, true);
+}
+EXPORT_SYMBOL(handle_sysrq);
+
+#ifdef CONFIG_INPUT
+
+/* Simple translation table for the SysRq keys */
+static const unsigned char sysrq_xlate[KEY_CNT] =
+        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
+        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
+        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
+        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
+        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
+        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+        "\r\000/";                                      /* 0x60 - 0x6f */
+
+struct sysrq_state {
+       struct input_handle handle;
+       struct work_struct reinject_work;
+       unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+       unsigned int alt;
+       unsigned int alt_use;
+       bool active;
+       bool need_reinject;
+};
+
+static void sysrq_reinject_alt_sysrq(struct work_struct *work)
+{
+       struct sysrq_state *sysrq =
+                       container_of(work, struct sysrq_state, reinject_work);
+       struct input_handle *handle = &sysrq->handle;
+       unsigned int alt_code = sysrq->alt_use;
+
+       if (sysrq->need_reinject) {
+               /* Simulate press and release of Alt + SysRq */
+               input_inject_event(handle, EV_KEY, alt_code, 1);
+               input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+
+               input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
+               input_inject_event(handle, EV_KEY, alt_code, 0);
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+       }
+}
+
+static bool sysrq_filter(struct input_handle *handle,
+                        unsigned int type, unsigned int code, int value)
+{
+       struct sysrq_state *sysrq = handle->private;
+       bool was_active = sysrq->active;
+       bool suppress;
+
+       switch (type) {
+
+       case EV_SYN:
+               suppress = false;
+               break;
+
+       case EV_KEY:
+               switch (code) {
+
+               case KEY_LEFTALT:
+               case KEY_RIGHTALT:
+                       if (!value) {
+                               /* One of ALTs is being released */
+                               if (sysrq->active && code == sysrq->alt_use)
+                                       sysrq->active = false;
+
+                               sysrq->alt = KEY_RESERVED;
+
+                       } else if (value != 2) {
+                               sysrq->alt = code;
+                               sysrq->need_reinject = false;
+                       }
+                       break;
+
+               case KEY_SYSRQ:
+                       if (value == 1 && sysrq->alt != KEY_RESERVED) {
+                               sysrq->active = true;
+                               sysrq->alt_use = sysrq->alt;
+                               /*
+                                * If nothing else will be pressed we'll need
+                                * to * re-inject Alt-SysRq keysroke.
+                                */
+                               sysrq->need_reinject = true;
+                       }
+
+                       /*
+                        * Pretend that sysrq was never pressed at all. This
+                        * is needed to properly handle KGDB which will try
+                        * to release all keys after exiting debugger. If we
+                        * do not clear key bit it KGDB will end up sending
+                        * release events for Alt and SysRq, potentially
+                        * triggering print screen function.
+                        */
+                       if (sysrq->active)
+                               clear_bit(KEY_SYSRQ, handle->dev->key);
+
+                       break;
+
+               default:
+                       if (sysrq->active && value && value != 2) {
+                               sysrq->need_reinject = false;
+                               __handle_sysrq(sysrq_xlate[code], true);
+                       }
+                       break;
+               }
+
+               suppress = sysrq->active;
+
+               if (!sysrq->active) {
+                       /*
+                        * If we are not suppressing key presses keep track of
+                        * keyboard state so we can release keys that have been
+                        * pressed before entering SysRq mode.
+                        */
+                       if (value)
+                               set_bit(code, sysrq->key_down);
+                       else
+                               clear_bit(code, sysrq->key_down);
+
+                       if (was_active)
+                               schedule_work(&sysrq->reinject_work);
+
+               } else if (value == 0 &&
+                          test_and_clear_bit(code, sysrq->key_down)) {
+                       /*
+                        * Pass on release events for keys that was pressed before
+                        * entering SysRq mode.
+                        */
+                       suppress = false;
+               }
+               break;
+
+       default:
+               suppress = sysrq->active;
+               break;
+       }
+
+       return suppress;
+}
+
+static int sysrq_connect(struct input_handler *handler,
+                        struct input_dev *dev,
+                        const struct input_device_id *id)
+{
+       struct sysrq_state *sysrq;
+       int error;
+
+       sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL);
+       if (!sysrq)
+               return -ENOMEM;
+
+       INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq);
+
+       sysrq->handle.dev = dev;
+       sysrq->handle.handler = handler;
+       sysrq->handle.name = "sysrq";
+       sysrq->handle.private = sysrq;
+
+       error = input_register_handle(&sysrq->handle);
+       if (error) {
+               pr_err("Failed to register input sysrq handler, error %d\n",
+                       error);
+               goto err_free;
+       }
+
+       error = input_open_device(&sysrq->handle);
+       if (error) {
+               pr_err("Failed to open input device, error %d\n", error);
+               goto err_unregister;
+       }
+
+       return 0;
+
+ err_unregister:
+       input_unregister_handle(&sysrq->handle);
+ err_free:
+       kfree(sysrq);
+       return error;
+}
+
+static void sysrq_disconnect(struct input_handle *handle)
+{
+       struct sysrq_state *sysrq = handle->private;
+
+       input_close_device(handle);
+       cancel_work_sync(&sysrq->reinject_work);
+       input_unregister_handle(handle);
+       kfree(sysrq);
+}
+
+/*
+ * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
+ * keyboards have SysRq key predefined and so user may add it to keymap
+ * later, but we expect all such keyboards to have left alt.
+ */
+static const struct input_device_id sysrq_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+                               INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { BIT_MASK(KEY_LEFTALT) },
+       },
+       { },
+};
+
+static struct input_handler sysrq_handler = {
+       .filter         = sysrq_filter,
+       .connect        = sysrq_connect,
+       .disconnect     = sysrq_disconnect,
+       .name           = "sysrq",
+       .id_table       = sysrq_ids,
+};
+
+static bool sysrq_handler_registered;
+
+static inline void sysrq_register_handler(void)
+{
+       int error;
+
+       error = input_register_handler(&sysrq_handler);
+       if (error)
+               pr_err("Failed to register input handler, error %d", error);
+       else
+               sysrq_handler_registered = true;
+}
+
+static inline void sysrq_unregister_handler(void)
+{
+       if (sysrq_handler_registered) {
+               input_unregister_handler(&sysrq_handler);
+               sysrq_handler_registered = false;
+       }
+}
+
+#else
+
+static inline void sysrq_register_handler(void)
+{
+}
+
+static inline void sysrq_unregister_handler(void)
+{
+}
+
+#endif /* CONFIG_INPUT */
+
+int sysrq_toggle_support(int enable_mask)
+{
+       bool was_enabled = sysrq_on();
+
+       sysrq_enabled = enable_mask;
+
+       if (was_enabled != sysrq_on()) {
+               if (sysrq_on())
+                       sysrq_register_handler();
+               else
+                       sysrq_unregister_handler();
+       }
+
+       return 0;
+}
+
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+                                struct sysrq_key_op *remove_op_p)
+{
+       int retval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sysrq_key_table_lock, flags);
+       if (__sysrq_get_key_op(key) == remove_op_p) {
+               __sysrq_put_key_op(key, insert_op_p);
+               retval = 0;
+       } else {
+               retval = -1;
+       }
+       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+       return retval;
+}
+
+int register_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, op_p, NULL);
+}
+EXPORT_SYMBOL(register_sysrq_key);
+
+int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, NULL, op_p);
+}
+EXPORT_SYMBOL(unregister_sysrq_key);
+
+#ifdef CONFIG_PROC_FS
+/*
+ * writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ */
+static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       if (count) {
+               char c;
+
+               if (get_user(c, buf))
+                       return -EFAULT;
+               __handle_sysrq(c, false);
+       }
+
+       return count;
+}
+
+static const struct file_operations proc_sysrq_trigger_operations = {
+       .write          = write_sysrq_trigger,
+       .llseek         = noop_llseek,
+};
+
+static void sysrq_init_procfs(void)
+{
+       if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
+                        &proc_sysrq_trigger_operations))
+               pr_err("Failed to register proc interface\n");
+}
+
+#else
+
+static inline void sysrq_init_procfs(void)
+{
+}
+
+#endif /* CONFIG_PROC_FS */
+
+static int __init sysrq_init(void)
+{
+       sysrq_init_procfs();
+
+       if (sysrq_on())
+               sysrq_register_handler();
+
+       return 0;
+}
+module_init(sysrq_init);
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
new file mode 100644 (file)
index 0000000..f64582b
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Creating audit events from TTY input.
+ *
+ * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
+ * material is made available to anyone wishing to use, modify, copy, or
+ * redistribute it subject to the terms and conditions of the GNU General
+ * Public License v.2.
+ *
+ * Authors: Miloslav Trmac <mitr@redhat.com>
+ */
+
+#include <linux/audit.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+
+struct tty_audit_buf {
+       atomic_t count;
+       struct mutex mutex;     /* Protects all data below */
+       int major, minor;       /* The TTY which the data is from */
+       unsigned icanon:1;
+       size_t valid;
+       unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
+};
+
+static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
+                                                int icanon)
+{
+       struct tty_audit_buf *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               goto err;
+       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+       if (!buf->data)
+               goto err_buf;
+       atomic_set(&buf->count, 1);
+       mutex_init(&buf->mutex);
+       buf->major = major;
+       buf->minor = minor;
+       buf->icanon = icanon;
+       buf->valid = 0;
+       return buf;
+
+err_buf:
+       kfree(buf);
+err:
+       return NULL;
+}
+
+static void tty_audit_buf_free(struct tty_audit_buf *buf)
+{
+       WARN_ON(buf->valid != 0);
+       kfree(buf->data);
+       kfree(buf);
+}
+
+static void tty_audit_buf_put(struct tty_audit_buf *buf)
+{
+       if (atomic_dec_and_test(&buf->count))
+               tty_audit_buf_free(buf);
+}
+
+static void tty_audit_log(const char *description, struct task_struct *tsk,
+                         uid_t loginuid, unsigned sessionid, int major,
+                         int minor, unsigned char *data, size_t size)
+{
+       struct audit_buffer *ab;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
+       if (ab) {
+               char name[sizeof(tsk->comm)];
+               uid_t uid = task_uid(tsk);
+
+               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
+                                "major=%d minor=%d comm=", description,
+                                tsk->pid, uid, loginuid, sessionid,
+                                major, minor);
+               get_task_comm(name, tsk);
+               audit_log_untrustedstring(ab, name);
+               audit_log_format(ab, " data=");
+               audit_log_n_hex(ab, data, size);
+               audit_log_end(ab);
+       }
+}
+
+/**
+ *     tty_audit_buf_push      -       Push buffered data out
+ *
+ *     Generate an audit message from the contents of @buf, which is owned by
+ *     @tsk with @loginuid.  @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+                              unsigned int sessionid,
+                              struct tty_audit_buf *buf)
+{
+       if (buf->valid == 0)
+               return;
+       if (audit_enabled == 0)
+               return;
+       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
+                     buf->data, buf->valid);
+       buf->valid = 0;
+}
+
+/**
+ *     tty_audit_buf_push_current      -       Push buffered data out
+ *
+ *     Generate an audit message from the contents of @buf, which is owned by
+ *     the current task.  @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
+{
+       uid_t auid = audit_get_loginuid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
+       tty_audit_buf_push(current, auid, sessionid, buf);
+}
+
+/**
+ *     tty_audit_exit  -       Handle a task exit
+ *
+ *     Make sure all buffered data is written out and deallocate the buffer.
+ *     Only needs to be called if current->signal->tty_audit_buf != %NULL.
+ */
+void tty_audit_exit(void)
+{
+       struct tty_audit_buf *buf;
+
+       spin_lock_irq(&current->sighand->siglock);
+       buf = current->signal->tty_audit_buf;
+       current->signal->tty_audit_buf = NULL;
+       spin_unlock_irq(&current->sighand->siglock);
+       if (!buf)
+               return;
+
+       mutex_lock(&buf->mutex);
+       tty_audit_buf_push_current(buf);
+       mutex_unlock(&buf->mutex);
+
+       tty_audit_buf_put(buf);
+}
+
+/**
+ *     tty_audit_fork  -       Copy TTY audit state for a new task
+ *
+ *     Set up TTY audit state in @sig from current.  @sig needs no locking.
+ */
+void tty_audit_fork(struct signal_struct *sig)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       sig->audit_tty = current->signal->audit_tty;
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+/**
+ *     tty_audit_tiocsti       -       Log TIOCSTI
+ */
+void tty_audit_tiocsti(struct tty_struct *tty, char ch)
+{
+       struct tty_audit_buf *buf;
+       int major, minor, should_audit;
+
+       spin_lock_irq(&current->sighand->siglock);
+       should_audit = current->signal->audit_tty;
+       buf = current->signal->tty_audit_buf;
+       if (buf)
+               atomic_inc(&buf->count);
+       spin_unlock_irq(&current->sighand->siglock);
+
+       major = tty->driver->major;
+       minor = tty->driver->minor_start + tty->index;
+       if (buf) {
+               mutex_lock(&buf->mutex);
+               if (buf->major == major && buf->minor == minor)
+                       tty_audit_buf_push_current(buf);
+               mutex_unlock(&buf->mutex);
+               tty_audit_buf_put(buf);
+       }
+
+       if (should_audit && audit_enabled) {
+               uid_t auid;
+               unsigned int sessionid;
+
+               auid = audit_get_loginuid(current);
+               sessionid = audit_get_sessionid(current);
+               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
+                             minor, &ch, 1);
+       }
+}
+
+/**
+ * tty_audit_push_task -       Flush task's pending audit data
+ * @tsk:               task pointer
+ * @loginuid:          sender login uid
+ * @sessionid:         sender session id
+ *
+ * Called with a ref on @tsk held. Try to lock sighand and get a
+ * reference to the tty audit buffer if available.
+ * Flush the buffer or return an appropriate error code.
+ */
+int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+{
+       struct tty_audit_buf *buf = ERR_PTR(-EPERM);
+       unsigned long flags;
+
+       if (!lock_task_sighand(tsk, &flags))
+               return -ESRCH;
+
+       if (tsk->signal->audit_tty) {
+               buf = tsk->signal->tty_audit_buf;
+               if (buf)
+                       atomic_inc(&buf->count);
+       }
+       unlock_task_sighand(tsk, &flags);
+
+       /*
+        * Return 0 when signal->audit_tty set
+        * but tsk->signal->tty_audit_buf == NULL.
+        */
+       if (!buf || IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       mutex_lock(&buf->mutex);
+       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
+       mutex_unlock(&buf->mutex);
+
+       tty_audit_buf_put(buf);
+       return 0;
+}
+
+/**
+ *     tty_audit_buf_get       -       Get an audit buffer.
+ *
+ *     Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
+ *     if TTY auditing is disabled or out of memory.  Otherwise, return a new
+ *     reference to the buffer.
+ */
+static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
+{
+       struct tty_audit_buf *buf, *buf2;
+
+       buf = NULL;
+       buf2 = NULL;
+       spin_lock_irq(&current->sighand->siglock);
+       if (likely(!current->signal->audit_tty))
+               goto out;
+       buf = current->signal->tty_audit_buf;
+       if (buf) {
+               atomic_inc(&buf->count);
+               goto out;
+       }
+       spin_unlock_irq(&current->sighand->siglock);
+
+       buf2 = tty_audit_buf_alloc(tty->driver->major,
+                                  tty->driver->minor_start + tty->index,
+                                  tty->icanon);
+       if (buf2 == NULL) {
+               audit_log_lost("out of memory in TTY auditing");
+               return NULL;
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (!current->signal->audit_tty)
+               goto out;
+       buf = current->signal->tty_audit_buf;
+       if (!buf) {
+               current->signal->tty_audit_buf = buf2;
+               buf = buf2;
+               buf2 = NULL;
+       }
+       atomic_inc(&buf->count);
+       /* Fall through */
+ out:
+       spin_unlock_irq(&current->sighand->siglock);
+       if (buf2)
+               tty_audit_buf_free(buf2);
+       return buf;
+}
+
+/**
+ *     tty_audit_add_data      -       Add data for TTY auditing.
+ *
+ *     Audit @data of @size from @tty, if necessary.
+ */
+void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+                       size_t size)
+{
+       struct tty_audit_buf *buf;
+       int major, minor;
+
+       if (unlikely(size == 0))
+               return;
+
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY
+           && tty->driver->subtype == PTY_TYPE_MASTER)
+               return;
+
+       buf = tty_audit_buf_get(tty);
+       if (!buf)
+               return;
+
+       mutex_lock(&buf->mutex);
+       major = tty->driver->major;
+       minor = tty->driver->minor_start + tty->index;
+       if (buf->major != major || buf->minor != minor
+           || buf->icanon != tty->icanon) {
+               tty_audit_buf_push_current(buf);
+               buf->major = major;
+               buf->minor = minor;
+               buf->icanon = tty->icanon;
+       }
+       do {
+               size_t run;
+
+               run = N_TTY_BUF_SIZE - buf->valid;
+               if (run > size)
+                       run = size;
+               memcpy(buf->data + buf->valid, data, run);
+               buf->valid += run;
+               data += run;
+               size -= run;
+               if (buf->valid == N_TTY_BUF_SIZE)
+                       tty_audit_buf_push_current(buf);
+       } while (size != 0);
+       mutex_unlock(&buf->mutex);
+       tty_audit_buf_put(buf);
+}
+
+/**
+ *     tty_audit_push  -       Push buffered data out
+ *
+ *     Make sure no audit data is pending for @tty on the current process.
+ */
+void tty_audit_push(struct tty_struct *tty)
+{
+       struct tty_audit_buf *buf;
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (likely(!current->signal->audit_tty)) {
+               spin_unlock_irq(&current->sighand->siglock);
+               return;
+       }
+       buf = current->signal->tty_audit_buf;
+       if (buf)
+               atomic_inc(&buf->count);
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (buf) {
+               int major, minor;
+
+               major = tty->driver->major;
+               minor = tty->driver->minor_start + tty->index;
+               mutex_lock(&buf->mutex);
+               if (buf->major == major && buf->minor == minor)
+                       tty_audit_buf_push_current(buf);
+               mutex_unlock(&buf->mutex);
+               tty_audit_buf_put(buf);
+       }
+}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
new file mode 100644 (file)
index 0000000..d8210ca
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ *     tty_buffer_free_all             -       free buffers used by a tty
+ *     @tty: tty to free from
+ *
+ *     Remove all the buffers pending on a tty whether queued with data
+ *     or in the free ring. Must be called when the tty is no longer in use
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               kfree(thead);
+       }
+       while ((thead = tty->buf.free) != NULL) {
+               tty->buf.free = thead->next;
+               kfree(thead);
+       }
+       tty->buf.tail = NULL;
+       tty->buf.memory_used = 0;
+}
+
+/**
+ *     tty_buffer_alloc        -       allocate a tty buffer
+ *     @tty: tty device
+ *     @size: desired size (characters)
+ *
+ *     Allocate a new tty buffer to hold the desired number of characters.
+ *     Return NULL if out of memory or the allocation would exceed the
+ *     per device queue
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *p;
+
+       if (tty->buf.memory_used + size > 65536)
+               return NULL;
+       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+       if (p == NULL)
+               return NULL;
+       p->used = 0;
+       p->size = size;
+       p->next = NULL;
+       p->commit = 0;
+       p->read = 0;
+       p->char_buf_ptr = (char *)(p->data);
+       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+       tty->buf.memory_used += size;
+       return p;
+}
+
+/**
+ *     tty_buffer_free         -       free a tty buffer
+ *     @tty: tty owning the buffer
+ *     @b: the buffer to free
+ *
+ *     Free a tty buffer, or add it to the free list according to our
+ *     internal strategy
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+       /* Dumb strategy for now - should keep some stats */
+       tty->buf.memory_used -= b->size;
+       WARN_ON(tty->buf.memory_used < 0);
+
+       if (b->size >= 512)
+               kfree(b);
+       else {
+               b->next = tty->buf.free;
+               tty->buf.free = b;
+       }
+}
+
+/**
+ *     __tty_buffer_flush              -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. Caller must
+ *     hold the buffer lock and must have ensured no parallel flush to
+ *     ldisc is running.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               tty_buffer_free(tty, thead);
+       }
+       tty->buf.tail = NULL;
+}
+
+/**
+ *     tty_buffer_flush                -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. If the buffer is
+ *     being processed by flush_to_ldisc then we defer the processing
+ *     to that function
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* If the data is being pushed to the tty layer then we can't
+          process it here. Instead set a flag and the flush_to_ldisc
+          path will process the flush request before it exits */
+       if (test_bit(TTY_FLUSHING, &tty->flags)) {
+               set_bit(TTY_FLUSHPENDING, &tty->flags);
+               spin_unlock_irqrestore(&tty->buf.lock, flags);
+               wait_event(tty->read_wait,
+                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+               return;
+       } else
+               __tty_buffer_flush(tty);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ *     tty_buffer_find         -       find a free tty buffer
+ *     @tty: tty owning the buffer
+ *     @size: characters wanted
+ *
+ *     Locate an existing suitable tty buffer or if we are lacking one then
+ *     allocate a new one. We round our buffers off in 256 character chunks
+ *     to get better allocation behaviour.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer **tbh = &tty->buf.free;
+       while ((*tbh) != NULL) {
+               struct tty_buffer *t = *tbh;
+               if (t->size >= size) {
+                       *tbh = t->next;
+                       t->next = NULL;
+                       t->used = 0;
+                       t->commit = 0;
+                       t->read = 0;
+                       tty->buf.memory_used += t->size;
+                       return t;
+               }
+               tbh = &((*tbh)->next);
+       }
+       /* Round the buffer size out */
+       size = (size + 0xFF) & ~0xFF;
+       return tty_buffer_alloc(tty, size);
+       /* Should possibly check if this fails for the largest buffer we
+          have queued and recycle that ? */
+}
+
+/**
+ *     tty_buffer_request_room         -       grow tty buffer if needed
+ *     @tty: tty structure
+ *     @size: size desired
+ *
+ *     Make at least size bytes of linear space available for the tty
+ *     buffer. If we fail return the size we managed to find.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *b, *n;
+       int left;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
+          remove this conditional if its worth it. This would be invisible
+          to the callers */
+       if ((b = tty->buf.tail) != NULL)
+               left = b->size - b->used;
+       else
+               left = 0;
+
+       if (left < size) {
+               /* This is the slow path - looking for new buffers to use */
+               if ((n = tty_buffer_find(tty, size)) != NULL) {
+                       if (b != NULL) {
+                               b->next = n;
+                               b->commit = b->used;
+                       } else
+                               tty->buf.head = n;
+                       tty->buf.tail = n;
+               } else
+                       size = left;
+       }
+
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ *     tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flag: flag value for each character
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. All the characters
+ *     passed are marked with the supplied flag. Returns the number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
+               const unsigned char *chars, char flag, size_t size)
+{
+       int copied = 0;
+       do {
+               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memset(tb->flag_buf_ptr + tb->used, flag, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
+
+/**
+ *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flags: flag bytes
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. For each character
+ *     the flags array indicates the status of the character. Returns the
+ *     number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+               const unsigned char *chars, const char *flags, size_t size)
+{
+       int copied = 0;
+       do {
+               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               flags += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ *     tty_schedule_flip       -       push characters to ldisc
+ *     @tty: tty to push from
+ *
+ *     Takes any pending buffers and transfers their ownership to the
+ *     ldisc side of the queue. It then schedules those characters for
+ *     processing by the line discipline.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+
+void tty_schedule_flip(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ *     tty_prepare_flip_string         -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for normal characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+                                                               size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ *     tty_prepare_flip_string_flags   -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @flags: return pointer for status flag write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+                       unsigned char **chars, char **flags, size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               *flags = tb->flag_buf_ptr + tb->used;
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ *     flush_to_ldisc
+ *     @work: tty structure passed from work queue.
+ *
+ *     This routine is called out of the software interrupt to flush data
+ *     from the buffer chain to the line discipline.
+ *
+ *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ *     while invoking the line discipline receive_buf method. The
+ *     receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, buf.work.work);
+       unsigned long   flags;
+       struct tty_ldisc *disc;
+
+       disc = tty_ldisc_ref(tty);
+       if (disc == NULL)       /*  !TTY_LDISC */
+               return;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+               struct tty_buffer *head, *tail = tty->buf.tail;
+               int seen_tail = 0;
+               while ((head = tty->buf.head) != NULL) {
+                       int count;
+                       char *char_buf;
+                       unsigned char *flag_buf;
+
+                       count = head->commit - head->read;
+                       if (!count) {
+                               if (head->next == NULL)
+                                       break;
+                               /*
+                                 There's a possibility tty might get new buffer
+                                 added during the unlock window below. We could
+                                 end up spinning in here forever hogging the CPU
+                                 completely. To avoid this let's have a rest each
+                                 time we processed the tail buffer.
+                               */
+                               if (tail == head)
+                                       seen_tail = 1;
+                               tty->buf.head = head->next;
+                               tty_buffer_free(tty, head);
+                               continue;
+                       }
+                       /* Ldisc or user is trying to flush the buffers
+                          we are feeding to the ldisc, stop feeding the
+                          line discipline as we want to empty the queue */
+                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+                               break;
+                       if (!tty->receive_room || seen_tail) {
+                               schedule_delayed_work(&tty->buf.work, 1);
+                               break;
+                       }
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
+                       char_buf = head->char_buf_ptr + head->read;
+                       flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
+                       spin_unlock_irqrestore(&tty->buf.lock, flags);
+                       disc->ops->receive_buf(tty, char_buf,
+                                                       flag_buf, count);
+                       spin_lock_irqsave(&tty->buf.lock, flags);
+               }
+               clear_bit(TTY_FLUSHING, &tty->flags);
+       }
+
+       /* We may have a deferred request to flush the input buffer,
+          if so pull the chain under the lock and empty the queue */
+       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+               __tty_buffer_flush(tty);
+               clear_bit(TTY_FLUSHPENDING, &tty->flags);
+               wake_up(&tty->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       tty_ldisc_deref(disc);
+}
+
+/**
+ *     tty_flush_to_ldisc
+ *     @tty: tty to push
+ *
+ *     Push the terminal flip buffers to the line discipline.
+ *
+ *     Must not be called from IRQ context.
+ */
+void tty_flush_to_ldisc(struct tty_struct *tty)
+{
+       flush_delayed_work(&tty->buf.work);
+}
+
+/**
+ *     tty_flip_buffer_push    -       terminal
+ *     @tty: tty to push
+ *
+ *     Queue a push of the terminal flip buffers to the line discipline. This
+ *     function must not be called from IRQ context if tty->low_latency is set.
+ *
+ *     In the event of the queue being busy for flipping the work will be
+ *     held off and retried later.
+ *
+ *     Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       if (tty->low_latency)
+               flush_to_ldisc(&tty->buf.work.work);
+       else
+               schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ *     tty_buffer_init         -       prepare a tty buffer structure
+ *     @tty: tty to initialise
+ *
+ *     Set up the initial state of the buffer management for a tty device.
+ *     Must be called before the other tty buffer functions are used.
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+       spin_lock_init(&tty->buf.lock);
+       tty->buf.head = NULL;
+       tty->buf.tail = NULL;
+       tty->buf.free = NULL;
+       tty->buf.memory_used = 0;
+       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
new file mode 100644 (file)
index 0000000..c05c5af
--- /dev/null
@@ -0,0 +1,3263 @@
+/*
+ *  linux/drivers/char/tty_io.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
+ * or rs-channels. It also implements echoing, cooked mode etc.
+ *
+ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
+ *
+ * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
+ * tty_struct and tty_queue structures.  Previously there was an array
+ * of 256 tty_struct's which was statically allocated, and the
+ * tty_queue structures were allocated at boot time.  Both are now
+ * dynamically allocated only when the tty is open.
+ *
+ * Also restructured routines so that there is more of a separation
+ * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
+ * the low-level tty routines (serial.c, pty.c, console.c).  This
+ * makes for cleaner and more compact code.  -TYT, 9/17/92
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ *
+ * NOTE: pay no attention to the line discipline code (yet); its
+ * interface is still subject to change in this version...
+ * -- TYT, 1/31/92
+ *
+ * Added functionality to the OPOST tty handling.  No delays, but all
+ * other bits should be there.
+ *     -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
+ *
+ * Rewrote canonical mode and added more termios flags.
+ *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ *
+ * Reorganized FASYNC support so mouse code can share it.
+ *     -- ctm@ardi.com, 9Sep95
+ *
+ * New TIOCLINUX variants added.
+ *     -- mj@k332.feld.cvut.cz, 19-Nov-95
+ *
+ * Restrict vt switching via ioctl()
+ *      -- grif@cs.ucr.edu, 5-Dec-95
+ *
+ * Move console and virtual terminal code to more appropriate files,
+ * implement CONFIG_VT and generalize console device interface.
+ *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
+ *
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
+ *     -- Bill Hawes <whawes@star.net>, June 97
+ *
+ * Added devfs support.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
+ *
+ * Added support for a Unix98-style ptmx device.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ * Reduced memory usage for older ARM systems
+ *      -- Russell King <rmk@arm.linux.org.uk>
+ *
+ * Move do_SAK() into process context.  Less stack use in devfs functions.
+ * alloc_tty_struct() always uses kmalloc()
+ *                      -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+#undef TTY_DEBUG_HANGUP
+
+#define TTY_PARANOIA_CHECK 1
+#define CHECK_TTY_COUNT 1
+
+struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
+       .c_iflag = ICRNL | IXON,
+       .c_oflag = OPOST | ONLCR,
+       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+       .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
+                  ECHOCTL | ECHOKE | IEXTEN,
+       .c_cc = INIT_C_CC,
+       .c_ispeed = 38400,
+       .c_ospeed = 38400
+};
+
+EXPORT_SYMBOL(tty_std_termios);
+
+/* This list gets poked at by procfs and various bits of boot up code. This
+   could do with some rationalisation such as pulling the tty proc function
+   into this file */
+
+LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
+
+/* Mutex to protect creating and releasing a tty. This is shared with
+   vt.c for deeply disgusting hack reasons */
+DEFINE_MUTEX(tty_mutex);
+EXPORT_SYMBOL(tty_mutex);
+
+/* Spinlock to protect the tty->tty_files list */
+DEFINE_SPINLOCK(tty_files_lock);
+
+static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
+ssize_t redirected_tty_write(struct file *, const char __user *,
+                                                       size_t, loff_t *);
+static unsigned int tty_poll(struct file *, poll_table *);
+static int tty_open(struct inode *, struct file *);
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
+static int __tty_fasync(int fd, struct file *filp, int on);
+static int tty_fasync(int fd, struct file *filp, int on);
+static void release_tty(struct tty_struct *tty, int idx);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+
+/**
+ *     alloc_tty_struct        -       allocate a tty object
+ *
+ *     Return a new empty tty structure. The data fields have not
+ *     been initialized in any way but has been zeroed
+ *
+ *     Locking: none
+ */
+
+struct tty_struct *alloc_tty_struct(void)
+{
+       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
+}
+
+/**
+ *     free_tty_struct         -       free a disused tty
+ *     @tty: tty struct to free
+ *
+ *     Free the write buffers, tty queue and tty memory itself.
+ *
+ *     Locking: none. Must be called after tty is definitely unused
+ */
+
+void free_tty_struct(struct tty_struct *tty)
+{
+       if (tty->dev)
+               put_device(tty->dev);
+       kfree(tty->write_buf);
+       tty_buffer_free_all(tty);
+       kfree(tty);
+}
+
+static inline struct tty_struct *file_tty(struct file *file)
+{
+       return ((struct tty_file_private *)file->private_data)->tty;
+}
+
+/* Associate a new file with the tty structure */
+int tty_add_file(struct tty_struct *tty, struct file *file)
+{
+       struct tty_file_private *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->tty = tty;
+       priv->file = file;
+       file->private_data = priv;
+
+       spin_lock(&tty_files_lock);
+       list_add(&priv->list, &tty->tty_files);
+       spin_unlock(&tty_files_lock);
+
+       return 0;
+}
+
+/* Delete file from its tty */
+void tty_del_file(struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
+       spin_lock(&tty_files_lock);
+       list_del(&priv->list);
+       spin_unlock(&tty_files_lock);
+       file->private_data = NULL;
+       kfree(priv);
+}
+
+
+#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
+
+/**
+ *     tty_name        -       return tty naming
+ *     @tty: tty structure
+ *     @buf: buffer for output
+ *
+ *     Convert a tty structure into a name. The name reflects the kernel
+ *     naming policy and if udev is in use may not reflect user space
+ *
+ *     Locking: none
+ */
+
+char *tty_name(struct tty_struct *tty, char *buf)
+{
+       if (!tty) /* Hmm.  NULL pointer.  That's fun. */
+               strcpy(buf, "NULL tty");
+       else
+               strcpy(buf, tty->name);
+       return buf;
+}
+
+EXPORT_SYMBOL(tty_name);
+
+int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
+                             const char *routine)
+{
+#ifdef TTY_PARANOIA_CHECK
+       if (!tty) {
+               printk(KERN_WARNING
+                       "null TTY for (%d:%d) in %s\n",
+                       imajor(inode), iminor(inode), routine);
+               return 1;
+       }
+       if (tty->magic != TTY_MAGIC) {
+               printk(KERN_WARNING
+                       "bad magic number for tty struct (%d:%d) in %s\n",
+                       imajor(inode), iminor(inode), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+static int check_tty_count(struct tty_struct *tty, const char *routine)
+{
+#ifdef CHECK_TTY_COUNT
+       struct list_head *p;
+       int count = 0;
+
+       spin_lock(&tty_files_lock);
+       list_for_each(p, &tty->tty_files) {
+               count++;
+       }
+       spin_unlock(&tty_files_lock);
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_SLAVE &&
+           tty->link && tty->link->count)
+               count++;
+       if (tty->count != count) {
+               printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
+                                   "!= #fd's(%d) in %s\n",
+                      tty->name, tty->count, count, routine);
+               return count;
+       }
+#endif
+       return 0;
+}
+
+/**
+ *     get_tty_driver          -       find device of a tty
+ *     @dev_t: device identifier
+ *     @index: returns the index of the tty
+ *
+ *     This routine returns a tty driver structure, given a device number
+ *     and also passes back the index number.
+ *
+ *     Locking: caller must hold tty_mutex
+ */
+
+static struct tty_driver *get_tty_driver(dev_t device, int *index)
+{
+       struct tty_driver *p;
+
+       list_for_each_entry(p, &tty_drivers, tty_drivers) {
+               dev_t base = MKDEV(p->major, p->minor_start);
+               if (device < base || device >= base + p->num)
+                       continue;
+               *index = device - base;
+               return tty_driver_kref_get(p);
+       }
+       return NULL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+/**
+ *     tty_find_polling_driver -       find device of a polled tty
+ *     @name: name string to match
+ *     @line: pointer to resulting tty line nr
+ *
+ *     This routine returns a tty driver structure, given a name
+ *     and the condition that the tty driver is capable of polled
+ *     operation.
+ */
+struct tty_driver *tty_find_polling_driver(char *name, int *line)
+{
+       struct tty_driver *p, *res = NULL;
+       int tty_line = 0;
+       int len;
+       char *str, *stp;
+
+       for (str = name; *str; str++)
+               if ((*str >= '0' && *str <= '9') || *str == ',')
+                       break;
+       if (!*str)
+               return NULL;
+
+       len = str - name;
+       tty_line = simple_strtoul(str, &str, 10);
+
+       mutex_lock(&tty_mutex);
+       /* Search through the tty devices to look for a match */
+       list_for_each_entry(p, &tty_drivers, tty_drivers) {
+               if (strncmp(name, p->name, len) != 0)
+                       continue;
+               stp = str;
+               if (*stp == ',')
+                       stp++;
+               if (*stp == '\0')
+                       stp = NULL;
+
+               if (tty_line >= 0 && tty_line < p->num && p->ops &&
+                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
+                       res = tty_driver_kref_get(p);
+                       *line = tty_line;
+                       break;
+               }
+       }
+       mutex_unlock(&tty_mutex);
+
+       return res;
+}
+EXPORT_SYMBOL_GPL(tty_find_polling_driver);
+#endif
+
+/**
+ *     tty_check_change        -       check for POSIX terminal changes
+ *     @tty: tty to check
+ *
+ *     If we try to write to, or set the state of, a terminal and we're
+ *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
+ *     ignored, go ahead and perform the operation.  (POSIX 7.2)
+ *
+ *     Locking: ctrl_lock
+ */
+
+int tty_check_change(struct tty_struct *tty)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (current->signal->tty != tty)
+               return 0;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+
+       if (!tty->pgrp) {
+               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
+               goto out_unlock;
+       }
+       if (task_pgrp(current) == tty->pgrp)
+               goto out_unlock;
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (is_ignored(SIGTTOU))
+               goto out;
+       if (is_current_pgrp_orphaned()) {
+               ret = -EIO;
+               goto out;
+       }
+       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
+       set_thread_flag(TIF_SIGPENDING);
+       ret = -ERESTARTSYS;
+out:
+       return ret;
+out_unlock:
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       return ret;
+}
+
+EXPORT_SYMBOL(tty_check_change);
+
+static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+
+static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       return -EIO;
+}
+
+/* No kernel lock held - none needed ;) */
+static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
+{
+       return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
+}
+
+static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
+               unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static long hung_up_tty_compat_ioctl(struct file *file,
+                                    unsigned int cmd, unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static const struct file_operations tty_fops = {
+       .llseek         = no_llseek,
+       .read           = tty_read,
+       .write          = tty_write,
+       .poll           = tty_poll,
+       .unlocked_ioctl = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
+       .open           = tty_open,
+       .release        = tty_release,
+       .fasync         = tty_fasync,
+};
+
+static const struct file_operations console_fops = {
+       .llseek         = no_llseek,
+       .read           = tty_read,
+       .write          = redirected_tty_write,
+       .poll           = tty_poll,
+       .unlocked_ioctl = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
+       .open           = tty_open,
+       .release        = tty_release,
+       .fasync         = tty_fasync,
+};
+
+static const struct file_operations hung_up_tty_fops = {
+       .llseek         = no_llseek,
+       .read           = hung_up_tty_read,
+       .write          = hung_up_tty_write,
+       .poll           = hung_up_tty_poll,
+       .unlocked_ioctl = hung_up_tty_ioctl,
+       .compat_ioctl   = hung_up_tty_compat_ioctl,
+       .release        = tty_release,
+};
+
+static DEFINE_SPINLOCK(redirect_lock);
+static struct file *redirect;
+
+/**
+ *     tty_wakeup      -       request more data
+ *     @tty: terminal
+ *
+ *     Internal and external helper for wakeups of tty. This function
+ *     informs the line discipline if present that the driver is ready
+ *     to receive more output data.
+ */
+
+void tty_wakeup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
+               ld = tty_ldisc_ref(tty);
+               if (ld) {
+                       if (ld->ops->write_wakeup)
+                               ld->ops->write_wakeup(tty);
+                       tty_ldisc_deref(ld);
+               }
+       }
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+EXPORT_SYMBOL_GPL(tty_wakeup);
+
+/**
+ *     __tty_hangup            -       actual handler for hangup events
+ *     @work: tty device
+ *
+ *     This can be called by the "eventd" kernel thread.  That is process
+ *     synchronous but doesn't hold any locks, so we need to make sure we
+ *     have the appropriate locks for what we're doing.
+ *
+ *     The hangup event clears any pending redirections onto the hung up
+ *     device. It ensures future writes will error and it does the needed
+ *     line discipline hangup and signal delivery. The tty object itself
+ *     remains intact.
+ *
+ *     Locking:
+ *             BTM
+ *               redirect lock for undoing redirection
+ *               file list lock for manipulating list of ttys
+ *               tty_ldisc_lock from called functions
+ *               termios_mutex resetting termios data
+ *               tasklist_lock to walk task list for hangup event
+ *                 ->siglock to protect ->signal/->sighand
+ */
+void __tty_hangup(struct tty_struct *tty)
+{
+       struct file *cons_filp = NULL;
+       struct file *filp, *f = NULL;
+       struct task_struct *p;
+       struct tty_file_private *priv;
+       int    closecount = 0, n;
+       unsigned long flags;
+       int refs = 0;
+
+       if (!tty)
+               return;
+
+
+       spin_lock(&redirect_lock);
+       if (redirect && file_tty(redirect) == tty) {
+               f = redirect;
+               redirect = NULL;
+       }
+       spin_unlock(&redirect_lock);
+
+       tty_lock();
+
+       /* inuse_filps is protected by the single tty lock,
+          this really needs to change if we want to flush the
+          workqueue with the lock held */
+       check_tty_count(tty, "tty_hangup");
+
+       spin_lock(&tty_files_lock);
+       /* This breaks for file handles being sent over AF_UNIX sockets ? */
+       list_for_each_entry(priv, &tty->tty_files, list) {
+               filp = priv->file;
+               if (filp->f_op->write == redirected_tty_write)
+                       cons_filp = filp;
+               if (filp->f_op->write != tty_write)
+                       continue;
+               closecount++;
+               __tty_fasync(-1, filp, 0);      /* can't block */
+               filp->f_op = &hung_up_tty_fops;
+       }
+       spin_unlock(&tty_files_lock);
+
+       tty_ldisc_hangup(tty);
+
+       read_lock(&tasklist_lock);
+       if (tty->session) {
+               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+                       spin_lock_irq(&p->sighand->siglock);
+                       if (p->signal->tty == tty) {
+                               p->signal->tty = NULL;
+                               /* We defer the dereferences outside fo
+                                  the tasklist lock */
+                               refs++;
+                       }
+                       if (!p->signal->leader) {
+                               spin_unlock_irq(&p->sighand->siglock);
+                               continue;
+                       }
+                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
+                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       if (tty->pgrp)
+                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       spin_unlock_irq(&p->sighand->siglock);
+               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+       }
+       read_unlock(&tasklist_lock);
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       clear_bit(TTY_THROTTLED, &tty->flags);
+       clear_bit(TTY_PUSH, &tty->flags);
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       put_pid(tty->session);
+       put_pid(tty->pgrp);
+       tty->session = NULL;
+       tty->pgrp = NULL;
+       tty->ctrl_status = 0;
+       set_bit(TTY_HUPPED, &tty->flags);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       /* Account for the p->signal references we killed */
+       while (refs--)
+               tty_kref_put(tty);
+
+       /*
+        * If one of the devices matches a console pointer, we
+        * cannot just call hangup() because that will cause
+        * tty->count and state->count to go out of sync.
+        * So we just call close() the right number of times.
+        */
+       if (cons_filp) {
+               if (tty->ops->close)
+                       for (n = 0; n < closecount; n++)
+                               tty->ops->close(tty, cons_filp);
+       } else if (tty->ops->hangup)
+               (tty->ops->hangup)(tty);
+       /*
+        * We don't want to have driver/ldisc interactions beyond
+        * the ones we did here. The driver layer expects no
+        * calls after ->hangup() from the ldisc side. However we
+        * can't yet guarantee all that.
+        */
+       set_bit(TTY_HUPPED, &tty->flags);
+       tty_ldisc_enable(tty);
+
+       tty_unlock();
+
+       if (f)
+               fput(f);
+}
+
+static void do_tty_hangup(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, hangup_work);
+
+       __tty_hangup(tty);
+}
+
+/**
+ *     tty_hangup              -       trigger a hangup event
+ *     @tty: tty to hangup
+ *
+ *     A carrier loss (virtual or otherwise) has occurred on this like
+ *     schedule a hangup sequence to run after this event.
+ */
+
+void tty_hangup(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+       printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
+#endif
+       schedule_work(&tty->hangup_work);
+}
+
+EXPORT_SYMBOL(tty_hangup);
+
+/**
+ *     tty_vhangup             -       process vhangup
+ *     @tty: tty to hangup
+ *
+ *     The user has asked via system call for the terminal to be hung up.
+ *     We do this synchronously so that when the syscall returns the process
+ *     is complete. That guarantee is necessary for security reasons.
+ */
+
+void tty_vhangup(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+
+       printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
+#endif
+       __tty_hangup(tty);
+}
+
+EXPORT_SYMBOL(tty_vhangup);
+
+
+/**
+ *     tty_vhangup_self        -       process vhangup for own ctty
+ *
+ *     Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+       struct tty_struct *tty;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     tty_hung_up_p           -       was tty hung up
+ *     @filp: file pointer of tty
+ *
+ *     Return true if the tty has been subject to a vhangup or a carrier
+ *     loss
+ */
+
+int tty_hung_up_p(struct file *filp)
+{
+       return (filp->f_op == &hung_up_tty_fops);
+}
+
+EXPORT_SYMBOL(tty_hung_up_p);
+
+static void session_clear_tty(struct pid *session)
+{
+       struct task_struct *p;
+       do_each_pid_task(session, PIDTYPE_SID, p) {
+               proc_clear_tty(p);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
+}
+
+/**
+ *     disassociate_ctty       -       disconnect controlling tty
+ *     @on_exit: true if exiting so need to "hang up" the session
+ *
+ *     This function is typically called only by the session leader, when
+ *     it wants to disassociate itself from its controlling tty.
+ *
+ *     It performs the following functions:
+ *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
+ *     (2)  Clears the tty from being controlling the session
+ *     (3)  Clears the controlling tty for all processes in the
+ *             session group.
+ *
+ *     The argument on_exit is set to 1 if called when a process is
+ *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ *
+ *     Locking:
+ *             BTM is taken for hysterical raisins, and held when
+ *               called from no_tty().
+ *               tty_mutex is taken to protect tty
+ *               ->siglock is taken to protect ->signal/->sighand
+ *               tasklist_lock is taken to walk process list for sessions
+ *                 ->siglock is taken to protect ->signal/->sighand
+ */
+
+void disassociate_ctty(int on_exit)
+{
+       struct tty_struct *tty;
+       struct pid *tty_pgrp = NULL;
+
+       if (!current->signal->leader)
+               return;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_pgrp = get_pid(tty->pgrp);
+               if (on_exit) {
+                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
+                               tty_vhangup(tty);
+               }
+               tty_kref_put(tty);
+       } else if (on_exit) {
+               struct pid *old_pgrp;
+               spin_lock_irq(&current->sighand->siglock);
+               old_pgrp = current->signal->tty_old_pgrp;
+               current->signal->tty_old_pgrp = NULL;
+               spin_unlock_irq(&current->sighand->siglock);
+               if (old_pgrp) {
+                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
+                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
+                       put_pid(old_pgrp);
+               }
+               return;
+       }
+       if (tty_pgrp) {
+               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
+               if (!on_exit)
+                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+               put_pid(tty_pgrp);
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       put_pid(current->signal->tty_old_pgrp);
+       current->signal->tty_old_pgrp = NULL;
+       spin_unlock_irq(&current->sighand->siglock);
+
+       tty = get_current_tty();
+       if (tty) {
+               unsigned long flags;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->session = NULL;
+               tty->pgrp = NULL;
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty_kref_put(tty);
+       } else {
+#ifdef TTY_DEBUG_HANGUP
+               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
+                      " = NULL", tty);
+#endif
+       }
+
+       /* Now clear signal->tty under the lock */
+       read_lock(&tasklist_lock);
+       session_clear_tty(task_session(current));
+       read_unlock(&tasklist_lock);
+}
+
+/**
+ *
+ *     no_tty  - Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+       struct task_struct *tsk = current;
+       tty_lock();
+       disassociate_ctty(0);
+       tty_unlock();
+       proc_clear_tty(tsk);
+}
+
+
+/**
+ *     stop_tty        -       propagate flow control
+ *     @tty: tty to stop
+ *
+ *     Perform flow control to the driver. For PTY/TTY pairs we
+ *     must also propagate the TIOCKPKT status. May be called
+ *     on an already stopped device and will not re-call the driver
+ *     method.
+ *
+ *     This functionality is used by both the line disciplines for
+ *     halting incoming flow and by the driver. It may therefore be
+ *     called from any context, may be under the tty atomic_write_lock
+ *     but not always.
+ *
+ *     Locking:
+ *             Uses the tty control lock internally
+ */
+
+void stop_tty(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->stopped) {
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return;
+       }
+       tty->stopped = 1;
+       if (tty->link && tty->link->packet) {
+               tty->ctrl_status &= ~TIOCPKT_START;
+               tty->ctrl_status |= TIOCPKT_STOP;
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->ops->stop)
+               (tty->ops->stop)(tty);
+}
+
+EXPORT_SYMBOL(stop_tty);
+
+/**
+ *     start_tty       -       propagate flow control
+ *     @tty: tty to start
+ *
+ *     Start a tty that has been stopped if at all possible. Perform
+ *     any necessary wakeups and propagate the TIOCPKT status. If this
+ *     is the tty was previous stopped and is being started then the
+ *     driver start method is invoked and the line discipline woken.
+ *
+ *     Locking:
+ *             ctrl_lock
+ */
+
+void start_tty(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (!tty->stopped || tty->flow_stopped) {
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return;
+       }
+       tty->stopped = 0;
+       if (tty->link && tty->link->packet) {
+               tty->ctrl_status &= ~TIOCPKT_STOP;
+               tty->ctrl_status |= TIOCPKT_START;
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->ops->start)
+               (tty->ops->start)(tty);
+       /* If we have a running line discipline it may need kicking */
+       tty_wakeup(tty);
+}
+
+EXPORT_SYMBOL(start_tty);
+
+/**
+ *     tty_read        -       read method for tty device files
+ *     @file: pointer to tty file
+ *     @buf: user buffer
+ *     @count: size of user buffer
+ *     @ppos: unused
+ *
+ *     Perform the read system call function on this terminal device. Checks
+ *     for hung up devices before calling the line discipline method.
+ *
+ *     Locking:
+ *             Locks the line discipline internally while needed. Multiple
+ *     read calls may be outstanding in parallel.
+ */
+
+static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
+                       loff_t *ppos)
+{
+       int i;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+
+       if (tty_paranoia_check(tty, inode, "tty_read"))
+               return -EIO;
+       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
+               return -EIO;
+
+       /* We want to wait for the line discipline to sort out in this
+          situation */
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->read)
+               i = (ld->ops->read)(tty, file, buf, count);
+       else
+               i = -EIO;
+       tty_ldisc_deref(ld);
+       if (i > 0)
+               inode->i_atime = current_fs_time(inode->i_sb);
+       return i;
+}
+
+void tty_write_unlock(struct tty_struct *tty)
+{
+       mutex_unlock(&tty->atomic_write_lock);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+       if (!mutex_trylock(&tty->atomic_write_lock)) {
+               if (ndelay)
+                       return -EAGAIN;
+               if (mutex_lock_interruptible(&tty->atomic_write_lock))
+                       return -ERESTARTSYS;
+       }
+       return 0;
+}
+
+/*
+ * Split writes up in sane blocksizes to avoid
+ * denial-of-service type attacks
+ */
+static inline ssize_t do_tty_write(
+       ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
+       struct tty_struct *tty,
+       struct file *file,
+       const char __user *buf,
+       size_t count)
+{
+       ssize_t ret, written = 0;
+       unsigned int chunk;
+
+       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * We chunk up writes into a temporary buffer. This
+        * simplifies low-level drivers immensely, since they
+        * don't have locking issues and user mode accesses.
+        *
+        * But if TTY_NO_WRITE_SPLIT is set, we should use a
+        * big chunk-size..
+        *
+        * The default chunk-size is 2kB, because the NTTY
+        * layer has problems with bigger chunks. It will
+        * claim to be able to handle more characters than
+        * it actually does.
+        *
+        * FIXME: This can probably go away now except that 64K chunks
+        * are too likely to fail unless switched to vmalloc...
+        */
+       chunk = 2048;
+       if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
+               chunk = 65536;
+       if (count < chunk)
+               chunk = count;
+
+       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
+       if (tty->write_cnt < chunk) {
+               unsigned char *buf_chunk;
+
+               if (chunk < 1024)
+                       chunk = 1024;
+
+               buf_chunk = kmalloc(chunk, GFP_KERNEL);
+               if (!buf_chunk) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               kfree(tty->write_buf);
+               tty->write_cnt = chunk;
+               tty->write_buf = buf_chunk;
+       }
+
+       /* Do the write .. */
+       for (;;) {
+               size_t size = count;
+               if (size > chunk)
+                       size = chunk;
+               ret = -EFAULT;
+               if (copy_from_user(tty->write_buf, buf, size))
+                       break;
+               ret = write(tty, file, tty->write_buf, size);
+               if (ret <= 0)
+                       break;
+               written += ret;
+               buf += ret;
+               count -= ret;
+               if (!count)
+                       break;
+               ret = -ERESTARTSYS;
+               if (signal_pending(current))
+                       break;
+               cond_resched();
+       }
+       if (written) {
+               struct inode *inode = file->f_path.dentry->d_inode;
+               inode->i_mtime = current_fs_time(inode->i_sb);
+               ret = written;
+       }
+out:
+       tty_write_unlock(tty);
+       return ret;
+}
+
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BTM and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+       if (tty) {
+               mutex_lock(&tty->atomic_write_lock);
+               tty_lock();
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+                       tty_unlock();
+                       tty->ops->write(tty, msg, strlen(msg));
+               } else
+                       tty_unlock();
+               tty_write_unlock(tty);
+       }
+       return;
+}
+
+
+/**
+ *     tty_write               -       write method for tty device file
+ *     @file: tty file pointer
+ *     @buf: user data to write
+ *     @count: bytes to write
+ *     @ppos: unused
+ *
+ *     Write data to a tty device via the line discipline.
+ *
+ *     Locking:
+ *             Locks the line discipline as required
+ *             Writes to the tty driver are serialized by the atomic_write_lock
+ *     and are then processed in chunks to the device. The line discipline
+ *     write method will not be invoked in parallel for each device.
+ */
+
+static ssize_t tty_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+       ssize_t ret;
+
+       if (tty_paranoia_check(tty, inode, "tty_write"))
+               return -EIO;
+       if (!tty || !tty->ops->write ||
+               (test_bit(TTY_IO_ERROR, &tty->flags)))
+                       return -EIO;
+       /* Short term debug to catch buggy drivers */
+       if (tty->ops->write_room == NULL)
+               printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
+                       tty->driver->name);
+       ld = tty_ldisc_ref_wait(tty);
+       if (!ld->ops->write)
+               ret = -EIO;
+       else
+               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
+ssize_t redirected_tty_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct file *p = NULL;
+
+       spin_lock(&redirect_lock);
+       if (redirect) {
+               get_file(redirect);
+               p = redirect;
+       }
+       spin_unlock(&redirect_lock);
+
+       if (p) {
+               ssize_t res;
+               res = vfs_write(p, buf, count, &p->f_pos);
+               fput(p);
+               return res;
+       }
+       return tty_write(file, buf, count, ppos);
+}
+
+static char ptychar[] = "pqrstuvwxyzabcde";
+
+/**
+ *     pty_line_name   -       generate name for a pty
+ *     @driver: the tty driver in use
+ *     @index: the minor number
+ *     @p: output buffer of at least 6 bytes
+ *
+ *     Generate a name from a driver reference and write it to the output
+ *     buffer.
+ *
+ *     Locking: None
+ */
+static void pty_line_name(struct tty_driver *driver, int index, char *p)
+{
+       int i = index + driver->name_base;
+       /* ->name is initialized to "ttyp", but "tty" is expected */
+       sprintf(p, "%s%c%x",
+               driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
+               ptychar[i >> 4 & 0xf], i & 0xf);
+}
+
+/**
+ *     tty_line_name   -       generate name for a tty
+ *     @driver: the tty driver in use
+ *     @index: the minor number
+ *     @p: output buffer of at least 7 bytes
+ *
+ *     Generate a name from a driver reference and write it to the output
+ *     buffer.
+ *
+ *     Locking: None
+ */
+static void tty_line_name(struct tty_driver *driver, int index, char *p)
+{
+       sprintf(p, "%s%d", driver->name, index + driver->name_base);
+}
+
+/**
+ *     tty_driver_lookup_tty() - find an existing tty, if any
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Return the tty, if found or ERR_PTR() otherwise.
+ *
+ *     Locking: tty_mutex must be held. If tty is found, the mutex must
+ *     be held until the 'fast-open' is also done. Will change once we
+ *     have refcounting in the driver and per driver locking
+ */
+static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+               struct inode *inode, int idx)
+{
+       struct tty_struct *tty;
+
+       if (driver->ops->lookup)
+               return driver->ops->lookup(driver, inode, idx);
+
+       tty = driver->ttys[idx];
+       return tty;
+}
+
+/**
+ *     tty_init_termios        -  helper for termios setup
+ *     @tty: the tty to set up
+ *
+ *     Initialise the termios structures for this tty. Thus runs under
+ *     the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+
+       tp = tty->driver->termios[idx];
+       if (tp == NULL) {
+               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+               if (tp == NULL)
+                       return -ENOMEM;
+               memcpy(tp, &tty->driver->init_termios,
+                                               sizeof(struct ktermios));
+               tty->driver->termios[idx] = tp;
+       }
+       tty->termios = tp;
+       tty->termios_locked = tp + 1;
+
+       /* Compatibility until drivers always set this */
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tty_init_termios);
+
+/**
+ *     tty_driver_install_tty() - install a tty entry in the driver
+ *     @driver: the driver for the tty
+ *     @tty: the tty
+ *
+ *     Install a tty object into the driver tables. The tty->index field
+ *     will be set by the time this is called. This method is responsible
+ *     for ensuring any need additional structures are allocated and
+ *     configured.
+ *
+ *     Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       int idx = tty->index;
+       int ret;
+
+       if (driver->ops->install) {
+               ret = driver->ops->install(driver, tty);
+               return ret;
+       }
+
+       if (tty_init_termios(tty) == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               driver->ttys[idx] = tty;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/**
+ *     tty_driver_remove_tty() - remove a tty from the driver tables
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Remvoe a tty object from the driver tables. The tty->index field
+ *     will be set by the time this is called.
+ *
+ *     Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       if (driver->ops->remove)
+               driver->ops->remove(driver, tty);
+       else
+               driver->ttys[tty->index] = NULL;
+}
+
+/*
+ *     tty_reopen()    - fast re-open of an open tty
+ *     @tty    - the tty to open
+ *
+ *     Return 0 on success, -errno on error.
+ *
+ *     Locking: tty_mutex must be held from the time the tty was found
+ *              till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+       struct tty_driver *driver = tty->driver;
+
+       if (test_bit(TTY_CLOSING, &tty->flags))
+               return -EIO;
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY &&
+           driver->subtype == PTY_TYPE_MASTER) {
+               /*
+                * special case for PTY masters: only one open permitted,
+                * and the slave side open count is incremented as well.
+                */
+               if (tty->count)
+                       return -EIO;
+
+               tty->link->count++;
+       }
+       tty->count++;
+       tty->driver = driver; /* N.B. why do this every time?? */
+
+       mutex_lock(&tty->ldisc_mutex);
+       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+       mutex_unlock(&tty->ldisc_mutex);
+
+       return 0;
+}
+
+/**
+ *     tty_init_dev            -       initialise a tty device
+ *     @driver: tty driver we are opening a device on
+ *     @idx: device index
+ *     @ret_tty: returned tty structure
+ *     @first_ok: ok to open a new device (used by ptmx)
+ *
+ *     Prepare a tty device. This may not be a "new" clean device but
+ *     could also be an active device. The pty drivers require special
+ *     handling because of this.
+ *
+ *     Locking:
+ *             The function is called under the tty_mutex, which
+ *     protects us from the tty struct or driver itself going away.
+ *
+ *     On exit the tty device has the line discipline attached and
+ *     a reference count of 1. If a pair was created for pty/tty use
+ *     and the other was a pty master then it too has a reference count of 1.
+ *
+ * WSH 06/09/97: Rewritten to remove races and properly clean up after a
+ * failed open.  The new code protects the open with a mutex, so it's
+ * really quite straightforward.  The mutex locking can probably be
+ * relaxed for the (most common) case of reopening a tty.
+ */
+
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok)
+{
+       struct tty_struct *tty;
+       int retval;
+
+       /* Check if pty master is being opened multiple times */
+       if (driver->subtype == PTY_TYPE_MASTER &&
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+               return ERR_PTR(-EIO);
+       }
+
+       /*
+        * First time open is complex, especially for PTY devices.
+        * This code guarantees that either everything succeeds and the
+        * TTY is ready for operation, or else the table slots are vacated
+        * and the allocated memory released.  (Except that the termios
+        * and locked termios may be retained.)
+        */
+
+       if (!try_module_get(driver->owner))
+               return ERR_PTR(-ENODEV);
+
+       tty = alloc_tty_struct();
+       if (!tty)
+               goto fail_no_mem;
+       initialize_tty_struct(tty, driver, idx);
+
+       retval = tty_driver_install_tty(driver, tty);
+       if (retval < 0) {
+               free_tty_struct(tty);
+               module_put(driver->owner);
+               return ERR_PTR(retval);
+       }
+
+       /*
+        * Structures all installed ... call the ldisc open routines.
+        * If we fail here just call release_tty to clean up.  No need
+        * to decrement the use counts, as release_tty doesn't care.
+        */
+       retval = tty_ldisc_setup(tty, tty->link);
+       if (retval)
+               goto release_mem_out;
+       return tty;
+
+fail_no_mem:
+       module_put(driver->owner);
+       return ERR_PTR(-ENOMEM);
+
+       /* call the tty release_tty routine to clean out this slot */
+release_mem_out:
+       if (printk_ratelimit())
+               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
+                                "clearing slot %d\n", idx);
+       release_tty(tty, idx);
+       return ERR_PTR(retval);
+}
+
+void tty_free_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+       /* Kill this flag and push into drivers for locking etc */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+               /* FIXME: Locking on ->termios array */
+               tp = tty->termios;
+               tty->driver->termios[idx] = NULL;
+               kfree(tp);
+       }
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+       tty_driver_remove_tty(tty->driver, tty);
+       tty_free_termios(tty);
+}
+EXPORT_SYMBOL(tty_shutdown);
+
+/**
+ *     release_one_tty         -       release tty structure memory
+ *     @kref: kref of tty we are obliterating
+ *
+ *     Releases memory associated with a tty structure, and clears out the
+ *     driver table slots. This function is called when a device is no longer
+ *     in use. It also gets called when setup of a device fails.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *
+ *     This method gets called from a work queue so that the driver private
+ *     cleanup ops can sleep (needed for USB at least)
+ */
+static void release_one_tty(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, hangup_work);
+       struct tty_driver *driver = tty->driver;
+
+       if (tty->ops->cleanup)
+               tty->ops->cleanup(tty);
+
+       tty->magic = 0;
+       tty_driver_kref_put(driver);
+       module_put(driver->owner);
+
+       spin_lock(&tty_files_lock);
+       list_del_init(&tty->tty_files);
+       spin_unlock(&tty_files_lock);
+
+       put_pid(tty->pgrp);
+       put_pid(tty->session);
+       free_tty_struct(tty);
+}
+
+static void queue_release_one_tty(struct kref *kref)
+{
+       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+
+       if (tty->ops->shutdown)
+               tty->ops->shutdown(tty);
+       else
+               tty_shutdown(tty);
+
+       /* The hangup queue is now free so we can reuse it rather than
+          waste a chunk of memory for each port */
+       INIT_WORK(&tty->hangup_work, release_one_tty);
+       schedule_work(&tty->hangup_work);
+}
+
+/**
+ *     tty_kref_put            -       release a tty kref
+ *     @tty: tty device
+ *
+ *     Release a reference to a tty device and if need be let the kref
+ *     layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+       if (tty)
+               kref_put(&tty->kref, queue_release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
+ *     release_tty             -       release tty structure memory
+ *
+ *     Release both @tty and a possible linked partner (think pty pair),
+ *     and decrement the refcount of the backing module.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *             FIXME: should we require tty_mutex is held here ??
+ *
+ */
+static void release_tty(struct tty_struct *tty, int idx)
+{
+       /* This should always be true but check for the moment */
+       WARN_ON(tty->index != idx);
+
+       if (tty->link)
+               tty_kref_put(tty->link);
+       tty_kref_put(tty);
+}
+
+/**
+ *     tty_release             -       vfs callback for close
+ *     @inode: inode of tty
+ *     @filp: file pointer for handle to tty
+ *
+ *     Called the last time each file handle is closed that references
+ *     this tty. There may however be several such references.
+ *
+ *     Locking:
+ *             Takes bkl. See tty_release_dev
+ *
+ * Even releasing the tty structures is a tricky business.. We have
+ * to be very careful that the structures are all released at the
+ * same time, as interrupts might otherwise get the wrong pointers.
+ *
+ * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
+ * lead to double frees or releasing memory still in use.
+ */
+
+int tty_release(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty = file_tty(filp);
+       struct tty_struct *o_tty;
+       int     pty_master, tty_closing, o_tty_closing, do_sleep;
+       int     devpts;
+       int     idx;
+       char    buf[64];
+
+       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
+               return 0;
+
+       tty_lock();
+       check_tty_count(tty, "tty_release_dev");
+
+       __tty_fasync(-1, filp, 0);
+
+       idx = tty->index;
+       pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+                     tty->driver->subtype == PTY_TYPE_MASTER);
+       devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+       o_tty = tty->link;
+
+#ifdef TTY_PARANOIA_CHECK
+       if (idx < 0 || idx >= tty->driver->num) {
+               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
+                                 "free (%s)\n", tty->name);
+               tty_unlock();
+               return 0;
+       }
+       if (!devpts) {
+               if (tty != tty->driver->ttys[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
+                              "for (%s)\n", idx, tty->name);
+                       return 0;
+               }
+               if (tty->termios != tty->driver->termios[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
+                              "for (%s)\n",
+                              idx, tty->name);
+                       return 0;
+               }
+       }
+#endif
+
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
+              tty_name(tty, buf), tty->count);
+#endif
+
+#ifdef TTY_PARANOIA_CHECK
+       if (tty->driver->other &&
+            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+               if (o_tty != tty->driver->other->ttys[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
+                                         "not o_tty for (%s)\n",
+                              idx, tty->name);
+                       return 0 ;
+               }
+               if (o_tty->termios != tty->driver->other->termios[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
+                                         "not o_termios for (%s)\n",
+                              idx, tty->name);
+                       return 0;
+               }
+               if (o_tty->link != tty) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
+                       return 0;
+               }
+       }
+#endif
+       if (tty->ops->close)
+               tty->ops->close(tty, filp);
+
+       tty_unlock();
+       /*
+        * Sanity check: if tty->count is going to zero, there shouldn't be
+        * any waiters on tty->read_wait or tty->write_wait.  We test the
+        * wait queues and kick everyone out _before_ actually starting to
+        * close.  This ensures that we won't block while releasing the tty
+        * structure.
+        *
+        * The test for the o_tty closing is necessary, since the master and
+        * slave sides may close in any order.  If the slave side closes out
+        * first, its count will be one, since the master side holds an open.
+        * Thus this test wouldn't be triggered at the time the slave closes,
+        * so we do it now.
+        *
+        * Note that it's possible for the tty to be opened again while we're
+        * flushing out waiters.  By recalculating the closing flags before
+        * each iteration we avoid any problems.
+        */
+       while (1) {
+               /* Guard against races with tty->count changes elsewhere and
+                  opens on /dev/tty */
+
+               mutex_lock(&tty_mutex);
+               tty_lock();
+               tty_closing = tty->count <= 1;
+               o_tty_closing = o_tty &&
+                       (o_tty->count <= (pty_master ? 1 : 0));
+               do_sleep = 0;
+
+               if (tty_closing) {
+                       if (waitqueue_active(&tty->read_wait)) {
+                               wake_up_poll(&tty->read_wait, POLLIN);
+                               do_sleep++;
+                       }
+                       if (waitqueue_active(&tty->write_wait)) {
+                               wake_up_poll(&tty->write_wait, POLLOUT);
+                               do_sleep++;
+                       }
+               }
+               if (o_tty_closing) {
+                       if (waitqueue_active(&o_tty->read_wait)) {
+                               wake_up_poll(&o_tty->read_wait, POLLIN);
+                               do_sleep++;
+                       }
+                       if (waitqueue_active(&o_tty->write_wait)) {
+                               wake_up_poll(&o_tty->write_wait, POLLOUT);
+                               do_sleep++;
+                       }
+               }
+               if (!do_sleep)
+                       break;
+
+               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
+                                   "active!\n", tty_name(tty, buf));
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               schedule();
+       }
+
+       /*
+        * The closing flags are now consistent with the open counts on
+        * both sides, and we've completed the last operation that could
+        * block, so it's safe to proceed with closing.
+        */
+       if (pty_master) {
+               if (--o_tty->count < 0) {
+                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
+                                           "(%d) for %s\n",
+                              o_tty->count, tty_name(o_tty, buf));
+                       o_tty->count = 0;
+               }
+       }
+       if (--tty->count < 0) {
+               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
+                      tty->count, tty_name(tty, buf));
+               tty->count = 0;
+       }
+
+       /*
+        * We've decremented tty->count, so we need to remove this file
+        * descriptor off the tty->tty_files list; this serves two
+        * purposes:
+        *  - check_tty_count sees the correct number of file descriptors
+        *    associated with this tty.
+        *  - do_tty_hangup no longer sees this file descriptor as
+        *    something that needs to be handled for hangups.
+        */
+       tty_del_file(filp);
+
+       /*
+        * Perform some housekeeping before deciding whether to return.
+        *
+        * Set the TTY_CLOSING flag if this was the last open.  In the
+        * case of a pty we may have to wait around for the other side
+        * to close, and TTY_CLOSING makes sure we can't be reopened.
+        */
+       if (tty_closing)
+               set_bit(TTY_CLOSING, &tty->flags);
+       if (o_tty_closing)
+               set_bit(TTY_CLOSING, &o_tty->flags);
+
+       /*
+        * If _either_ side is closing, make sure there aren't any
+        * processes that still think tty or o_tty is their controlling
+        * tty.
+        */
+       if (tty_closing || o_tty_closing) {
+               read_lock(&tasklist_lock);
+               session_clear_tty(tty->session);
+               if (o_tty)
+                       session_clear_tty(o_tty->session);
+               read_unlock(&tasklist_lock);
+       }
+
+       mutex_unlock(&tty_mutex);
+
+       /* check whether both sides are closing ... */
+       if (!tty_closing || (o_tty && !o_tty_closing)) {
+               tty_unlock();
+               return 0;
+       }
+
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "freeing tty structure...");
+#endif
+       /*
+        * Ask the line discipline code to release its structures
+        */
+       tty_ldisc_release(tty, o_tty);
+       /*
+        * The release_tty function takes care of the details of clearing
+        * the slots and preserving the termios structure.
+        */
+       release_tty(tty, idx);
+
+       /* Make this pty number available for reallocation */
+       if (devpts)
+               devpts_kill_index(inode, idx);
+       tty_unlock();
+       return 0;
+}
+
+/**
+ *     tty_open                -       open a tty device
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     tty_open and tty_release keep up the tty count that contains the
+ *     number of opens done on a tty. We cannot use the inode-count, as
+ *     different inodes might point to the same tty.
+ *
+ *     Open-counting is needed for pty masters, as well as for keeping
+ *     track of serial lines: DTR is dropped when the last close happens.
+ *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
+ *
+ *     The termios state of a pty is reset on first open so that
+ *     settings don't persist across reuse.
+ *
+ *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
+ *              tty->count should protect the rest.
+ *              ->siglock protects ->signal/->sighand
+ */
+
+static int tty_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty = NULL;
+       int noctty, retval;
+       struct tty_driver *driver;
+       int index;
+       dev_t device = inode->i_rdev;
+       unsigned saved_flags = filp->f_flags;
+
+       nonseekable_open(inode, filp);
+
+retry_open:
+       noctty = filp->f_flags & O_NOCTTY;
+       index  = -1;
+       retval = 0;
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+
+       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
+               tty = get_current_tty();
+               if (!tty) {
+                       tty_unlock();
+                       mutex_unlock(&tty_mutex);
+                       return -ENXIO;
+               }
+               driver = tty_driver_kref_get(tty->driver);
+               index = tty->index;
+               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
+               /* noctty = 1; */
+               /* FIXME: Should we take a driver reference ? */
+               tty_kref_put(tty);
+               goto got_driver;
+       }
+#ifdef CONFIG_VT
+       if (device == MKDEV(TTY_MAJOR, 0)) {
+               extern struct tty_driver *console_driver;
+               driver = tty_driver_kref_get(console_driver);
+               index = fg_console;
+               noctty = 1;
+               goto got_driver;
+       }
+#endif
+       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
+               struct tty_driver *console_driver = console_device(&index);
+               if (console_driver) {
+                       driver = tty_driver_kref_get(console_driver);
+                       if (driver) {
+                               /* Don't let /dev/console block */
+                               filp->f_flags |= O_NONBLOCK;
+                               noctty = 1;
+                               goto got_driver;
+                       }
+               }
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               return -ENODEV;
+       }
+
+       driver = get_tty_driver(device, &index);
+       if (!driver) {
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               return -ENODEV;
+       }
+got_driver:
+       if (!tty) {
+               /* check whether we're reopening an existing tty */
+               tty = tty_driver_lookup_tty(driver, inode, index);
+
+               if (IS_ERR(tty)) {
+                       tty_unlock();
+                       mutex_unlock(&tty_mutex);
+                       return PTR_ERR(tty);
+               }
+       }
+
+       if (tty) {
+               retval = tty_reopen(tty);
+               if (retval)
+                       tty = ERR_PTR(retval);
+       } else
+               tty = tty_init_dev(driver, index, 0);
+
+       mutex_unlock(&tty_mutex);
+       tty_driver_kref_put(driver);
+       if (IS_ERR(tty)) {
+               tty_unlock();
+               return PTR_ERR(tty);
+       }
+
+       retval = tty_add_file(tty, filp);
+       if (retval) {
+               tty_unlock();
+               return retval;
+       }
+
+       check_tty_count(tty, "tty_open");
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               noctty = 1;
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "opening %s...", tty->name);
+#endif
+       if (!retval) {
+               if (tty->ops->open)
+                       retval = tty->ops->open(tty, filp);
+               else
+                       retval = -ENODEV;
+       }
+       filp->f_flags = saved_flags;
+
+       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
+                                               !capable(CAP_SYS_ADMIN))
+               retval = -EBUSY;
+
+       if (retval) {
+#ifdef TTY_DEBUG_HANGUP
+               printk(KERN_DEBUG "error %d in opening %s...", retval,
+                      tty->name);
+#endif
+               tty_unlock(); /* need to call tty_release without BTM */
+               tty_release(inode, filp);
+               if (retval != -ERESTARTSYS)
+                       return retval;
+
+               if (signal_pending(current))
+                       return retval;
+
+               schedule();
+               /*
+                * Need to reset f_op in case a hangup happened.
+                */
+               tty_lock();
+               if (filp->f_op == &hung_up_tty_fops)
+                       filp->f_op = &tty_fops;
+               tty_unlock();
+               goto retry_open;
+       }
+       tty_unlock();
+
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+       spin_lock_irq(&current->sighand->siglock);
+       if (!noctty &&
+           current->signal->leader &&
+           !current->signal->tty &&
+           tty->session == NULL)
+               __proc_set_tty(current, tty);
+       spin_unlock_irq(&current->sighand->siglock);
+       tty_unlock();
+       mutex_unlock(&tty_mutex);
+       return 0;
+}
+
+
+
+/**
+ *     tty_poll        -       check tty status
+ *     @filp: file being polled
+ *     @wait: poll wait structures to update
+ *
+ *     Call the line discipline polling method to obtain the poll
+ *     status of the device.
+ *
+ *     Locking: locks called line discipline but ldisc poll method
+ *     may be re-entered freely by other callers.
+ */
+
+static unsigned int tty_poll(struct file *filp, poll_table *wait)
+{
+       struct tty_struct *tty = file_tty(filp);
+       struct tty_ldisc *ld;
+       int ret = 0;
+
+       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
+               return 0;
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->poll)
+               ret = (ld->ops->poll)(tty, filp, wait);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
+static int __tty_fasync(int fd, struct file *filp, int on)
+{
+       struct tty_struct *tty = file_tty(filp);
+       unsigned long flags;
+       int retval = 0;
+
+       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
+               goto out;
+
+       retval = fasync_helper(fd, filp, on, &tty->fasync);
+       if (retval <= 0)
+               goto out;
+
+       if (on) {
+               enum pid_type type;
+               struct pid *pid;
+               if (!waitqueue_active(&tty->read_wait))
+                       tty->minimum_to_wake = 1;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               if (tty->pgrp) {
+                       pid = tty->pgrp;
+                       type = PIDTYPE_PGID;
+               } else {
+                       pid = task_pid(current);
+                       type = PIDTYPE_PID;
+               }
+               get_pid(pid);
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               retval = __f_setown(filp, pid, type, 0);
+               put_pid(pid);
+               if (retval)
+                       goto out;
+       } else {
+               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
+                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
+       }
+       retval = 0;
+out:
+       return retval;
+}
+
+static int tty_fasync(int fd, struct file *filp, int on)
+{
+       int retval;
+       tty_lock();
+       retval = __tty_fasync(fd, filp, on);
+       tty_unlock();
+       return retval;
+}
+
+/**
+ *     tiocsti                 -       fake input character
+ *     @tty: tty to fake input into
+ *     @p: pointer to character
+ *
+ *     Fake input to a tty device. Does the necessary locking and
+ *     input management.
+ *
+ *     FIXME: does not honour flow control ??
+ *
+ *     Locking:
+ *             Called functions take tty_ldisc_lock
+ *             current->signal->tty check is safe without locks
+ *
+ *     FIXME: may race normal receive processing
+ */
+
+static int tiocsti(struct tty_struct *tty, char __user *p)
+{
+       char ch, mbz = 0;
+       struct tty_ldisc *ld;
+
+       if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(ch, p))
+               return -EFAULT;
+       tty_audit_tiocsti(tty, ch);
+       ld = tty_ldisc_ref_wait(tty);
+       ld->ops->receive_buf(tty, &ch, &mbz, 1);
+       tty_ldisc_deref(ld);
+       return 0;
+}
+
+/**
+ *     tiocgwinsz              -       implement window query ioctl
+ *     @tty; tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the kernel idea of the window size into the user buffer.
+ *
+ *     Locking: tty->termios_mutex is taken to ensure the winsize data
+ *             is consistent.
+ */
+
+static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
+{
+       int err;
+
+       mutex_lock(&tty->termios_mutex);
+       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
+       mutex_unlock(&tty->termios_mutex);
+
+       return err ? -EFAULT: 0;
+}
+
+/**
+ *     tty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @rows: rows (character)
+ *     @cols: cols (character)
+ *
+ *     Update the termios variables and send the necessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
+{
+       struct pid *pgrp;
+       unsigned long flags;
+
+       /* Lock the tty */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals */
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       put_pid(pgrp);
+
+       tty->winsize = *ws;
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+/**
+ *     tiocswinsz              -       implement window size set ioctl
+ *     @tty; tty side of tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the user idea of the window size to the kernel. Traditionally
+ *     this is just advisory information but for the Linux console it
+ *     actually has driver level meaning and triggers a VC resize.
+ *
+ *     Locking:
+ *             Driver dependant. The default do_resize method takes the
+ *     tty termios mutex and ctrl_lock. The console takes its own lock
+ *     then calls into the default method.
+ */
+
+static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
+{
+       struct winsize tmp_ws;
+       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+               return -EFAULT;
+
+       if (tty->ops->resize)
+               return tty->ops->resize(tty, &tmp_ws);
+       else
+               return tty_do_resize(tty, &tmp_ws);
+}
+
+/**
+ *     tioccons        -       allow admin to move logical console
+ *     @file: the file to become console
+ *
+ *     Allow the adminstrator to move the redirected console device
+ *
+ *     Locking: uses redirect_lock to guard the redirect information
+ */
+
+static int tioccons(struct file *file)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (file->f_op->write == redirected_tty_write) {
+               struct file *f;
+               spin_lock(&redirect_lock);
+               f = redirect;
+               redirect = NULL;
+               spin_unlock(&redirect_lock);
+               if (f)
+                       fput(f);
+               return 0;
+       }
+       spin_lock(&redirect_lock);
+       if (redirect) {
+               spin_unlock(&redirect_lock);
+               return -EBUSY;
+       }
+       get_file(file);
+       redirect = file;
+       spin_unlock(&redirect_lock);
+       return 0;
+}
+
+/**
+ *     fionbio         -       non blocking ioctl
+ *     @file: file to set blocking value
+ *     @p: user parameter
+ *
+ *     Historical tty interfaces had a blocking control ioctl before
+ *     the generic functionality existed. This piece of history is preserved
+ *     in the expected tty API of posix OS's.
+ *
+ *     Locking: none, the open file handle ensures it won't go away.
+ */
+
+static int fionbio(struct file *file, int __user *p)
+{
+       int nonblock;
+
+       if (get_user(nonblock, p))
+               return -EFAULT;
+
+       spin_lock(&file->f_lock);
+       if (nonblock)
+               file->f_flags |= O_NONBLOCK;
+       else
+               file->f_flags &= ~O_NONBLOCK;
+       spin_unlock(&file->f_lock);
+       return 0;
+}
+
+/**
+ *     tiocsctty       -       set controlling tty
+ *     @tty: tty structure
+ *     @arg: user argument
+ *
+ *     This ioctl is used to manage job control. It permits a session
+ *     leader to set this tty as the controlling tty for the session.
+ *
+ *     Locking:
+ *             Takes tty_mutex() to protect tty instance
+ *             Takes tasklist_lock internally to walk sessions
+ *             Takes ->siglock() when updating signal->tty
+ */
+
+static int tiocsctty(struct tty_struct *tty, int arg)
+{
+       int ret = 0;
+       if (current->signal->leader && (task_session(current) == tty->session))
+               return ret;
+
+       mutex_lock(&tty_mutex);
+       /*
+        * The process must be a session leader and
+        * not have a controlling tty already.
+        */
+       if (!current->signal->leader || current->signal->tty) {
+               ret = -EPERM;
+               goto unlock;
+       }
+
+       if (tty->session) {
+               /*
+                * This tty is already the controlling
+                * tty for another session group!
+                */
+               if (arg == 1 && capable(CAP_SYS_ADMIN)) {
+                       /*
+                        * Steal it away
+                        */
+                       read_lock(&tasklist_lock);
+                       session_clear_tty(tty->session);
+                       read_unlock(&tasklist_lock);
+               } else {
+                       ret = -EPERM;
+                       goto unlock;
+               }
+       }
+       proc_set_tty(current, tty);
+unlock:
+       mutex_unlock(&tty_mutex);
+       return ret;
+}
+
+/**
+ *     tty_get_pgrp    -       return a ref counted pgrp pid
+ *     @tty: tty to read
+ *
+ *     Returns a refcounted instance of the pid struct for the process
+ *     group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct pid *pgrp;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
+/**
+ *     tiocgpgrp               -       get process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side of the tty pased by the user if a pty else the tty
+ *     @p: returned pid
+ *
+ *     Obtain the process group of the tty. If there is no process group
+ *     return an error.
+ *
+ *     Locking: none. Reference to current->signal->tty is safe.
+ */
+
+static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       struct pid *pid;
+       int ret;
+       /*
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+        */
+       if (tty == real_tty && current->signal->tty != real_tty)
+               return -ENOTTY;
+       pid = tty_get_pgrp(real_tty);
+       ret =  put_user(pid_vnr(pid), p);
+       put_pid(pid);
+       return ret;
+}
+
+/**
+ *     tiocspgrp               -       attempt to set process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side device matching tty passed by user
+ *     @p: pid pointer
+ *
+ *     Set the process group of the tty to the session passed. Only
+ *     permitted where the tty session is our session.
+ *
+ *     Locking: RCU, ctrl lock
+ */
+
+static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       struct pid *pgrp;
+       pid_t pgrp_nr;
+       int retval = tty_check_change(real_tty);
+       unsigned long flags;
+
+       if (retval == -EIO)
+               return -ENOTTY;
+       if (retval)
+               return retval;
+       if (!current->signal->tty ||
+           (current->signal->tty != real_tty) ||
+           (real_tty->session != task_session(current)))
+               return -ENOTTY;
+       if (get_user(pgrp_nr, p))
+               return -EFAULT;
+       if (pgrp_nr < 0)
+               return -EINVAL;
+       rcu_read_lock();
+       pgrp = find_vpid(pgrp_nr);
+       retval = -ESRCH;
+       if (!pgrp)
+               goto out_unlock;
+       retval = -EPERM;
+       if (session_of_pgrp(pgrp) != task_session(current))
+               goto out_unlock;
+       retval = 0;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       put_pid(real_tty->pgrp);
+       real_tty->pgrp = get_pid(pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+out_unlock:
+       rcu_read_unlock();
+       return retval;
+}
+
+/**
+ *     tiocgsid                -       get session id
+ *     @tty: tty passed by user
+ *     @real_tty: tty side of the tty pased by the user if a pty else the tty
+ *     @p: pointer to returned session id
+ *
+ *     Obtain the session id of the tty. If there is no session
+ *     return an error.
+ *
+ *     Locking: none. Reference to current->signal->tty is safe.
+ */
+
+static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       /*
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+       */
+       if (tty == real_tty && current->signal->tty != real_tty)
+               return -ENOTTY;
+       if (!real_tty->session)
+               return -ENOTTY;
+       return put_user(pid_vnr(real_tty->session), p);
+}
+
+/**
+ *     tiocsetd        -       set line discipline
+ *     @tty: tty device
+ *     @p: pointer to user data
+ *
+ *     Set the line discipline according to user request.
+ *
+ *     Locking: see tty_set_ldisc, this function is just a helper
+ */
+
+static int tiocsetd(struct tty_struct *tty, int __user *p)
+{
+       int ldisc;
+       int ret;
+
+       if (get_user(ldisc, p))
+               return -EFAULT;
+
+       ret = tty_set_ldisc(tty, ldisc);
+
+       return ret;
+}
+
+/**
+ *     send_break      -       performed time break
+ *     @tty: device to break on
+ *     @duration: timeout in mS
+ *
+ *     Perform a timed break on hardware that lacks its own driver level
+ *     timed break functionality.
+ *
+ *     Locking:
+ *             atomic_write_lock serializes
+ *
+ */
+
+static int send_break(struct tty_struct *tty, unsigned int duration)
+{
+       int retval;
+
+       if (tty->ops->break_ctl == NULL)
+               return 0;
+
+       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
+               retval = tty->ops->break_ctl(tty, duration);
+       else {
+               /* Do the work ourselves */
+               if (tty_write_lock(tty, 0) < 0)
+                       return -EINTR;
+               retval = tty->ops->break_ctl(tty, -1);
+               if (retval)
+                       goto out;
+               if (!signal_pending(current))
+                       msleep_interruptible(duration);
+               retval = tty->ops->break_ctl(tty, 0);
+out:
+               tty_write_unlock(tty);
+               if (signal_pending(current))
+                       retval = -EINTR;
+       }
+       return retval;
+}
+
+/**
+ *     tty_tiocmget            -       get modem status
+ *     @tty: tty device
+ *     @file: user file pointer
+ *     @p: pointer to result
+ *
+ *     Obtain the modem status bits from the tty driver if the feature
+ *     is supported. Return -EINVAL if it is not available.
+ *
+ *     Locking: none (up to the driver)
+ */
+
+static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
+{
+       int retval = -EINVAL;
+
+       if (tty->ops->tiocmget) {
+               retval = tty->ops->tiocmget(tty, file);
+
+               if (retval >= 0)
+                       retval = put_user(retval, p);
+       }
+       return retval;
+}
+
+/**
+ *     tty_tiocmset            -       set modem status
+ *     @tty: tty device
+ *     @file: user file pointer
+ *     @cmd: command - clear bits, set bits or set all
+ *     @p: pointer to desired bits
+ *
+ *     Set the modem status bits from the tty driver if the feature
+ *     is supported. Return -EINVAL if it is not available.
+ *
+ *     Locking: none (up to the driver)
+ */
+
+static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
+            unsigned __user *p)
+{
+       int retval;
+       unsigned int set, clear, val;
+
+       if (tty->ops->tiocmset == NULL)
+               return -EINVAL;
+
+       retval = get_user(val, p);
+       if (retval)
+               return retval;
+       set = clear = 0;
+       switch (cmd) {
+       case TIOCMBIS:
+               set = val;
+               break;
+       case TIOCMBIC:
+               clear = val;
+               break;
+       case TIOCMSET:
+               set = val;
+               clear = ~val;
+               break;
+       }
+       set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+       clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+       return tty->ops->tiocmset(tty, file, set, clear);
+}
+
+static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
+{
+       int retval = -EINVAL;
+       struct serial_icounter_struct icount;
+       memset(&icount, 0, sizeof(icount));
+       if (tty->ops->get_icount)
+               retval = tty->ops->get_icount(tty, &icount);
+       if (retval != 0)
+               return retval;
+       if (copy_to_user(arg, &icount, sizeof(icount)))
+               return -EFAULT;
+       return 0;
+}
+
+struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               tty = tty->link;
+       return tty;
+}
+EXPORT_SYMBOL(tty_pair_get_tty);
+
+struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+           return tty;
+       return tty->link;
+}
+EXPORT_SYMBOL(tty_pair_get_pty);
+
+/*
+ * Split this up, as gcc can choke on it otherwise..
+ */
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct tty_struct *tty = file_tty(file);
+       struct tty_struct *real_tty;
+       void __user *p = (void __user *)arg;
+       int retval;
+       struct tty_ldisc *ld;
+       struct inode *inode = file->f_dentry->d_inode;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       real_tty = tty_pair_get_tty(tty);
+
+       /*
+        * Factor out some common prep work
+        */
+       switch (cmd) {
+       case TIOCSETD:
+       case TIOCSBRK:
+       case TIOCCBRK:
+       case TCSBRK:
+       case TCSBRKP:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               if (cmd != TIOCCBRK) {
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+               }
+               break;
+       }
+
+       /*
+        *      Now do the stuff.
+        */
+       switch (cmd) {
+       case TIOCSTI:
+               return tiocsti(tty, p);
+       case TIOCGWINSZ:
+               return tiocgwinsz(real_tty, p);
+       case TIOCSWINSZ:
+               return tiocswinsz(real_tty, p);
+       case TIOCCONS:
+               return real_tty != tty ? -EINVAL : tioccons(file);
+       case FIONBIO:
+               return fionbio(file, p);
+       case TIOCEXCL:
+               set_bit(TTY_EXCLUSIVE, &tty->flags);
+               return 0;
+       case TIOCNXCL:
+               clear_bit(TTY_EXCLUSIVE, &tty->flags);
+               return 0;
+       case TIOCNOTTY:
+               if (current->signal->tty != tty)
+                       return -ENOTTY;
+               no_tty();
+               return 0;
+       case TIOCSCTTY:
+               return tiocsctty(tty, arg);
+       case TIOCGPGRP:
+               return tiocgpgrp(tty, real_tty, p);
+       case TIOCSPGRP:
+               return tiocspgrp(tty, real_tty, p);
+       case TIOCGSID:
+               return tiocgsid(tty, real_tty, p);
+       case TIOCGETD:
+               return put_user(tty->ldisc->ops->num, (int __user *)p);
+       case TIOCSETD:
+               return tiocsetd(tty, p);
+       /*
+        * Break handling
+        */
+       case TIOCSBRK:  /* Turn break on, unconditionally */
+               if (tty->ops->break_ctl)
+                       return tty->ops->break_ctl(tty, -1);
+               return 0;
+       case TIOCCBRK:  /* Turn break off, unconditionally */
+               if (tty->ops->break_ctl)
+                       return tty->ops->break_ctl(tty, 0);
+               return 0;
+       case TCSBRK:   /* SVID version: non-zero arg --> no break */
+               /* non-zero arg means wait for all output data
+                * to be sent (performed above) but don't send break.
+                * This is used by the tcdrain() termios function.
+                */
+               if (!arg)
+                       return send_break(tty, 250);
+               return 0;
+       case TCSBRKP:   /* support for POSIX tcsendbreak() */
+               return send_break(tty, arg ? arg*100 : 250);
+
+       case TIOCMGET:
+               return tty_tiocmget(tty, file, p);
+       case TIOCMSET:
+       case TIOCMBIC:
+       case TIOCMBIS:
+               return tty_tiocmset(tty, file, cmd, p);
+       case TIOCGICOUNT:
+               retval = tty_tiocgicount(tty, p);
+               /* For the moment allow fall through to the old method */
+               if (retval != -EINVAL)
+                       return retval;
+               break;
+       case TCFLSH:
+               switch (arg) {
+               case TCIFLUSH:
+               case TCIOFLUSH:
+               /* flush tty buffer and allow ldisc to process ioctl */
+                       tty_buffer_flush(tty);
+                       break;
+               }
+               break;
+       }
+       if (tty->ops->ioctl) {
+               retval = (tty->ops->ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+       ld = tty_ldisc_ref_wait(tty);
+       retval = -EINVAL;
+       if (ld->ops->ioctl) {
+               retval = ld->ops->ioctl(tty, file, cmd, arg);
+               if (retval == -ENOIOCTLCMD)
+                       retval = -EINVAL;
+       }
+       tty_ldisc_deref(ld);
+       return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+       int retval = -ENOIOCTLCMD;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       if (tty->ops->compat_ioctl) {
+               retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->compat_ioctl)
+               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+       tty_ldisc_deref(ld);
+
+       return retval;
+}
+#endif
+
+/*
+ * This implements the "Secure Attention Key" ---  the idea is to
+ * prevent trojan horses by killing all processes associated with this
+ * tty when the user hits the "Secure Attention Key".  Required for
+ * super-paranoid applications --- see the Orange Book for more details.
+ *
+ * This code could be nicer; ideally it should send a HUP, wait a few
+ * seconds, then send a INT, and then a KILL signal.  But you then
+ * have to coordinate with the init process, since all processes associated
+ * with the current tty must be dead before the new getty is allowed
+ * to spawn.
+ *
+ * Now, if it would be correct ;-/ The current code has a nasty hole -
+ * it doesn't catch files in flight. We may send the descriptor to ourselves
+ * via AF_UNIX socket, close it and later fetch from socket. FIXME.
+ *
+ * Nasty bug: do_SAK is being called in interrupt context.  This can
+ * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
+ */
+void __do_SAK(struct tty_struct *tty)
+{
+#ifdef TTY_SOFT_SAK
+       tty_hangup(tty);
+#else
+       struct task_struct *g, *p;
+       struct pid *session;
+       int             i;
+       struct file     *filp;
+       struct fdtable *fdt;
+
+       if (!tty)
+               return;
+       session = tty->session;
+
+       tty_ldisc_flush(tty);
+
+       tty_driver_flush_buffer(tty);
+
+       read_lock(&tasklist_lock);
+       /* Kill the entire session */
+       do_each_pid_task(session, PIDTYPE_SID, p) {
+               printk(KERN_NOTICE "SAK: killed process %d"
+                       " (%s): task_session(p)==tty->session\n",
+                       task_pid_nr(p), p->comm);
+               send_sig(SIGKILL, p, 1);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
+       /* Now kill any processes that happen to have the
+        * tty open.
+        */
+       do_each_thread(g, p) {
+               if (p->signal->tty == tty) {
+                       printk(KERN_NOTICE "SAK: killed process %d"
+                           " (%s): task_session(p)==tty->session\n",
+                           task_pid_nr(p), p->comm);
+                       send_sig(SIGKILL, p, 1);
+                       continue;
+               }
+               task_lock(p);
+               if (p->files) {
+                       /*
+                        * We don't take a ref to the file, so we must
+                        * hold ->file_lock instead.
+                        */
+                       spin_lock(&p->files->file_lock);
+                       fdt = files_fdtable(p->files);
+                       for (i = 0; i < fdt->max_fds; i++) {
+                               filp = fcheck_files(p->files, i);
+                               if (!filp)
+                                       continue;
+                               if (filp->f_op->read == tty_read &&
+                                   file_tty(filp) == tty) {
+                                       printk(KERN_NOTICE "SAK: killed process %d"
+                                           " (%s): fd#%d opened to the tty\n",
+                                           task_pid_nr(p), p->comm, i);
+                                       force_sig(SIGKILL, p);
+                                       break;
+                               }
+                       }
+                       spin_unlock(&p->files->file_lock);
+               }
+               task_unlock(p);
+       } while_each_thread(g, p);
+       read_unlock(&tasklist_lock);
+#endif
+}
+
+static void do_SAK_work(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, SAK_work);
+       __do_SAK(tty);
+}
+
+/*
+ * The tq handling here is a little racy - tty->SAK_work may already be queued.
+ * Fortunately we don't need to worry, because if ->SAK_work is already queued,
+ * the values which we write to it will be identical to the values which it
+ * already has. --akpm
+ */
+void do_SAK(struct tty_struct *tty)
+{
+       if (!tty)
+               return;
+       schedule_work(&tty->SAK_work);
+}
+
+EXPORT_SYMBOL(do_SAK);
+
+static int dev_match_devt(struct device *dev, void *data)
+{
+       dev_t *devt = data;
+       return dev->devt == *devt;
+}
+
+/* Must put_device() after it's unused! */
+static struct device *tty_get_device(struct tty_struct *tty)
+{
+       dev_t devt = tty_devnum(tty);
+       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+
+
+/**
+ *     initialize_tty_struct
+ *     @tty: tty to initialize
+ *
+ *     This subroutine initializes a tty structure that has been newly
+ *     allocated.
+ *
+ *     Locking: none - tty in question must not be exposed at this point
+ */
+
+void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx)
+{
+       memset(tty, 0, sizeof(struct tty_struct));
+       kref_init(&tty->kref);
+       tty->magic = TTY_MAGIC;
+       tty_ldisc_init(tty);
+       tty->session = NULL;
+       tty->pgrp = NULL;
+       tty->overrun_time = jiffies;
+       tty->buf.head = tty->buf.tail = NULL;
+       tty_buffer_init(tty);
+       mutex_init(&tty->termios_mutex);
+       mutex_init(&tty->ldisc_mutex);
+       init_waitqueue_head(&tty->write_wait);
+       init_waitqueue_head(&tty->read_wait);
+       INIT_WORK(&tty->hangup_work, do_tty_hangup);
+       mutex_init(&tty->atomic_read_lock);
+       mutex_init(&tty->atomic_write_lock);
+       mutex_init(&tty->output_lock);
+       mutex_init(&tty->echo_lock);
+       spin_lock_init(&tty->read_lock);
+       spin_lock_init(&tty->ctrl_lock);
+       INIT_LIST_HEAD(&tty->tty_files);
+       INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+       tty->driver = driver;
+       tty->ops = driver->ops;
+       tty->index = idx;
+       tty_line_name(driver, idx, tty->name);
+       tty->dev = tty_get_device(tty);
+}
+
+/**
+ *     tty_put_char    -       write one character to a tty
+ *     @tty: tty
+ *     @ch: character
+ *
+ *     Write one byte to the tty using the provided put_char method
+ *     if present. Returns the number of characters successfully output.
+ *
+ *     Note: the specific put_char operation in the driver layer may go
+ *     away soon. Don't call it directly, use this method
+ */
+
+int tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       if (tty->ops->put_char)
+               return tty->ops->put_char(tty, ch);
+       return tty->ops->write(tty, &ch, 1);
+}
+EXPORT_SYMBOL_GPL(tty_put_char);
+
+struct class *tty_class;
+
+/**
+ *     tty_register_device - register a tty device
+ *     @driver: the tty driver that describes the tty device
+ *     @index: the index in the tty driver for this tty device
+ *     @device: a struct device that is associated with this tty device.
+ *             This field is optional, if there is no known struct device
+ *             for this tty device it can be set to NULL safely.
+ *
+ *     Returns a pointer to the struct device for this tty device
+ *     (or ERR_PTR(-EFOO) on error).
+ *
+ *     This call is required to be made to register an individual tty device
+ *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
+ *     that bit is not set, this function should not be called by a tty
+ *     driver.
+ *
+ *     Locking: ??
+ */
+
+struct device *tty_register_device(struct tty_driver *driver, unsigned index,
+                                  struct device *device)
+{
+       char name[64];
+       dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+
+       if (index >= driver->num) {
+               printk(KERN_ERR "Attempt to register invalid tty line number "
+                      " (%d).\n", index);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY)
+               pty_line_name(driver, index, name);
+       else
+               tty_line_name(driver, index, name);
+
+       return device_create(tty_class, device, dev, NULL, name);
+}
+EXPORT_SYMBOL(tty_register_device);
+
+/**
+ *     tty_unregister_device - unregister a tty device
+ *     @driver: the tty driver that describes the tty device
+ *     @index: the index in the tty driver for this tty device
+ *
+ *     If a tty device is registered with a call to tty_register_device() then
+ *     this function must be called when the tty device is gone.
+ *
+ *     Locking: ??
+ */
+
+void tty_unregister_device(struct tty_driver *driver, unsigned index)
+{
+       device_destroy(tty_class,
+               MKDEV(driver->major, driver->minor_start) + index);
+}
+EXPORT_SYMBOL(tty_unregister_device);
+
+struct tty_driver *alloc_tty_driver(int lines)
+{
+       struct tty_driver *driver;
+
+       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
+       if (driver) {
+               kref_init(&driver->kref);
+               driver->magic = TTY_DRIVER_MAGIC;
+               driver->num = lines;
+               /* later we'll move allocation of tables here */
+       }
+       return driver;
+}
+EXPORT_SYMBOL(alloc_tty_driver);
+
+static void destruct_tty_driver(struct kref *kref)
+{
+       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+       int i;
+       struct ktermios *tp;
+       void *p;
+
+       if (driver->flags & TTY_DRIVER_INSTALLED) {
+               /*
+                * Free the termios and termios_locked structures because
+                * we don't want to get memory leaks when modular tty
+                * drivers are removed from the kernel.
+                */
+               for (i = 0; i < driver->num; i++) {
+                       tp = driver->termios[i];
+                       if (tp) {
+                               driver->termios[i] = NULL;
+                               kfree(tp);
+                       }
+                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+                               tty_unregister_device(driver, i);
+               }
+               p = driver->ttys;
+               proc_tty_unregister_driver(driver);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               cdev_del(&driver->cdev);
+       }
+       kfree(driver);
+}
+
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+       kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
+void tty_set_operations(struct tty_driver *driver,
+                       const struct tty_operations *op)
+{
+       driver->ops = op;
+};
+EXPORT_SYMBOL(tty_set_operations);
+
+void put_tty_driver(struct tty_driver *d)
+{
+       tty_driver_kref_put(d);
+}
+EXPORT_SYMBOL(put_tty_driver);
+
+/*
+ * Called by a tty driver to register itself.
+ */
+int tty_register_driver(struct tty_driver *driver)
+{
+       int error;
+       int i;
+       dev_t dev;
+       void **p = NULL;
+       struct device *d;
+
+       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+       }
+
+       if (!driver->major) {
+               error = alloc_chrdev_region(&dev, driver->minor_start,
+                                               driver->num, driver->name);
+               if (!error) {
+                       driver->major = MAJOR(dev);
+                       driver->minor_start = MINOR(dev);
+               }
+       } else {
+               dev = MKDEV(driver->major, driver->minor_start);
+               error = register_chrdev_region(dev, driver->num, driver->name);
+       }
+       if (error < 0) {
+               kfree(p);
+               return error;
+       }
+
+       if (p) {
+               driver->ttys = (struct tty_struct **)p;
+               driver->termios = (struct ktermios **)(p + driver->num);
+       } else {
+               driver->ttys = NULL;
+               driver->termios = NULL;
+       }
+
+       cdev_init(&driver->cdev, &tty_fops);
+       driver->cdev.owner = driver->owner;
+       error = cdev_add(&driver->cdev, dev, driver->num);
+       if (error) {
+               unregister_chrdev_region(dev, driver->num);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               return error;
+       }
+
+       mutex_lock(&tty_mutex);
+       list_add(&driver->tty_drivers, &tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
+               for (i = 0; i < driver->num; i++) {
+                       d = tty_register_device(driver, i, NULL);
+                       if (IS_ERR(d)) {
+                               error = PTR_ERR(d);
+                               goto err;
+                       }
+               }
+       }
+       proc_tty_register_driver(driver);
+       driver->flags |= TTY_DRIVER_INSTALLED;
+       return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               tty_unregister_device(driver, i);
+
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       unregister_chrdev_region(dev, driver->num);
+       driver->ttys = NULL;
+       driver->termios = NULL;
+       kfree(p);
+       return error;
+}
+
+EXPORT_SYMBOL(tty_register_driver);
+
+/*
+ * Called by a tty driver to unregister itself.
+ */
+int tty_unregister_driver(struct tty_driver *driver)
+{
+#if 0
+       /* FIXME */
+       if (driver->refcount)
+               return -EBUSY;
+#endif
+       unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
+                               driver->num);
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+       return 0;
+}
+
+EXPORT_SYMBOL(tty_unregister_driver);
+
+dev_t tty_devnum(struct tty_struct *tty)
+{
+       return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+}
+EXPORT_SYMBOL(tty_devnum);
+
+void proc_clear_tty(struct task_struct *p)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+       spin_lock_irqsave(&p->sighand->siglock, flags);
+       tty = p->signal->tty;
+       p->signal->tty = NULL;
+       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+       tty_kref_put(tty);
+}
+
+/* Called under the sighand lock */
+
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+       if (tty) {
+               unsigned long flags;
+               /* We should not have a session or pgrp to put here but.... */
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->pgrp = get_pid(task_pgrp(tsk));
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty->session = get_pid(task_session(tsk));
+               if (tsk->signal->tty) {
+                       printk(KERN_DEBUG "tty not NULL!!\n");
+                       tty_kref_put(tsk->signal->tty);
+               }
+       }
+       put_pid(tsk->signal->tty_old_pgrp);
+       tsk->signal->tty = tty_kref_get(tty);
+       tsk->signal->tty_old_pgrp = NULL;
+}
+
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+       spin_lock_irq(&tsk->sighand->siglock);
+       __proc_set_tty(tsk, tty);
+       spin_unlock_irq(&tsk->sighand->siglock);
+}
+
+struct tty_struct *get_current_tty(void)
+{
+       struct tty_struct *tty;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       tty = tty_kref_get(current->signal->tty);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       return tty;
+}
+EXPORT_SYMBOL_GPL(get_current_tty);
+
+void tty_default_fops(struct file_operations *fops)
+{
+       *fops = tty_fops;
+}
+
+/*
+ * Initialize the console device. This is called *early*, so
+ * we can't necessarily depend on lots of kernel help here.
+ * Just do some early initializations, and do the complex setup
+ * later.
+ */
+void __init console_init(void)
+{
+       initcall_t *call;
+
+       /* Setup the default TTY line discipline. */
+       tty_ldisc_begin();
+
+       /*
+        * set up the console device so that later boot sequences can
+        * inform about problems etc..
+        */
+       call = __con_initcall_start;
+       while (call < __con_initcall_end) {
+               (*call)();
+               call++;
+       }
+}
+
+static char *tty_devnode(struct device *dev, mode_t *mode)
+{
+       if (!mode)
+               return NULL;
+       if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
+           dev->devt == MKDEV(TTYAUX_MAJOR, 2))
+               *mode = 0666;
+       return NULL;
+}
+
+static int __init tty_class_init(void)
+{
+       tty_class = class_create(THIS_MODULE, "tty");
+       if (IS_ERR(tty_class))
+               return PTR_ERR(tty_class);
+       tty_class->devnode = tty_devnode;
+       return 0;
+}
+
+postcore_initcall(tty_class_init);
+
+/* 3/2004 jmc: why do these devices exist? */
+
+static struct cdev tty_cdev, console_cdev;
+
+/*
+ * Ok, now we can initialize the rest of the tty devices and can count
+ * on memory allocations, interrupts etc..
+ */
+int __init tty_init(void)
+{
+       cdev_init(&tty_cdev, &tty_fops);
+       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
+               panic("Couldn't register /dev/tty driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+                             "tty");
+
+       cdev_init(&console_cdev, &console_fops);
+       if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
+               panic("Couldn't register /dev/console driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+                             "console");
+
+#ifdef CONFIG_VT
+       vty_init(&console_fops);
+#endif
+       return 0;
+}
+
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
new file mode 100644 (file)
index 0000000..0c18899
--- /dev/null
@@ -0,0 +1,1179 @@
+/*
+ *  linux/drivers/char/tty_ioctl.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ */
+
+#include <linux/types.h>
+#include <linux/termios.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/tty.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#undef TTY_DEBUG_WAIT_UNTIL_SENT
+
+#undef DEBUG
+
+/*
+ * Internal flag options for termios setting behavior
+ */
+#define TERMIOS_FLUSH  1
+#define TERMIOS_WAIT   2
+#define TERMIOS_TERMIO 4
+#define TERMIOS_OLD    8
+
+
+/**
+ *     tty_chars_in_buffer     -       characters pending
+ *     @tty: terminal
+ *
+ *     Return the number of bytes of data in the device private
+ *     output queue. If no private method is supplied there is assumed
+ *     to be no queue on the device.
+ */
+
+int tty_chars_in_buffer(struct tty_struct *tty)
+{
+       if (tty->ops->chars_in_buffer)
+               return tty->ops->chars_in_buffer(tty);
+       else
+               return 0;
+}
+EXPORT_SYMBOL(tty_chars_in_buffer);
+
+/**
+ *     tty_write_room          -       write queue space
+ *     @tty: terminal
+ *
+ *     Return the number of bytes that can be queued to this device
+ *     at the present time. The result should be treated as a guarantee
+ *     and the driver cannot offer a value it later shrinks by more than
+ *     the number of bytes written. If no method is provided 2K is always
+ *     returned and data may be lost as there will be no flow control.
+ */
+int tty_write_room(struct tty_struct *tty)
+{
+       if (tty->ops->write_room)
+               return tty->ops->write_room(tty);
+       return 2048;
+}
+EXPORT_SYMBOL(tty_write_room);
+
+/**
+ *     tty_driver_flush_buffer -       discard internal buffer
+ *     @tty: terminal
+ *
+ *     Discard the internal output buffer for this device. If no method
+ *     is provided then either the buffer cannot be hardware flushed or
+ *     there is no buffer driver side.
+ */
+void tty_driver_flush_buffer(struct tty_struct *tty)
+{
+       if (tty->ops->flush_buffer)
+               tty->ops->flush_buffer(tty);
+}
+EXPORT_SYMBOL(tty_driver_flush_buffer);
+
+/**
+ *     tty_throttle            -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty should stop transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ */
+
+void tty_throttle(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       /* check TTY_THROTTLED first so it indicates our state */
+       if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+           tty->ops->throttle)
+               tty->ops->throttle(tty);
+       mutex_unlock(&tty->termios_mutex);
+}
+EXPORT_SYMBOL(tty_throttle);
+
+/**
+ *     tty_unthrottle          -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty may continue transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ *
+ *     Drivers should however remember that the stack can issue a throttle,
+ *     then change flow control method, then unthrottle.
+ */
+
+void tty_unthrottle(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+           tty->ops->unthrottle)
+               tty->ops->unthrottle(tty);
+       mutex_unlock(&tty->termios_mutex);
+}
+EXPORT_SYMBOL(tty_unthrottle);
+
+/**
+ *     tty_wait_until_sent     -       wait for I/O to finish
+ *     @tty: tty we are waiting for
+ *     @timeout: how long we will wait
+ *
+ *     Wait for characters pending in a tty driver to hit the wire, or
+ *     for a timeout to occur (eg due to flow control)
+ *
+ *     Locking: none
+ */
+
+void tty_wait_until_sent(struct tty_struct *tty, long timeout)
+{
+#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
+       char buf[64];
+
+       printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
+#endif
+       if (!timeout)
+               timeout = MAX_SCHEDULE_TIMEOUT;
+       if (wait_event_interruptible_timeout(tty->write_wait,
+                       !tty_chars_in_buffer(tty), timeout) >= 0) {
+               if (tty->ops->wait_until_sent)
+                       tty->ops->wait_until_sent(tty, timeout);
+       }
+}
+EXPORT_SYMBOL(tty_wait_until_sent);
+
+
+/*
+ *             Termios Helper Methods
+ */
+
+static void unset_locked_termios(struct ktermios *termios,
+                                struct ktermios *old,
+                                struct ktermios *locked)
+{
+       int     i;
+
+#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
+
+       if (!locked) {
+               printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
+               return;
+       }
+
+       NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
+       NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
+       NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
+       NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
+       termios->c_line = locked->c_line ? old->c_line : termios->c_line;
+       for (i = 0; i < NCCS; i++)
+               termios->c_cc[i] = locked->c_cc[i] ?
+                       old->c_cc[i] : termios->c_cc[i];
+       /* FIXME: What should we do for i/ospeed */
+}
+
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static const speed_t baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+       76800, 153600, 307200, 614400, 921600
+#else
+       500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+       2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+#ifndef __sparc__
+static const tcflag_t baud_bits[] = {
+       B0, B50, B75, B110, B134, B150, B200, B300, B600,
+       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+       B57600, B115200, B230400, B460800, B500000, B576000,
+       B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
+       B3000000, B3500000, B4000000
+};
+#else
+static const tcflag_t baud_bits[] = {
+       B0, B50, B75, B110, B134, B150, B200, B300, B600,
+       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+       B57600, B115200, B230400, B460800, B76800, B153600,
+       B307200, B614400, B921600
+};
+#endif
+
+static int n_baud_table = ARRAY_SIZE(baud_table);
+
+/**
+ *     tty_termios_baud_rate
+ *     @termios: termios structure
+ *
+ *     Convert termios baud rate data into a speed. This should be called
+ *     with the termios lock held if this termios is a terminal termios
+ *     structure. May change the termios data. Device drivers can call this
+ *     function but should use ->c_[io]speed directly as they are updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_termios_baud_rate(struct ktermios *termios)
+{
+       unsigned int cbaud;
+
+       cbaud = termios->c_cflag & CBAUD;
+
+#ifdef BOTHER
+       /* Magic token for arbitary speed via c_ispeed/c_ospeed */
+       if (cbaud == BOTHER)
+               return termios->c_ospeed;
+#endif
+       if (cbaud & CBAUDEX) {
+               cbaud &= ~CBAUDEX;
+
+               if (cbaud < 1 || cbaud + 15 > n_baud_table)
+                       termios->c_cflag &= ~CBAUDEX;
+               else
+                       cbaud += 15;
+       }
+       return baud_table[cbaud];
+}
+EXPORT_SYMBOL(tty_termios_baud_rate);
+
+/**
+ *     tty_termios_input_baud_rate
+ *     @termios: termios structure
+ *
+ *     Convert termios baud rate data into a speed. This should be called
+ *     with the termios lock held if this termios is a terminal termios
+ *     structure. May change the termios data. Device drivers can call this
+ *     function but should use ->c_[io]speed directly as they are updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_termios_input_baud_rate(struct ktermios *termios)
+{
+#ifdef IBSHIFT
+       unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
+
+       if (cbaud == B0)
+               return tty_termios_baud_rate(termios);
+
+       /* Magic token for arbitary speed via c_ispeed*/
+       if (cbaud == BOTHER)
+               return termios->c_ispeed;
+
+       if (cbaud & CBAUDEX) {
+               cbaud &= ~CBAUDEX;
+
+               if (cbaud < 1 || cbaud + 15 > n_baud_table)
+                       termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
+               else
+                       cbaud += 15;
+       }
+       return baud_table[cbaud];
+#else
+       return tty_termios_baud_rate(termios);
+#endif
+}
+EXPORT_SYMBOL(tty_termios_input_baud_rate);
+
+/**
+ *     tty_termios_encode_baud_rate
+ *     @termios: ktermios structure holding user requested state
+ *     @ispeed: input speed
+ *     @ospeed: output speed
+ *
+ *     Encode the speeds set into the passed termios structure. This is
+ *     used as a library helper for drivers os that they can report back
+ *     the actual speed selected when it differs from the speed requested
+ *
+ *     For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
+ *     we need to carefully set the bits when the user does not get the
+ *     desired speed. We allow small margins and preserve as much of possible
+ *     of the input intent to keep compatibility.
+ *
+ *     Locking: Caller should hold termios lock. This is already held
+ *     when calling this function from the driver termios handler.
+ *
+ *     The ifdefs deal with platforms whose owners have yet to update them
+ *     and will all go away once this is done.
+ */
+
+void tty_termios_encode_baud_rate(struct ktermios *termios,
+                                 speed_t ibaud, speed_t obaud)
+{
+       int i = 0;
+       int ifound = -1, ofound = -1;
+       int iclose = ibaud/50, oclose = obaud/50;
+       int ibinput = 0;
+
+       if (obaud == 0)                 /* CD dropped             */
+               ibaud = 0;              /* Clear ibaud to be sure */
+
+       termios->c_ispeed = ibaud;
+       termios->c_ospeed = obaud;
+
+#ifdef BOTHER
+       /* If the user asked for a precise weird speed give a precise weird
+          answer. If they asked for a Bfoo speed they many have problems
+          digesting non-exact replies so fuzz a bit */
+
+       if ((termios->c_cflag & CBAUD) == BOTHER)
+               oclose = 0;
+       if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
+               iclose = 0;
+       if ((termios->c_cflag >> IBSHIFT) & CBAUD)
+               ibinput = 1;    /* An input speed was specified */
+#endif
+       termios->c_cflag &= ~CBAUD;
+
+       /*
+        *      Our goal is to find a close match to the standard baud rate
+        *      returned. Walk the baud rate table and if we get a very close
+        *      match then report back the speed as a POSIX Bxxxx value by
+        *      preference
+        */
+
+       do {
+               if (obaud - oclose <= baud_table[i] &&
+                   obaud + oclose >= baud_table[i]) {
+                       termios->c_cflag |= baud_bits[i];
+                       ofound = i;
+               }
+               if (ibaud - iclose <= baud_table[i] &&
+                   ibaud + iclose >= baud_table[i]) {
+                       /* For the case input == output don't set IBAUD bits
+                          if the user didn't do so */
+                       if (ofound == i && !ibinput)
+                               ifound  = i;
+#ifdef IBSHIFT
+                       else {
+                               ifound = i;
+                               termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+                       }
+#endif
+               }
+       } while (++i < n_baud_table);
+
+       /*
+        *      If we found no match then use BOTHER if provided or warn
+        *      the user their platform maintainer needs to wake up if not.
+        */
+#ifdef BOTHER
+       if (ofound == -1)
+               termios->c_cflag |= BOTHER;
+       /* Set exact input bits only if the input and output differ or the
+          user already did */
+       if (ifound == -1 && (ibaud != obaud || ibinput))
+               termios->c_cflag |= (BOTHER << IBSHIFT);
+#else
+       if (ifound == -1 || ofound == -1) {
+               printk_once(KERN_WARNING "tty: Unable to return correct "
+                         "speed data as your architecture needs updating.\n");
+       }
+#endif
+}
+EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+
+/**
+ *     tty_encode_baud_rate            -       set baud rate of the tty
+ *     @ibaud: input baud rate
+ *     @obad: output baud rate
+ *
+ *     Update the current termios data for the tty with the new speed
+ *     settings. The caller must hold the termios_mutex for the tty in
+ *     question.
+ */
+
+void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
+{
+       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+}
+EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
+
+/**
+ *     tty_get_baud_rate       -       get tty bit rates
+ *     @tty: tty to query
+ *
+ *     Returns the baud rate as an integer for this terminal. The
+ *     termios lock must be held by the caller and the terminal bit
+ *     flags may be updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_get_baud_rate(struct tty_struct *tty)
+{
+       speed_t baud = tty_termios_baud_rate(tty->termios);
+
+       if (baud == 38400 && tty->alt_speed) {
+               if (!tty->warned) {
+                       printk(KERN_WARNING "Use of setserial/setrocket to "
+                                           "set SPD_* flags is deprecated\n");
+                       tty->warned = 1;
+               }
+               baud = tty->alt_speed;
+       }
+
+       return baud;
+}
+EXPORT_SYMBOL(tty_get_baud_rate);
+
+/**
+ *     tty_termios_copy_hw     -       copy hardware settings
+ *     @new: New termios
+ *     @old: Old termios
+ *
+ *     Propogate the hardware specific terminal setting bits from
+ *     the old termios structure to the new one. This is used in cases
+ *     where the hardware does not support reconfiguration or as a helper
+ *     in some cases where only minimal reconfiguration is supported
+ */
+
+void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
+{
+       /* The bits a dumb device handles in software. Smart devices need
+          to always provide a set_termios method */
+       new->c_cflag &= HUPCL | CREAD | CLOCAL;
+       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
+       new->c_ispeed = old->c_ispeed;
+       new->c_ospeed = old->c_ospeed;
+}
+EXPORT_SYMBOL(tty_termios_copy_hw);
+
+/**
+ *     tty_termios_hw_change   -       check for setting change
+ *     @a: termios
+ *     @b: termios to compare
+ *
+ *     Check if any of the bits that affect a dumb device have changed
+ *     between the two termios structures, or a speed change is needed.
+ */
+
+int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
+{
+       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
+               return 1;
+       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(tty_termios_hw_change);
+
+/**
+ *     change_termios          -       update termios values
+ *     @tty: tty to update
+ *     @new_termios: desired new value
+ *
+ *     Perform updates to the termios values set on this terminal. There
+ *     is a bit of layering violation here with n_tty in terms of the
+ *     internal knowledge of this function.
+ *
+ *     Locking: termios_mutex
+ */
+
+static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
+{
+       struct ktermios old_termios;
+       struct tty_ldisc *ld;
+       unsigned long flags;
+
+       /*
+        *      Perform the actual termios internal changes under lock.
+        */
+
+
+       /* FIXME: we need to decide on some locking/ordering semantics
+          for the set_termios notification eventually */
+       mutex_lock(&tty->termios_mutex);
+       old_termios = *tty->termios;
+       *tty->termios = *new_termios;
+       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+
+       /* See if packet mode change of state. */
+       if (tty->link && tty->link->packet) {
+               int extproc = (old_termios.c_lflag & EXTPROC) |
+                               (tty->termios->c_lflag & EXTPROC);
+               int old_flow = ((old_termios.c_iflag & IXON) &&
+                               (old_termios.c_cc[VSTOP] == '\023') &&
+                               (old_termios.c_cc[VSTART] == '\021'));
+               int new_flow = (I_IXON(tty) &&
+                               STOP_CHAR(tty) == '\023' &&
+                               START_CHAR(tty) == '\021');
+               if ((old_flow != new_flow) || extproc) {
+                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       if (old_flow != new_flow) {
+                               tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+                               if (new_flow)
+                                       tty->ctrl_status |= TIOCPKT_DOSTOP;
+                               else
+                                       tty->ctrl_status |= TIOCPKT_NOSTOP;
+                       }
+                       if (extproc)
+                               tty->ctrl_status |= TIOCPKT_IOCTL;
+                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       wake_up_interruptible(&tty->link->read_wait);
+               }
+       }
+
+       if (tty->ops->set_termios)
+               (*tty->ops->set_termios)(tty, &old_termios);
+       else
+               tty_termios_copy_hw(tty->termios, &old_termios);
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if (ld->ops->set_termios)
+                       (ld->ops->set_termios)(tty, &old_termios);
+               tty_ldisc_deref(ld);
+       }
+       mutex_unlock(&tty->termios_mutex);
+}
+
+/**
+ *     set_termios             -       set termios values for a tty
+ *     @tty: terminal device
+ *     @arg: user data
+ *     @opt: option information
+ *
+ *     Helper function to prepare termios data and run necessary other
+ *     functions before using change_termios to do the actual changes.
+ *
+ *     Locking:
+ *             Called functions take ldisc and termios_mutex locks
+ */
+
+static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct ktermios tmp_termios;
+       struct tty_ldisc *ld;
+       int retval = tty_check_change(tty);
+
+       if (retval)
+               return retval;
+
+       mutex_lock(&tty->termios_mutex);
+       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+
+       if (opt & TERMIOS_TERMIO) {
+               if (user_termio_to_kernel_termios(&tmp_termios,
+                                               (struct termio __user *)arg))
+                       return -EFAULT;
+#ifdef TCGETS2
+       } else if (opt & TERMIOS_OLD) {
+               if (user_termios_to_kernel_termios_1(&tmp_termios,
+                                               (struct termios __user *)arg))
+                       return -EFAULT;
+       } else {
+               if (user_termios_to_kernel_termios(&tmp_termios,
+                                               (struct termios2 __user *)arg))
+                       return -EFAULT;
+       }
+#else
+       } else if (user_termios_to_kernel_termios(&tmp_termios,
+                                       (struct termios __user *)arg))
+               return -EFAULT;
+#endif
+
+       /* If old style Bfoo values are used then load c_ispeed/c_ospeed
+        * with the real speed so its unconditionally usable */
+       tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
+       tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
+
+       ld = tty_ldisc_ref(tty);
+
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       change_termios(tty, &tmp_termios);
+
+       /* FIXME: Arguably if tmp_termios == tty->termios AND the
+          actual requested termios was not tmp_termios then we may
+          want to return an error as no user requested change has
+          succeeded */
+       return 0;
+}
+
+static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static int get_termio(struct tty_struct *tty, struct termio __user *termio)
+{
+       struct ktermios kterm;
+       copy_termios(tty, &kterm);
+       if (kernel_termios_to_user_termio(termio, &kterm))
+               return -EFAULT;
+       return 0;
+}
+
+
+#ifdef TCGETX
+
+/**
+ *     set_termiox     -       set termiox fields if possible
+ *     @tty: terminal
+ *     @arg: termiox structure from user
+ *     @opt: option flags for ioctl type
+ *
+ *     Implement the device calling points for the SYS5 termiox ioctl
+ *     interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct termiox tnew;
+       struct tty_ldisc *ld;
+
+       if (tty->termiox == NULL)
+               return -EINVAL;
+       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+               return -EFAULT;
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       mutex_lock(&tty->termios_mutex);
+       if (tty->ops->set_termiox)
+               tty->ops->set_termiox(tty, &tnew);
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+#endif
+
+
+#ifdef TIOCGETP
+/*
+ * These are deprecated, but there is limited support..
+ *
+ * The "sg_flags" translation is a joke..
+ */
+static int get_sgflags(struct tty_struct *tty)
+{
+       int flags = 0;
+
+       if (!(tty->termios->c_lflag & ICANON)) {
+               if (tty->termios->c_lflag & ISIG)
+                       flags |= 0x02;          /* cbreak */
+               else
+                       flags |= 0x20;          /* raw */
+       }
+       if (tty->termios->c_lflag & ECHO)
+               flags |= 0x08;                  /* echo */
+       if (tty->termios->c_oflag & OPOST)
+               if (tty->termios->c_oflag & ONLCR)
+                       flags |= 0x10;          /* crmod */
+       return flags;
+}
+
+static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
+{
+       struct sgttyb tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.sg_ispeed = tty->termios->c_ispeed;
+       tmp.sg_ospeed = tty->termios->c_ospeed;
+       tmp.sg_erase = tty->termios->c_cc[VERASE];
+       tmp.sg_kill = tty->termios->c_cc[VKILL];
+       tmp.sg_flags = get_sgflags(tty);
+       mutex_unlock(&tty->termios_mutex);
+
+       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static void set_sgflags(struct ktermios *termios, int flags)
+{
+       termios->c_iflag = ICRNL | IXON;
+       termios->c_oflag = 0;
+       termios->c_lflag = ISIG | ICANON;
+       if (flags & 0x02) {     /* cbreak */
+               termios->c_iflag = 0;
+               termios->c_lflag &= ~ICANON;
+       }
+       if (flags & 0x08) {             /* echo */
+               termios->c_lflag |= ECHO | ECHOE | ECHOK |
+                                   ECHOCTL | ECHOKE | IEXTEN;
+       }
+       if (flags & 0x10) {             /* crmod */
+               termios->c_oflag |= OPOST | ONLCR;
+       }
+       if (flags & 0x20) {     /* raw */
+               termios->c_iflag = 0;
+               termios->c_lflag &= ~(ISIG | ICANON);
+       }
+       if (!(termios->c_lflag & ICANON)) {
+               termios->c_cc[VMIN] = 1;
+               termios->c_cc[VTIME] = 0;
+       }
+}
+
+/**
+ *     set_sgttyb              -       set legacy terminal values
+ *     @tty: tty structure
+ *     @sgttyb: pointer to old style terminal structure
+ *
+ *     Updates a terminal from the legacy BSD style terminal information
+ *     structure.
+ *
+ *     Locking: termios_mutex
+ */
+
+static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
+{
+       int retval;
+       struct sgttyb tmp;
+       struct ktermios termios;
+
+       retval = tty_check_change(tty);
+       if (retval)
+               return retval;
+
+       if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
+               return -EFAULT;
+
+       mutex_lock(&tty->termios_mutex);
+       termios = *tty->termios;
+       termios.c_cc[VERASE] = tmp.sg_erase;
+       termios.c_cc[VKILL] = tmp.sg_kill;
+       set_sgflags(&termios, tmp.sg_flags);
+       /* Try and encode into Bfoo format */
+#ifdef BOTHER
+       tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
+                                               termios.c_ospeed);
+#endif
+       mutex_unlock(&tty->termios_mutex);
+       change_termios(tty, &termios);
+       return 0;
+}
+#endif
+
+#ifdef TIOCGETC
+static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
+{
+       struct tchars tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.t_intrc = tty->termios->c_cc[VINTR];
+       tmp.t_quitc = tty->termios->c_cc[VQUIT];
+       tmp.t_startc = tty->termios->c_cc[VSTART];
+       tmp.t_stopc = tty->termios->c_cc[VSTOP];
+       tmp.t_eofc = tty->termios->c_cc[VEOF];
+       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+       mutex_unlock(&tty->termios_mutex);
+       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
+{
+       struct tchars tmp;
+
+       if (copy_from_user(&tmp, tchars, sizeof(tmp)))
+               return -EFAULT;
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_cc[VINTR] = tmp.t_intrc;
+       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
+       tty->termios->c_cc[VSTART] = tmp.t_startc;
+       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
+       tty->termios->c_cc[VEOF] = tmp.t_eofc;
+       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+#endif
+
+#ifdef TIOCGLTC
+static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
+{
+       struct ltchars tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.t_suspc = tty->termios->c_cc[VSUSP];
+       /* what is dsuspc anyway? */
+       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
+       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
+       /* what is flushc anyway? */
+       tmp.t_flushc = tty->termios->c_cc[VEOL2];
+       tmp.t_werasc = tty->termios->c_cc[VWERASE];
+       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+       mutex_unlock(&tty->termios_mutex);
+       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
+{
+       struct ltchars tmp;
+
+       if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
+               return -EFAULT;
+
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
+       /* what is dsuspc anyway? */
+       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
+       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
+       /* what is flushc anyway? */
+       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
+       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
+       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+#endif
+
+/**
+ *     send_prio_char          -       send priority character
+ *
+ *     Send a high priority character to the tty even if stopped
+ *
+ *     Locking: none for xchar method, write ordering for write method.
+ */
+
+static int send_prio_char(struct tty_struct *tty, char ch)
+{
+       int     was_stopped = tty->stopped;
+
+       if (tty->ops->send_xchar) {
+               tty->ops->send_xchar(tty, ch);
+               return 0;
+       }
+
+       if (tty_write_lock(tty, 0) < 0)
+               return -ERESTARTSYS;
+
+       if (was_stopped)
+               start_tty(tty);
+       tty->ops->write(tty, &ch, 1);
+       if (was_stopped)
+               stop_tty(tty);
+       tty_write_unlock(tty);
+       return 0;
+}
+
+/**
+ *     tty_change_softcar      -       carrier change ioctl helper
+ *     @tty: tty to update
+ *     @arg: enable/disable CLOCAL
+ *
+ *     Perform a change to the CLOCAL state and call into the driver
+ *     layer to make it visible. All done with the termios mutex
+ */
+
+static int tty_change_softcar(struct tty_struct *tty, int arg)
+{
+       int ret = 0;
+       int bit = arg ? CLOCAL : 0;
+       struct ktermios old;
+
+       mutex_lock(&tty->termios_mutex);
+       old = *tty->termios;
+       tty->termios->c_cflag &= ~CLOCAL;
+       tty->termios->c_cflag |= bit;
+       if (tty->ops->set_termios)
+               tty->ops->set_termios(tty, &old);
+       if ((tty->termios->c_cflag & CLOCAL) != bit)
+               ret = -EINVAL;
+       mutex_unlock(&tty->termios_mutex);
+       return ret;
+}
+
+/**
+ *     tty_mode_ioctl          -       mode related ioctls
+ *     @tty: tty for the ioctl
+ *     @file: file pointer for the tty
+ *     @cmd: command
+ *     @arg: ioctl argument
+ *
+ *     Perform non line discipline specific mode control ioctls. This
+ *     is designed to be called by line disciplines to ensure they provide
+ *     consistent mode setting.
+ */
+
+int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       struct tty_struct *real_tty;
+       void __user *p = (void __user *)arg;
+       int ret = 0;
+       struct ktermios kterm;
+
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               real_tty = tty->link;
+       else
+               real_tty = tty;
+
+       switch (cmd) {
+#ifdef TIOCGETP
+       case TIOCGETP:
+               return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
+       case TIOCSETP:
+       case TIOCSETN:
+               return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
+#endif
+#ifdef TIOCGETC
+       case TIOCGETC:
+               return get_tchars(real_tty, p);
+       case TIOCSETC:
+               return set_tchars(real_tty, p);
+#endif
+#ifdef TIOCGLTC
+       case TIOCGLTC:
+               return get_ltchars(real_tty, p);
+       case TIOCSLTC:
+               return set_ltchars(real_tty, p);
+#endif
+       case TCSETSF:
+               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+       case TCSETSW:
+               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+       case TCSETS:
+               return set_termios(real_tty, p, TERMIOS_OLD);
+#ifndef TCGETS2
+       case TCGETS:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+#else
+       case TCGETS:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TCGETS2:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TCSETSF2:
+               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
+       case TCSETSW2:
+               return set_termios(real_tty, p, TERMIOS_WAIT);
+       case TCSETS2:
+               return set_termios(real_tty, p, 0);
+#endif
+       case TCGETA:
+               return get_termio(real_tty, p);
+       case TCSETAF:
+               return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
+       case TCSETAW:
+               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
+       case TCSETA:
+               return set_termios(real_tty, p, TERMIOS_TERMIO);
+#ifndef TCGETS2
+       case TIOCGLCKTRMIOS:
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TIOCSLCKTRMIOS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios(&kterm,
+                                              (struct termios __user *) arg))
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               mutex_unlock(&real_tty->termios_mutex);
+               return 0;
+#else
+       case TIOCGLCKTRMIOS:
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TIOCSLCKTRMIOS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios_1(&kterm,
+                                              (struct termios __user *) arg))
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
+#endif
+#ifdef TCGETX
+       case TCGETX: {
+               struct termiox ktermx;
+               if (real_tty->termiox == NULL)
+                       return -EINVAL;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
+               mutex_unlock(&real_tty->termios_mutex);
+               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
+                       ret = -EFAULT;
+               return ret;
+       }
+       case TCSETX:
+               return set_termiox(real_tty, p, 0);
+       case TCSETXW:
+               return set_termiox(real_tty, p, TERMIOS_WAIT);
+       case TCSETXF:
+               return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif         
+       case TIOCGSOFTCAR:
+               copy_termios(real_tty, &kterm);
+               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
+                                               (int __user *)arg);
+               return ret;
+       case TIOCSSOFTCAR:
+               if (get_user(arg, (unsigned int __user *) arg))
+                       return -EFAULT;
+               return tty_change_softcar(real_tty, arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+EXPORT_SYMBOL_GPL(tty_mode_ioctl);
+
+int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
+{
+       struct tty_ldisc *ld;
+       int retval = tty_check_change(tty);
+       if (retval)
+               return retval;
+
+       ld = tty_ldisc_ref_wait(tty);
+       switch (arg) {
+       case TCIFLUSH:
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               break;
+       case TCIOFLUSH:
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               /* fall through */
+       case TCOFLUSH:
+               tty_driver_flush_buffer(tty);
+               break;
+       default:
+               tty_ldisc_deref(ld);
+               return -EINVAL;
+       }
+       tty_ldisc_deref(ld);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tty_perform_flush);
+
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       unsigned long flags;
+       int retval;
+
+       switch (cmd) {
+       case TCXONC:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               switch (arg) {
+               case TCOOFF:
+                       if (!tty->flow_stopped) {
+                               tty->flow_stopped = 1;
+                               stop_tty(tty);
+                       }
+                       break;
+               case TCOON:
+                       if (tty->flow_stopped) {
+                               tty->flow_stopped = 0;
+                               start_tty(tty);
+                       }
+                       break;
+               case TCIOFF:
+                       if (STOP_CHAR(tty) != __DISABLED_CHAR)
+                               return send_prio_char(tty, STOP_CHAR(tty));
+                       break;
+               case TCION:
+                       if (START_CHAR(tty) != __DISABLED_CHAR)
+                               return send_prio_char(tty, START_CHAR(tty));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       case TCFLSH:
+               return tty_perform_flush(tty, arg);
+       case TIOCPKT:
+       {
+               int pktmode;
+
+               if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
+                   tty->driver->subtype != PTY_TYPE_MASTER)
+                       return -ENOTTY;
+               if (get_user(pktmode, (int __user *) arg))
+                       return -EFAULT;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               if (pktmode) {
+                       if (!tty->packet) {
+                               tty->packet = 1;
+                               tty->link->ctrl_status = 0;
+                       }
+               } else
+                       tty->packet = 0;
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return 0;
+       }
+       default:
+               /* Try the mode commands */
+               return tty_mode_ioctl(tty, file, cmd, arg);
+       }
+}
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
new file mode 100644 (file)
index 0000000..d8e96b0
--- /dev/null
@@ -0,0 +1,950 @@
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/smp_lock.h>    /* For the moment */
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+/*
+ *     This guards the refcounted line discipline lists. The lock
+ *     must be taken with irqs off because there are hangup path
+ *     callers who will do ldisc lookups and cannot sleep.
+ */
+
+static DEFINE_SPINLOCK(tty_ldisc_lock);
+static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
+/* Line disc dispatch table */
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+
+static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
+{
+       if (ld)
+               atomic_inc(&ld->users);
+       return ld;
+}
+
+static void put_ldisc(struct tty_ldisc *ld)
+{
+       unsigned long flags;
+
+       if (WARN_ON_ONCE(!ld))
+               return;
+
+       /*
+        * If this is the last user, free the ldisc, and
+        * release the ldisc ops.
+        *
+        * We really want an "atomic_dec_and_lock_irqsave()",
+        * but we don't have it, so this does it by hand.
+        */
+       local_irq_save(flags);
+       if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
+               struct tty_ldisc_ops *ldo = ld->ops;
+
+               ldo->refcount--;
+               module_put(ldo->owner);
+               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+               kfree(ld);
+               return;
+       }
+       local_irq_restore(flags);
+       wake_up(&tty_ldisc_idle);
+}
+
+/**
+ *     tty_register_ldisc      -       install a line discipline
+ *     @disc: ldisc number
+ *     @new_ldisc: pointer to the ldisc object
+ *
+ *     Installs a new line discipline into the kernel. The discipline
+ *     is set up as unreferenced and then made available to the kernel
+ *     from this point onwards.
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       tty_ldiscs[disc] = new_ldisc;
+       new_ldisc->num = disc;
+       new_ldisc->refcount = 0;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(tty_register_ldisc);
+
+/**
+ *     tty_unregister_ldisc    -       unload a line discipline
+ *     @disc: ldisc number
+ *     @new_ldisc: pointer to the ldisc object
+ *
+ *     Remove a line discipline from the kernel providing it is not
+ *     currently in use.
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_unregister_ldisc(int disc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       if (tty_ldiscs[disc]->refcount)
+               ret = -EBUSY;
+       else
+               tty_ldiscs[disc] = NULL;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(tty_unregister_ldisc);
+
+static struct tty_ldisc_ops *get_ldops(int disc)
+{
+       unsigned long flags;
+       struct tty_ldisc_ops *ldops, *ret;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ret = ERR_PTR(-EINVAL);
+       ldops = tty_ldiscs[disc];
+       if (ldops) {
+               ret = ERR_PTR(-EAGAIN);
+               if (try_module_get(ldops->owner)) {
+                       ldops->refcount++;
+                       ret = ldops;
+               }
+       }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ret;
+}
+
+static void put_ldops(struct tty_ldisc_ops *ldops)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ldops->refcount--;
+       module_put(ldops->owner);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+/**
+ *     tty_ldisc_get           -       take a reference to an ldisc
+ *     @disc: ldisc number
+ *
+ *     Takes a reference to a line discipline. Deals with refcounts and
+ *     module locking counts. Returns NULL if the discipline is not available.
+ *     Returns a pointer to the discipline and bumps the ref count if it is
+ *     available
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+static struct tty_ldisc *tty_ldisc_get(int disc)
+{
+       struct tty_ldisc *ld;
+       struct tty_ldisc_ops *ldops;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * Get the ldisc ops - we may need to request them to be loaded
+        * dynamically and try again.
+        */
+       ldops = get_ldops(disc);
+       if (IS_ERR(ldops)) {
+               request_module("tty-ldisc-%d", disc);
+               ldops = get_ldops(disc);
+               if (IS_ERR(ldops))
+                       return ERR_CAST(ldops);
+       }
+
+       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
+       if (ld == NULL) {
+               put_ldops(ldops);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ld->ops = ldops;
+       atomic_set(&ld->users, 1);
+       return ld;
+}
+
+static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+{
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+       int i = *(loff_t *)v;
+       struct tty_ldisc_ops *ldops;
+
+       ldops = get_ldops(i);
+       if (IS_ERR(ldops))
+               return 0;
+       seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
+       put_ldops(ldops);
+       return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+       .start  = tty_ldiscs_seq_start,
+       .next   = tty_ldiscs_seq_next,
+       .stop   = tty_ldiscs_seq_stop,
+       .show   = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+const struct file_operations tty_ldiscs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = proc_tty_ldiscs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/**
+ *     tty_ldisc_assign        -       set ldisc on a tty
+ *     @tty: tty to assign
+ *     @ld: line discipline
+ *
+ *     Install an instance of a line discipline into a tty structure. The
+ *     ldisc must have a reference count above zero to ensure it remains.
+ *     The tty instance refcount starts at zero.
+ *
+ *     Locking:
+ *             Caller must hold references
+ */
+
+static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       tty->ldisc = ld;
+}
+
+/**
+ *     tty_ldisc_try           -       internal helper
+ *     @tty: the tty
+ *
+ *     Make a single attempt to grab and bump the refcount on
+ *     the tty ldisc. Return 0 on failure or 1 on success. This is
+ *     used to implement both the waiting and non waiting versions
+ *     of tty_ldisc_ref
+ *
+ *     Locking: takes tty_ldisc_lock
+ */
+
+static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct tty_ldisc *ld;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ld = NULL;
+       if (test_bit(TTY_LDISC, &tty->flags))
+               ld = get_ldisc(tty->ldisc);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ld;
+}
+
+/**
+ *     tty_ldisc_ref_wait      -       wait for the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     wait patiently until it changes.
+ *
+ *     Note: Must not be called from an IRQ/timer context. The caller
+ *     must also be careful not to hold other locks that will deadlock
+ *     against a discipline change, such as an existing ldisc reference
+ *     (which we check for)
+ *
+ *     Locking: call functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       /* wait_event is a macro */
+       wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
+       return ld;
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
+
+/**
+ *     tty_ldisc_ref           -       get the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     return NULL. Can be called from IRQ and timer functions.
+ *
+ *     Locking: called functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
+{
+       return tty_ldisc_try(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_ref);
+
+/**
+ *     tty_ldisc_deref         -       free a tty ldisc reference
+ *     @ld: reference to free up
+ *
+ *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
+ *     be called in IRQ context.
+ *
+ *     Locking: takes tty_ldisc_lock
+ */
+
+void tty_ldisc_deref(struct tty_ldisc *ld)
+{
+       put_ldisc(ld);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+
+static inline void tty_ldisc_put(struct tty_ldisc *ld)
+{
+       put_ldisc(ld);
+}
+
+/**
+ *     tty_ldisc_enable        -       allow ldisc use
+ *     @tty: terminal to activate ldisc on
+ *
+ *     Set the TTY_LDISC flag when the line discipline can be called
+ *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
+ *     changing flag to indicate any ldisc change is now over.
+ *
+ *     Note: nobody should set the TTY_LDISC bit except via this function.
+ *     Clearing directly is allowed.
+ */
+
+void tty_ldisc_enable(struct tty_struct *tty)
+{
+       set_bit(TTY_LDISC, &tty->flags);
+       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+       wake_up(&tty_ldisc_wait);
+}
+
+/**
+ *     tty_ldisc_flush -       flush line discipline queue
+ *     @tty: tty
+ *
+ *     Flush the line discipline queue (if any) for this tty. If there
+ *     is no line discipline active this is a no-op.
+ */
+
+void tty_ldisc_flush(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       tty_buffer_flush(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
+/**
+ *     tty_set_termios_ldisc           -       set ldisc field
+ *     @tty: tty structure
+ *     @num: line discipline number
+ *
+ *     This is probably overkill for real world processors but
+ *     they are not on hot paths so a little discipline won't do
+ *     any harm.
+ *
+ *     Locking: takes termios_mutex
+ */
+
+static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+{
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_line = num;
+       mutex_unlock(&tty->termios_mutex);
+}
+
+/**
+ *     tty_ldisc_open          -       open a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to open
+ *
+ *     A helper opening method. Also a convenient debugging and check
+ *     point.
+ *
+ *     Locking: always called with BTM already held.
+ */
+
+static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
+       if (ld->ops->open) {
+               int ret;
+                /* BTM here locks versus a hangup event */
+               WARN_ON(!tty_locked());
+               ret = ld->ops->open(tty);
+               return ret;
+       }
+       return 0;
+}
+
+/**
+ *     tty_ldisc_close         -       close a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to close
+ *
+ *     A helper close method. Also a convenient debugging and check
+ *     point.
+ */
+
+static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
+       clear_bit(TTY_LDISC_OPEN, &tty->flags);
+       if (ld->ops->close)
+               ld->ops->close(tty);
+}
+
+/**
+ *     tty_ldisc_restore       -       helper for tty ldisc change
+ *     @tty: tty to recover
+ *     @old: previous ldisc
+ *
+ *     Restore the previous line discipline or N_TTY when a line discipline
+ *     change fails due to an open error
+ */
+
+static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
+{
+       char buf[64];
+       struct tty_ldisc *new_ldisc;
+       int r;
+
+       /* There is an outstanding reference here so this is safe */
+       old = tty_ldisc_get(old->ops->num);
+       WARN_ON(IS_ERR(old));
+       tty_ldisc_assign(tty, old);
+       tty_set_termios_ldisc(tty, old->ops->num);
+       if (tty_ldisc_open(tty, old) < 0) {
+               tty_ldisc_put(old);
+               /* This driver is always present */
+               new_ldisc = tty_ldisc_get(N_TTY);
+               if (IS_ERR(new_ldisc))
+                       panic("n_tty: get");
+               tty_ldisc_assign(tty, new_ldisc);
+               tty_set_termios_ldisc(tty, N_TTY);
+               r = tty_ldisc_open(tty, new_ldisc);
+               if (r < 0)
+                       panic("Couldn't open N_TTY ldisc for "
+                             "%s --- error %d.",
+                             tty_name(tty, buf), r);
+       }
+}
+
+/**
+ *     tty_ldisc_halt          -       shut down the line discipline
+ *     @tty: tty device
+ *
+ *     Shut down the line discipline and work queue for this tty device.
+ *     The TTY_LDISC flag being cleared ensures no further references can
+ *     be obtained while the delayed work queue halt ensures that no more
+ *     data is fed to the ldisc.
+ *
+ *     You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
+ *     in order to make sure any currently executing ldisc work is also
+ *     flushed.
+ */
+
+static int tty_ldisc_halt(struct tty_struct *tty)
+{
+       clear_bit(TTY_LDISC, &tty->flags);
+       return cancel_delayed_work_sync(&tty->buf.work);
+}
+
+/**
+ *     tty_ldisc_wait_idle     -       wait for the ldisc to become idle
+ *     @tty: tty to wait for
+ *
+ *     Wait for the line discipline to become idle. The discipline must
+ *     have been halted for this to guarantee it remains idle.
+ */
+static int tty_ldisc_wait_idle(struct tty_struct *tty)
+{
+       int ret;
+       ret = wait_event_interruptible_timeout(tty_ldisc_idle,
+                       atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+       if (ret < 0)
+               return ret;
+       return ret > 0 ? 0 : -EBUSY;
+}
+
+/**
+ *     tty_set_ldisc           -       set line discipline
+ *     @tty: the terminal to set
+ *     @ldisc: the line discipline
+ *
+ *     Set the discipline of a tty line. Must be called from a process
+ *     context. The ldisc change logic has to protect itself against any
+ *     overlapping ldisc change (including on the other end of pty pairs),
+ *     the close of one side of a tty/pty pair, and eventually hangup.
+ *
+ *     Locking: takes tty_ldisc_lock, termios_mutex
+ */
+
+int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+{
+       int retval;
+       struct tty_ldisc *o_ldisc, *new_ldisc;
+       int work, o_work = 0;
+       struct tty_struct *o_tty;
+
+       new_ldisc = tty_ldisc_get(ldisc);
+       if (IS_ERR(new_ldisc))
+               return PTR_ERR(new_ldisc);
+
+       tty_lock();
+       /*
+        *      We need to look at the tty locking here for pty/tty pairs
+        *      when both sides try to change in parallel.
+        */
+
+       o_tty = tty->link;      /* o_tty is the pty side or NULL */
+
+
+       /*
+        *      Check the no-op case
+        */
+
+       if (tty->ldisc->ops->num == ldisc) {
+               tty_unlock();
+               tty_ldisc_put(new_ldisc);
+               return 0;
+       }
+
+       tty_unlock();
+       /*
+        *      Problem: What do we do if this blocks ?
+        *      We could deadlock here
+        */
+
+       tty_wait_until_sent(tty, 0);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        *      We could be midstream of another ldisc change which has
+        *      dropped the lock during processing. If so we need to wait.
+        */
+
+       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_unlock();
+               wait_event(tty_ldisc_wait,
+                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
+               tty_lock();
+               mutex_lock(&tty->ldisc_mutex);
+       }
+
+       set_bit(TTY_LDISC_CHANGING, &tty->flags);
+
+       /*
+        *      No more input please, we are switching. The new ldisc
+        *      will update this value in the ldisc open function
+        */
+
+       tty->receive_room = 0;
+
+       o_ldisc = tty->ldisc;
+
+       tty_unlock();
+       /*
+        *      Make sure we don't change while someone holds a
+        *      reference to the line discipline. The TTY_LDISC bit
+        *      prevents anyone taking a reference once it is clear.
+        *      We need the lock to avoid racing reference takers.
+        *
+        *      We must clear the TTY_LDISC bit here to avoid a livelock
+        *      with a userspace app continually trying to use the tty in
+        *      parallel to the change and re-referencing the tty.
+        */
+
+       work = tty_ldisc_halt(tty);
+       if (o_tty)
+               o_work = tty_ldisc_halt(o_tty);
+
+       /*
+        * Wait for ->hangup_work and ->buf.work handlers to terminate.
+        * We must drop the mutex here in case a hangup is also in process.
+        */
+
+       mutex_unlock(&tty->ldisc_mutex);
+
+       flush_scheduled_work();
+
+       retval = tty_ldisc_wait_idle(tty);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /* handle wait idle failure locked */
+       if (retval) {
+               tty_ldisc_put(new_ldisc);
+               goto enable;
+       }
+
+       if (test_bit(TTY_HUPPED, &tty->flags)) {
+               /* We were raced by the hangup method. It will have stomped
+                  the ldisc data and closed the ldisc down */
+               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_ldisc_put(new_ldisc);
+               tty_unlock();
+               return -EIO;
+       }
+
+       /* Shutdown the current discipline. */
+       tty_ldisc_close(tty, o_ldisc);
+
+       /* Now set up the new line discipline. */
+       tty_ldisc_assign(tty, new_ldisc);
+       tty_set_termios_ldisc(tty, ldisc);
+
+       retval = tty_ldisc_open(tty, new_ldisc);
+       if (retval < 0) {
+               /* Back to the old one or N_TTY if we can't */
+               tty_ldisc_put(new_ldisc);
+               tty_ldisc_restore(tty, o_ldisc);
+       }
+
+       /* At this point we hold a reference to the new ldisc and a
+          a reference to the old ldisc. If we ended up flipping back
+          to the existing ldisc we have two references to it */
+
+       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
+               tty->ops->set_ldisc(tty);
+
+       tty_ldisc_put(o_ldisc);
+
+enable:
+       /*
+        *      Allow ldisc referencing to occur again
+        */
+
+       tty_ldisc_enable(tty);
+       if (o_tty)
+               tty_ldisc_enable(o_tty);
+
+       /* Restart the work queue in case no characters kick it off. Safe if
+          already running */
+       if (work)
+               schedule_delayed_work(&tty->buf.work, 1);
+       if (o_work)
+               schedule_delayed_work(&o_tty->buf.work, 1);
+       mutex_unlock(&tty->ldisc_mutex);
+       tty_unlock();
+       return retval;
+}
+
+/**
+ *     tty_reset_termios       -       reset terminal state
+ *     @tty: tty to reset
+ *
+ *     Restore a terminal to the driver default state.
+ */
+
+static void tty_reset_termios(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       *tty->termios = tty->driver->init_termios;
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       mutex_unlock(&tty->termios_mutex);
+}
+
+
+/**
+ *     tty_ldisc_reinit        -       reinitialise the tty ldisc
+ *     @tty: tty to reinit
+ *     @ldisc: line discipline to reinitialize
+ *
+ *     Switch the tty to a line discipline and leave the ldisc
+ *     state closed
+ */
+
+static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+{
+       struct tty_ldisc *ld = tty_ldisc_get(ldisc);
+
+       if (IS_ERR(ld))
+               return -1;
+
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       tty->ldisc = NULL;
+       /*
+        *      Switch the line discipline back
+        */
+       tty_ldisc_assign(tty, ld);
+       tty_set_termios_ldisc(tty, ldisc);
+
+       return 0;
+}
+
+/**
+ *     tty_ldisc_hangup                -       hangup ldisc reset
+ *     @tty: tty being hung up
+ *
+ *     Some tty devices reset their termios when they receive a hangup
+ *     event. In that situation we must also switch back to N_TTY properly
+ *     before we reset the termios data.
+ *
+ *     Locking: We can take the ldisc mutex as the rest of the code is
+ *     careful to allow for this.
+ *
+ *     In the pty pair case this occurs in the close() path of the
+ *     tty itself so we must be careful about locking rules.
+ */
+
+void tty_ldisc_hangup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+       int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
+       int err = 0;
+
+       /*
+        * FIXME! What are the locking issues here? This may me overdoing
+        * things... This question is especially important now that we've
+        * removed the irqlock.
+        */
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               /* We may have no line discipline at this point */
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+                   ld->ops->write_wakeup)
+                       ld->ops->write_wakeup(tty);
+               if (ld->ops->hangup)
+                       ld->ops->hangup(tty);
+               tty_ldisc_deref(ld);
+       }
+       /*
+        * FIXME: Once we trust the LDISC code better we can wait here for
+        * ldisc completion and fix the driver call race
+        */
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+       /*
+        * Shutdown the current line discipline, and reset it to
+        * N_TTY if need be.
+        *
+        * Avoid racing set_ldisc or tty_ldisc_release
+        */
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        * this is like tty_ldisc_halt, but we need to give up
+        * the BTM before calling cancel_delayed_work_sync,
+        * which may need to wait for another function taking the BTM
+        */
+       clear_bit(TTY_LDISC, &tty->flags);
+       tty_unlock();
+       cancel_delayed_work_sync(&tty->buf.work);
+       mutex_unlock(&tty->ldisc_mutex);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /* At this point we have a closed ldisc and we want to
+          reopen it. We could defer this to the next open but
+          it means auditing a lot of other paths so this is
+          a FIXME */
+       if (tty->ldisc) {       /* Not yet closed */
+               if (reset == 0) {
+
+                       if (!tty_ldisc_reinit(tty, tty->termios->c_line))
+                               err = tty_ldisc_open(tty, tty->ldisc);
+                       else
+                               err = 1;
+               }
+               /* If the re-open fails or we reset then go to N_TTY. The
+                  N_TTY open cannot fail */
+               if (reset || err) {
+                       BUG_ON(tty_ldisc_reinit(tty, N_TTY));
+                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+               }
+               tty_ldisc_enable(tty);
+       }
+       mutex_unlock(&tty->ldisc_mutex);
+       if (reset)
+               tty_reset_termios(tty);
+}
+
+/**
+ *     tty_ldisc_setup                 -       open line discipline
+ *     @tty: tty being shut down
+ *     @o_tty: pair tty for pty/tty pairs
+ *
+ *     Called during the initial open of a tty/pty pair in order to set up the
+ *     line disciplines and bind them to the tty. This has no locking issues
+ *     as the device isn't yet active.
+ */
+
+int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+       struct tty_ldisc *ld = tty->ldisc;
+       int retval;
+
+       retval = tty_ldisc_open(tty, ld);
+       if (retval)
+               return retval;
+
+       if (o_tty) {
+               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
+               if (retval) {
+                       tty_ldisc_close(tty, ld);
+                       return retval;
+               }
+               tty_ldisc_enable(o_tty);
+       }
+       tty_ldisc_enable(tty);
+       return 0;
+}
+/**
+ *     tty_ldisc_release               -       release line discipline
+ *     @tty: tty being shut down
+ *     @o_tty: pair tty for pty/tty pairs
+ *
+ *     Called during the final close of a tty/pty pair in order to shut down
+ *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
+ *     ldisc has not been opened.
+ */
+
+void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+       /*
+        * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
+        * kill any delayed work. As this is the final close it does not
+        * race with the set_ldisc code path.
+        */
+
+       tty_unlock();
+       tty_ldisc_halt(tty);
+       flush_scheduled_work();
+       tty_lock();
+
+       mutex_lock(&tty->ldisc_mutex);
+       /*
+        * Now kill off the ldisc
+        */
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       /* Force an oops if we mess this up */
+       tty->ldisc = NULL;
+
+       /* Ensure the next open requests the N_TTY ldisc */
+       tty_set_termios_ldisc(tty, N_TTY);
+       mutex_unlock(&tty->ldisc_mutex);
+
+       /* This will need doing differently if we need to lock */
+       if (o_tty)
+               tty_ldisc_release(o_tty, NULL);
+
+       /* And the memory resources remaining (buffers, termios) will be
+          disposed of when the kref hits zero */
+}
+
+/**
+ *     tty_ldisc_init          -       ldisc setup for new tty
+ *     @tty: tty being allocated
+ *
+ *     Set up the line discipline objects for a newly allocated tty. Note that
+ *     the tty structure is not completely set up when this call is made.
+ */
+
+void tty_ldisc_init(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
+       if (IS_ERR(ld))
+               panic("n_tty: init_tty");
+       tty_ldisc_assign(tty, ld);
+}
+
+void tty_ldisc_begin(void)
+{
+       /* Setup the default TTY line discipline. */
+       (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+}
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
new file mode 100644 (file)
index 0000000..1336975
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * drivers/char/tty_lock.c
+ */
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+
+/*
+ * The 'big tty mutex'
+ *
+ * This mutex is taken and released by tty_lock() and tty_unlock(),
+ * replacing the older big kernel lock.
+ * It can no longer be taken recursively, and does not get
+ * released implicitly while sleeping.
+ *
+ * Don't use in new code.
+ */
+static DEFINE_MUTEX(big_tty_mutex);
+struct task_struct *__big_tty_mutex_owner;
+EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
+
+/*
+ * Getting the big tty mutex.
+ */
+void __lockfunc tty_lock(void)
+{
+       struct task_struct *task = current;
+
+       WARN_ON(__big_tty_mutex_owner == task);
+
+       mutex_lock(&big_tty_mutex);
+       __big_tty_mutex_owner = task;
+}
+EXPORT_SYMBOL(tty_lock);
+
+void __lockfunc tty_unlock(void)
+{
+       struct task_struct *task = current;
+
+       WARN_ON(__big_tty_mutex_owner != task);
+       __big_tty_mutex_owner = NULL;
+
+       mutex_unlock(&big_tty_mutex);
+}
+EXPORT_SYMBOL(tty_unlock);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
new file mode 100644 (file)
index 0000000..33d37d2
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+       memset(port, 0, sizeof(*port));
+       init_waitqueue_head(&port->open_wait);
+       init_waitqueue_head(&port->close_wait);
+       init_waitqueue_head(&port->delta_msr_wait);
+       mutex_init(&port->mutex);
+       mutex_init(&port->buf_mutex);
+       spin_lock_init(&port->lock);
+       port->close_delay = (50 * HZ) / 100;
+       port->closing_wait = (3000 * HZ) / 100;
+       kref_init(&port->kref);
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+       /* We may sleep in get_zeroed_page() */
+       mutex_lock(&port->buf_mutex);
+       if (port->xmit_buf == NULL)
+               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+       mutex_unlock(&port->buf_mutex);
+       if (port->xmit_buf == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+       mutex_lock(&port->buf_mutex);
+       if (port->xmit_buf != NULL) {
+               free_page((unsigned long)port->xmit_buf);
+               port->xmit_buf = NULL;
+       }
+       mutex_unlock(&port->buf_mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+static void tty_port_destructor(struct kref *kref)
+{
+       struct tty_port *port = container_of(kref, struct tty_port, kref);
+       if (port->xmit_buf)
+               free_page((unsigned long)port->xmit_buf);
+       if (port->ops->destruct)
+               port->ops->destruct(port);
+       else
+               kfree(port);
+}
+
+void tty_port_put(struct tty_port *port)
+{
+       if (port)
+               kref_put(&port->kref, tty_port_destructor);
+}
+EXPORT_SYMBOL(tty_port_put);
+
+/**
+ *     tty_port_tty_get        -       get a tty reference
+ *     @port: tty port
+ *
+ *     Return a refcount protected tty instance or NULL if the port is not
+ *     associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = tty_kref_get(port->tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *     tty_port_tty_set        -       set the tty of a port
+ *     @port: tty port
+ *     @tty: the tty
+ *
+ *     Associate the port and tty pair. Manages any internal refcounts.
+ *     Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (port->tty)
+               tty_kref_put(port->tty);
+       port->tty = tty_kref_get(tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
+
+static void tty_port_shutdown(struct tty_port *port)
+{
+       mutex_lock(&port->mutex);
+       if (port->ops->shutdown && !port->console &&
+               test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
+                       port->ops->shutdown(port);
+       mutex_unlock(&port->mutex);
+}
+
+/**
+ *     tty_port_hangup         -       hangup helper
+ *     @port: tty port
+ *
+ *     Perform port level tty hangup flag and count changes. Drop the tty
+ *     reference.
+ */
+
+void tty_port_hangup(struct tty_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->count = 0;
+       port->flags &= ~ASYNC_NORMAL_ACTIVE;
+       if (port->tty) {
+               set_bit(TTY_IO_ERROR, &port->tty->flags);
+               tty_kref_put(port->tty);
+       }
+       port->tty = NULL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       wake_up_interruptible(&port->open_wait);
+       wake_up_interruptible(&port->delta_msr_wait);
+       tty_port_shutdown(port);
+}
+EXPORT_SYMBOL(tty_port_hangup);
+
+/**
+ *     tty_port_carrier_raised -       carrier raised check
+ *     @port: tty port
+ *
+ *     Wrapper for the carrier detect logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+int tty_port_carrier_raised(struct tty_port *port)
+{
+       if (port->ops->carrier_raised == NULL)
+               return 1;
+       return port->ops->carrier_raised(port);
+}
+EXPORT_SYMBOL(tty_port_carrier_raised);
+
+/**
+ *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_raise_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 1);
+}
+EXPORT_SYMBOL(tty_port_raise_dtr_rts);
+
+/**
+ *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_lower_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 0);
+}
+EXPORT_SYMBOL(tty_port_lower_dtr_rts);
+
+/**
+ *     tty_port_block_til_ready        -       Waiting logic for tty open
+ *     @port: the tty port being opened
+ *     @tty: the tty device being bound
+ *     @filp: the file pointer of the opener
+ *
+ *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
+ *     Handles:
+ *             - hangup (both before and during)
+ *             - non blocking open
+ *             - rts/dtr/dcd
+ *             - signals
+ *             - port flags and counts
+ *
+ *     The passed tty_port must implement the carrier_raised method if it can
+ *     do carrier detect and the dtr_rts method if it supports software
+ *     management of these lines. Note that the dtr/rts raise is done each
+ *     iteration as a hangup may have previously dropped them while we wait.
+ */
+
+int tty_port_block_til_ready(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       int do_clocal = 0, retval;
+       unsigned long flags;
+       DEFINE_WAIT(wait);
+       int cd;
+
+       /* block if port is in the process of being closed */
+       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+               wait_event_interruptible_tty(port->close_wait,
+                               !(port->flags & ASYNC_CLOSING));
+               if (port->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+       }
+
+       /* if non-blocking mode is set we can pass directly to open unless
+          the port has just hung up or is in another error state */
+       if (tty->flags & (1 << TTY_IO_ERROR)) {
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+       if (filp->f_flags & O_NONBLOCK) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (C_CLOCAL(tty))
+               do_clocal = 1;
+
+       /* Block waiting until we can proceed. We may need to wait for the
+          carrier, but we must also wait for any close that is in progress
+          before the next open may complete */
+
+       retval = 0;
+
+       /* The port lock protects the port counts */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count--;
+       port->blocked_open++;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       while (1) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+
+               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
+               /* Check for a hangup or uninitialised port.
+                                                       Return accordingly */
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+                       if (port->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+                       break;
+               }
+               /* Probe the carrier. For devices with no carrier detect this
+                  will always return true */
+               cd = tty_port_carrier_raised(port);
+               if (!(port->flags & ASYNC_CLOSING) &&
+                               (do_clocal || cd))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       finish_wait(&port->open_wait, &wait);
+
+       /* Update counts. A parallel hangup will have set count to zero and
+          we must not mess that up further */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count++;
+       port->blocked_open--;
+       if (retval == 0)
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+       spin_unlock_irqrestore(&port->lock, flags);
+       return retval;
+}
+EXPORT_SYMBOL(tty_port_block_til_ready);
+
+int tty_port_close_start(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (tty_hung_up_p(filp)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return 0;
+       }
+
+       if (tty->count == 1 && port->count != 1) {
+               printk(KERN_WARNING
+                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
+                                                               port->count);
+               port->count = 1;
+       }
+       if (--port->count < 0) {
+               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
+                                                               port->count);
+               port->count = 0;
+       }
+
+       if (port->count) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->ops->drop)
+                       port->ops->drop(port);
+               return 0;
+       }
+       set_bit(ASYNCB_CLOSING, &port->flags);
+       tty->closing = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+       /* Don't block on a stalled port, just pull the chain */
+       if (tty->flow_stopped)
+               tty_driver_flush_buffer(tty);
+       if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
+                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, port->closing_wait);
+       if (port->drain_delay) {
+               unsigned int bps = tty_get_baud_rate(tty);
+               long timeout;
+
+               if (bps > 1200)
+                       timeout = max_t(long,
+                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
+               else
+                       timeout = 2 * HZ;
+               schedule_timeout_interruptible(timeout);
+       }
+       /* Flush the ldisc buffering */
+       tty_ldisc_flush(tty);
+
+       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
+          hang up the line */
+       if (tty->termios->c_cflag & HUPCL)
+               tty_port_lower_dtr_rts(port);
+
+       /* Don't call port->drop for the last reference. Callers will want
+          to drop the last active reference in ->shutdown() or the tty
+          shutdown path */
+       return 1;
+}
+EXPORT_SYMBOL(tty_port_close_start);
+
+void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty->closing = 0;
+
+       if (port->blocked_open) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->close_delay) {
+                       msleep_interruptible(
+                               jiffies_to_msecs(port->close_delay));
+               }
+               spin_lock_irqsave(&port->lock, flags);
+               wake_up_interruptible(&port->open_wait);
+       }
+       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       wake_up_interruptible(&port->close_wait);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_close_end);
+
+void tty_port_close(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       if (tty_port_close_start(port, tty, filp) == 0)
+               return;
+       tty_port_shutdown(port);
+       set_bit(TTY_IO_ERROR, &tty->flags);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
+}
+EXPORT_SYMBOL(tty_port_close);
+
+int tty_port_open(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       spin_lock_irq(&port->lock);
+       if (!tty_hung_up_p(filp))
+               ++port->count;
+       spin_unlock_irq(&port->lock);
+       tty_port_tty_set(port, tty);
+
+       /*
+        * Do the device-specific open only if the hardware isn't
+        * already initialized. Serialize open and shutdown using the
+        * port mutex.
+        */
+
+       mutex_lock(&port->mutex);
+
+       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+               if (port->ops->activate) {
+                       int retval = port->ops->activate(port, tty);
+                       if (retval) {
+                               mutex_unlock(&port->mutex);
+                               return retval;
+                       }
+               }
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+       }
+       mutex_unlock(&port->mutex);
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore
new file mode 100644 (file)
index 0000000..83683a2
--- /dev/null
@@ -0,0 +1,2 @@
+consolemap_deftbl.c
+defkeymap.c
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
new file mode 100644 (file)
index 0000000..14a51c9
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# This file contains the font map for the default (hardware) font
+#
+FONTMAPFILE = cp437.uni
+
+obj-$(CONFIG_VT)                       += vt_ioctl.o vc_screen.o \
+                                          selection.o keyboard.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS)     += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_HW_CONSOLE)               += vt.o defkeymap.o
+
+# Files generated that shall be removed upon make clean
+clean-files := consolemap_deftbl.c defkeymap.c
+
+quiet_cmd_conmk = CONMK   $@
+      cmd_conmk = scripts/conmakehash $< > $@
+
+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
+       $(call cmd,conmk)
+
+$(obj)/defkeymap.o:  $(obj)/defkeymap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
+       loadkeys --mktable $< > $@.tmp
+       sed -e 's/^static *//' $@.tmp > $@
+       rm $@.tmp
+
+endif
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
new file mode 100644 (file)
index 0000000..45d3e80
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+ * consolemap.c
+ *
+ * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
+ * to font positions.
+ *
+ * aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
+ *
+ * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
+ */
+
+#include <linux/module.h>
+#include <linux/kd.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <asm/uaccess.h>
+#include <linux/consolemap.h>
+#include <linux/vt_kern.h>
+
+static unsigned short translations[][256] = {
+  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
+  {
+    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+  }, 
+  /* VT100 graphics mapped to Unicode */
+  {
+    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
+    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
+    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
+    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
+    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
+    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+  },
+  /* IBM Codepage 437 mapped to Unicode */
+  {
+    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
+    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
+    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
+    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
+    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
+    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
+    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
+    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
+  }, 
+  /* User mapping -- default to codes for direct font mapping */
+  {
+    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
+    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
+    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
+    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
+    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
+    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
+    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
+    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
+    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
+    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
+    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
+    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
+    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
+    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
+    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
+    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
+    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
+    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
+    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
+    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
+    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
+    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
+    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
+    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
+    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
+    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
+    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
+    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
+    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
+    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
+    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
+    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
+  }
+};
+
+/* The standard kernel character-to-font mappings are not invertible
+   -- this is just a best effort. */
+
+#define MAX_GLYPH 512          /* Max possible glyph value */
+
+static int inv_translate[MAX_NR_CONSOLES];
+
+struct uni_pagedir {
+       u16             **uni_pgdir[32];
+       unsigned long   refcount;
+       unsigned long   sum;
+       unsigned char   *inverse_translations[4];
+       u16             *inverse_trans_unicode;
+       int             readonly;
+};
+
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
+{
+       int j, glyph;
+       unsigned short *t = translations[i];
+       unsigned char *q;
+       
+       if (!p) return;
+       q = p->inverse_translations[i];
+
+       if (!q) {
+               q = p->inverse_translations[i] = (unsigned char *) 
+                       kmalloc(MAX_GLYPH, GFP_KERNEL);
+               if (!q) return;
+       }
+       memset(q, 0, MAX_GLYPH);
+
+       for (j = 0; j < E_TABSZ; j++) {
+               glyph = conv_uni_to_pc(conp, t[j]);
+               if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
+                       /* prefer '-' above SHY etc. */
+                       q[glyph] = j;
+               }
+       }
+}
+
+static void set_inverse_trans_unicode(struct vc_data *conp,
+                                     struct uni_pagedir *p)
+{
+       int i, j, k, glyph;
+       u16 **p1, *p2;
+       u16 *q;
+
+       if (!p) return;
+       q = p->inverse_trans_unicode;
+       if (!q) {
+               q = p->inverse_trans_unicode =
+                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
+               if (!q)
+                       return;
+       }
+       memset(q, 0, MAX_GLYPH * sizeof(u16));
+
+       for (i = 0; i < 32; i++) {
+               p1 = p->uni_pgdir[i];
+               if (!p1)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       p2 = p1[j];
+                       if (!p2)
+                               continue;
+                       for (k = 0; k < 64; k++) {
+                               glyph = p2[k];
+                               if (glyph >= 0 && glyph < MAX_GLYPH
+                                              && q[glyph] < 32)
+                                       q[glyph] = (i << 11) + (j << 6) + k;
+                       }
+               }
+       }
+}
+
+unsigned short *set_translate(int m, struct vc_data *vc)
+{
+       inv_translate[vc->vc_num] = m;
+       return translations[m];
+}
+
+/*
+ * Inverse translation is impossible for several reasons:
+ * 1. The font<->character maps are not 1-1.
+ * 2. The text may have been written while a different translation map
+ *    was active.
+ * Still, it is now possible to a certain extent to cut and paste non-ASCII.
+ */
+u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
+{
+       struct uni_pagedir *p;
+       int m;
+       if (glyph < 0 || glyph >= MAX_GLYPH)
+               return 0;
+       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
+               return glyph;
+       else if (use_unicode) {
+               if (!p->inverse_trans_unicode)
+                       return glyph;
+               else
+                       return p->inverse_trans_unicode[glyph];
+       } else {
+               m = inv_translate[conp->vc_num];
+               if (!p->inverse_translations[m])
+                       return glyph;
+               else
+                       return p->inverse_translations[m][glyph];
+       }
+}
+EXPORT_SYMBOL_GPL(inverse_translate);
+
+static void update_user_maps(void)
+{
+       int i;
+       struct uni_pagedir *p, *q = NULL;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (p && p != q) {
+                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+                       set_inverse_trans_unicode(vc_cons[i].d, p);
+                       q = p;
+               }
+       }
+}
+
+/*
+ * Load customizable translation table
+ * arg points to a 256 byte translation table.
+ *
+ * The "old" variants are for translation directly to font (using the
+ * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
+ * Unicodes explicitly.
+ */
+int con_set_trans_old(unsigned char __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_READ, arg, E_TABSZ))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++) {
+               unsigned char uc;
+               __get_user(uc, arg+i);
+               p[i] = UNI_DIRECT_BASE | uc;
+       }
+
+       update_user_maps();
+       return 0;
+}
+
+int con_get_trans_old(unsigned char __user * arg)
+{
+       int i, ch;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++)
+         {
+           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+           __put_user((ch & ~0xff) ? 0 : ch, arg+i);
+         }
+       return 0;
+}
+
+int con_set_trans_new(ushort __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++) {
+               unsigned short us;
+               __get_user(us, arg+i);
+               p[i] = us;
+       }
+
+       update_user_maps();
+       return 0;
+}
+
+int con_get_trans_new(ushort __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++)
+         __put_user(p[i], arg+i);
+       
+       return 0;
+}
+
+/*
+ * Unicode -> current font conversion 
+ *
+ * A font has at most 512 chars, usually 256.
+ * But one font position may represent several Unicode chars.
+ * A hashtable is somewhat of a pain to deal with, so use a
+ * "paged table" instead.  Simulation has shown the memory cost of
+ * this 3-level paged table scheme to be comparable to a hash table.
+ */
+
+extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
+extern u16 dfont_unitable[];
+
+static void con_release_unimap(struct uni_pagedir *p)
+{
+       u16 **p1;
+       int i, j;
+
+       if (p == dflt) dflt = NULL;  
+       for (i = 0; i < 32; i++) {
+               if ((p1 = p->uni_pgdir[i]) != NULL) {
+                       for (j = 0; j < 32; j++)
+                               kfree(p1[j]);
+                       kfree(p1);
+               }
+               p->uni_pgdir[i] = NULL;
+       }
+       for (i = 0; i < 4; i++) {
+               kfree(p->inverse_translations[i]);
+               p->inverse_translations[i] = NULL;
+       }
+       if (p->inverse_trans_unicode) {
+               kfree(p->inverse_trans_unicode);
+               p->inverse_trans_unicode = NULL;
+       }
+}
+
+void con_free_unimap(struct vc_data *vc)
+{
+       struct uni_pagedir *p;
+
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (!p)
+               return;
+       *vc->vc_uni_pagedir_loc = 0;
+       if (--p->refcount)
+               return;
+       con_release_unimap(p);
+       kfree(p);
+}
+  
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+       int i, j, k;
+       struct uni_pagedir *q;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (!q || q == p || q->sum != p->sum)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       u16 **p1, **q1;
+                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+                       if (!p1 && !q1)
+                               continue;
+                       if (!p1 || !q1)
+                               break;
+                       for (k = 0; k < 32; k++) {
+                               if (!p1[k] && !q1[k])
+                                       continue;
+                               if (!p1[k] || !q1[k])
+                                       break;
+                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+                                       break;
+                       }
+                       if (k < 32)
+                               break;
+               }
+               if (j == 32) {
+                       q->refcount++;
+                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
+                       con_release_unimap(p);
+                       kfree(p);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
+{
+       int i, n;
+       u16 **p1, *p2;
+
+       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+               if (!p1) return -ENOMEM;
+               for (i = 0; i < 32; i++)
+                       p1[i] = NULL;
+       }
+
+       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+               if (!p2) return -ENOMEM;
+               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+       }
+
+       p2[unicode & 0x3f] = fontpos;
+       
+       p->sum += (fontpos << 20) + unicode;
+
+       return 0;
+}
+
+/* ui is a leftover from using a hashtable, but might be used again */
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+       struct uni_pagedir *p, *q;
+  
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (p && p->readonly) return -EIO;
+       if (!p || --p->refcount) {
+               q = kzalloc(sizeof(*p), GFP_KERNEL);
+               if (!q) {
+                       if (p) p->refcount++;
+                       return -ENOMEM;
+               }
+               q->refcount=1;
+               *vc->vc_uni_pagedir_loc = (unsigned long)q;
+       } else {
+               if (p == dflt) dflt = NULL;
+               p->refcount++;
+               p->sum = 0;
+               con_release_unimap(p);
+       }
+       return 0;
+}
+
+int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
+{
+       int err = 0, err1, i;
+       struct uni_pagedir *p, *q;
+
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (p->readonly) return -EIO;
+       
+       if (!ct) return 0;
+       
+       if (p->refcount > 1) {
+               int j, k;
+               u16 **p1, *p2, l;
+               
+               err1 = con_clear_unimap(vc, NULL);
+               if (err1) return err1;
+               
+               q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               for (i = 0, l = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = p1[j]))
+                               for (k = 0; k < 64; k++, l++)
+                               if (p2[k] != 0xffff) {
+                                       err1 = con_insert_unipair(q, l, p2[k]);
+                                       if (err1) {
+                                               p->refcount++;
+                                               *vc->vc_uni_pagedir_loc = (unsigned long)p;
+                                               con_release_unimap(q);
+                                               kfree(q);
+                                               return err1; 
+                                       }
+                               }
+               p = q;
+       } else if (p == dflt)
+               dflt = NULL;
+       
+       while (ct--) {
+               unsigned short unicode, fontpos;
+               __get_user(unicode, &list->unicode);
+               __get_user(fontpos, &list->fontpos);
+               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+                       err = err1;
+               list++;
+       }
+       
+       if (con_unify_unimap(vc, p))
+               return err;
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(vc, p, i); /* Update all inverse translations */
+       set_inverse_trans_unicode(vc, p);
+  
+       return err;
+}
+
+/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+   The representation used was the most compact I could come up
+   with.  This routine is executed at sys_setup time, and when the
+   PIO_FONTRESET ioctl is called. */
+
+int con_set_default_unimap(struct vc_data *vc)
+{
+       int i, j, err = 0, err1;
+       u16 *q;
+       struct uni_pagedir *p;
+
+       if (dflt) {
+               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               if (p == dflt)
+                       return 0;
+               dflt->refcount++;
+               *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
+               if (p && --p->refcount) {
+                       con_release_unimap(p);
+                       kfree(p);
+               }
+               return 0;
+       }
+       
+       /* The default font is always 256 characters */
+
+       err = con_clear_unimap(vc, NULL);
+       if (err) return err;
+    
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       q = dfont_unitable;
+       
+       for (i = 0; i < 256; i++)
+               for (j = dfont_unicount[i]; j; j--) {
+                       err1 = con_insert_unipair(p, *(q++), i);
+                       if (err1)
+                               err = err1;
+               }
+                       
+       if (con_unify_unimap(vc, p)) {
+               dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               return err;
+       }
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(vc, p, i);   /* Update all inverse translations */
+       set_inverse_trans_unicode(vc, p);
+       dflt = p;
+       return err;
+}
+EXPORT_SYMBOL(con_set_default_unimap);
+
+int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
+{
+       struct uni_pagedir *q;
+
+       if (!*src_vc->vc_uni_pagedir_loc)
+               return -EINVAL;
+       if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
+               return 0;
+       con_free_unimap(dst_vc);
+       q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
+       q->refcount++;
+       *dst_vc->vc_uni_pagedir_loc = (long)q;
+       return 0;
+}
+
+int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
+{
+       int i, j, k, ect;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
+
+       ect = 0;
+       if (*vc->vc_uni_pagedir_loc) {
+               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               for (i = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = *(p1++)))
+                               for (k = 0; k < 64; k++) {
+                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
+                                               __put_user((u_short)((i<<11)+(j<<6)+k),
+                                                          &list->unicode);
+                                               __put_user((u_short) *p2, 
+                                                          &list->fontpos);
+                                               list++;
+                                       }
+                                       p2++;
+                               }
+       }
+       __put_user(ect, uct);
+       return ((ect <= ct) ? 0 : -ENOMEM);
+}
+
+void con_protect_unimap(struct vc_data *vc, int rdonly)
+{
+       struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       
+       if (p)
+               p->readonly = rdonly;
+}
+
+/*
+ * Always use USER_MAP. These functions are used by the keyboard,
+ * which shouldn't be affected by G0/G1 switching, etc.
+ * If the user map still contains default values, i.e. the
+ * direct-to-font mapping, then assume user is using Latin1.
+ */
+/* may be called during an interrupt */
+u32 conv_8bit_to_uni(unsigned char c)
+{
+       unsigned short uni = translations[USER_MAP][c];
+       return uni == (0xf000 | c) ? c : uni;
+}
+
+int conv_uni_to_8bit(u32 uni)
+{
+       int c;
+       for (c = 0; c < 0x100; c++)
+               if (translations[USER_MAP][c] == uni ||
+                  (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
+                       return c;
+       return -1;
+}
+
+int
+conv_uni_to_pc(struct vc_data *conp, long ucs) 
+{
+       int h;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
+  
+       /* Only 16-bit codes supported at this time */
+       if (ucs > 0xffff)
+               return -4;              /* Not found */
+       else if (ucs < 0x20)
+               return -1;              /* Not a printable character */
+       else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
+               return -2;                      /* Zero-width space */
+       /*
+        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+        * which always has a 1:1 mapping to the currently loaded font.  The
+        * UNI_DIRECT_MASK indicates the bit span of the region.
+        */
+       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+               return ucs & UNI_DIRECT_MASK;
+  
+       if (!*conp->vc_uni_pagedir_loc)
+               return -3;
+
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
+       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+           (p2 = p1[(ucs >> 6) & 0x1f]) &&
+           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+               return h;
+
+       return -4;              /* not found */
+}
+
+/*
+ * This is called at sys_setup time, after memory and the console are
+ * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
+ * from this function, hence the call from sys_setup.
+ */
+void __init 
+console_map_init(void)
+{
+       int i;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+                       con_set_default_unimap(vc_cons[i].d);
+}
+
+EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/cp437.uni b/drivers/tty/vt/cp437.uni
new file mode 100644 (file)
index 0000000..bc61634
--- /dev/null
@@ -0,0 +1,291 @@
+#
+# Unicode table for IBM Codepage 437.  Note that there are many more
+# substitutions that could be conceived (for example, thick-line
+# graphs probably should be replaced with double-line ones, accented
+# Latin characters should replaced with their nonaccented versions,
+# and some upper case Greek characters could be replaced by Latin), however,
+# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
+# DEC VT, and IBM CP 437 tables.
+#
+# --------------------------------
+#
+# Basic IBM dingbats, some of which will never have a purpose clear
+# to mankind
+#
+0x00   U+0000
+0x01   U+263a
+0x02   U+263b
+0x03   U+2665
+0x04   U+2666 U+25c6
+0x05   U+2663
+0x06   U+2660
+0x07   U+2022
+0x08   U+25d8
+0x09   U+25cb
+0x0a   U+25d9
+0x0b   U+2642
+0x0c   U+2640
+0x0d   U+266a
+0x0e   U+266b
+0x0f   U+263c U+00a4
+0x10   U+25b6 U+25ba
+0x11   U+25c0 U+25c4
+0x12   U+2195
+0x13   U+203c
+0x14   U+00b6
+0x15   U+00a7
+0x16   U+25ac
+0x17   U+21a8
+0x18   U+2191
+0x19   U+2193
+0x1a   U+2192
+0x1b   U+2190
+0x1c   U+221f
+0x1d   U+2194
+0x1e   U+25b2
+0x1f   U+25bc
+#
+# The ASCII range is identity-mapped, but some of the characters also
+# have to act as substitutes, especially the upper-case characters.
+#
+0x20   U+0020
+0x21   U+0021
+0x22   U+0022 U+00a8
+0x23   U+0023
+0x24   U+0024
+0x25   U+0025
+0x26   U+0026
+0x27   U+0027 U+00b4
+0x28   U+0028
+0x29   U+0029
+0x2a   U+002a
+0x2b   U+002b
+0x2c   U+002c U+00b8
+0x2d   U+002d U+00ad
+0x2e   U+002e
+0x2f   U+002f
+0x30   U+0030
+0x31   U+0031
+0x32   U+0032
+0x33   U+0033
+0x34   U+0034
+0x35   U+0035
+0x36   U+0036
+0x37   U+0037
+0x38   U+0038
+0x39   U+0039
+0x3a   U+003a
+0x3b   U+003b
+0x3c   U+003c
+0x3d   U+003d
+0x3e   U+003e
+0x3f   U+003f
+0x40   U+0040
+0x41   U+0041 U+00c0 U+00c1 U+00c2 U+00c3
+0x42   U+0042
+0x43   U+0043 U+00a9
+0x44   U+0044 U+00d0
+0x45   U+0045 U+00c8 U+00ca U+00cb
+0x46   U+0046
+0x47   U+0047
+0x48   U+0048
+0x49   U+0049 U+00cc U+00cd U+00ce U+00cf
+0x4a   U+004a
+0x4b   U+004b U+212a
+0x4c   U+004c
+0x4d   U+004d
+0x4e   U+004e
+0x4f   U+004f U+00d2 U+00d3 U+00d4 U+00d5
+0x50   U+0050
+0x51   U+0051
+0x52   U+0052 U+00ae
+0x53   U+0053
+0x54   U+0054
+0x55   U+0055 U+00d9 U+00da U+00db
+0x56   U+0056
+0x57   U+0057
+0x58   U+0058
+0x59   U+0059 U+00dd
+0x5a   U+005a
+0x5b   U+005b
+0x5c   U+005c
+0x5d   U+005d
+0x5e   U+005e
+0x5f   U+005f U+23bd U+f804
+0x60   U+0060
+0x61   U+0061 U+00e3
+0x62   U+0062
+0x63   U+0063
+0x64   U+0064
+0x65   U+0065
+0x66   U+0066
+0x67   U+0067
+0x68   U+0068
+0x69   U+0069
+0x6a   U+006a
+0x6b   U+006b
+0x6c   U+006c
+0x6d   U+006d
+0x6e   U+006e
+0x6f   U+006f U+00f5
+0x70   U+0070
+0x71   U+0071
+0x72   U+0072
+0x73   U+0073
+0x74   U+0074
+0x75   U+0075
+0x76   U+0076
+0x77   U+0077
+0x78   U+0078 U+00d7
+0x79   U+0079 U+00fd
+0x7a   U+007a
+0x7b   U+007b
+0x7c   U+007c U+00a6
+0x7d   U+007d
+0x7e   U+007e
+#
+# Okay, what on Earth is this one supposed to be used for?
+#
+0x7f   U+2302
+#
+# Non-English characters, mostly lower case letters...
+#
+0x80   U+00c7
+0x81   U+00fc
+0x82   U+00e9
+0x83   U+00e2
+0x84   U+00e4
+0x85   U+00e0
+0x86   U+00e5
+0x87   U+00e7
+0x88   U+00ea
+0x89   U+00eb
+0x8a   U+00e8
+0x8b   U+00ef
+0x8c   U+00ee
+0x8d   U+00ec
+0x8e   U+00c4
+0x8f   U+00c5 U+212b
+0x90   U+00c9
+0x91   U+00e6
+0x92   U+00c6
+0x93   U+00f4
+0x94   U+00f6
+0x95   U+00f2
+0x96   U+00fb
+0x97   U+00f9
+0x98   U+00ff
+0x99   U+00d6
+0x9a   U+00dc
+0x9b   U+00a2
+0x9c   U+00a3
+0x9d   U+00a5
+0x9e   U+20a7
+0x9f   U+0192
+0xa0   U+00e1
+0xa1   U+00ed
+0xa2   U+00f3
+0xa3   U+00fa
+0xa4   U+00f1
+0xa5   U+00d1
+0xa6   U+00aa
+0xa7   U+00ba
+0xa8   U+00bf
+0xa9   U+2310
+0xaa   U+00ac
+0xab   U+00bd
+0xac   U+00bc
+0xad   U+00a1
+0xae   U+00ab
+0xaf   U+00bb
+#
+# Block graphics
+#
+0xb0   U+2591
+0xb1   U+2592
+0xb2   U+2593
+0xb3   U+2502
+0xb4   U+2524
+0xb5   U+2561
+0xb6   U+2562
+0xb7   U+2556
+0xb8   U+2555
+0xb9   U+2563
+0xba   U+2551
+0xbb   U+2557
+0xbc   U+255d
+0xbd   U+255c
+0xbe   U+255b
+0xbf   U+2510
+0xc0   U+2514
+0xc1   U+2534
+0xc2   U+252c
+0xc3   U+251c
+0xc4   U+2500
+0xc5   U+253c
+0xc6   U+255e
+0xc7   U+255f
+0xc8   U+255a
+0xc9   U+2554
+0xca   U+2569
+0xcb   U+2566
+0xcc   U+2560
+0xcd   U+2550
+0xce   U+256c
+0xcf   U+2567
+0xd0   U+2568
+0xd1   U+2564
+0xd2   U+2565
+0xd3   U+2559
+0xd4   U+2558
+0xd5   U+2552
+0xd6   U+2553
+0xd7   U+256b
+0xd8   U+256a
+0xd9   U+2518
+0xda   U+250c
+0xdb   U+2588
+0xdc   U+2584
+0xdd   U+258c
+0xde   U+2590
+0xdf   U+2580
+#
+# Greek letters and mathematical symbols
+#
+0xe0   U+03b1
+0xe1   U+03b2 U+00df
+0xe2   U+0393
+0xe3   U+03c0
+0xe4   U+03a3
+0xe5   U+03c3
+0xe6   U+00b5 U+03bc
+0xe7   U+03c4
+0xe8   U+03a6 U+00d8
+0xe9   U+0398
+0xea   U+03a9 U+2126
+0xeb   U+03b4 U+00f0
+0xec   U+221e
+0xed   U+03c6 U+00f8
+0xee   U+03b5 U+2208
+0xef   U+2229
+0xf0   U+2261
+0xf1   U+00b1
+0xf2   U+2265
+0xf3   U+2264
+0xf4   U+2320
+0xf5   U+2321
+0xf6   U+00f7
+0xf7   U+2248
+0xf8   U+00b0
+0xf9   U+2219
+0xfa   U+00b7
+0xfb   U+221a
+0xfc   U+207f
+0xfd   U+00b2
+#
+# Square bullet, non-spacing blank
+# Mapping U+fffd to the square bullet means it is the substitution
+# character
+# 
+0xfe   U+25a0 U+fffd
+0xff   U+00a0
diff --git a/drivers/tty/vt/defkeymap.c_shipped b/drivers/tty/vt/defkeymap.c_shipped
new file mode 100644 (file)
index 0000000..d2208df
--- /dev/null
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
+       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
+       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+       0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+       0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
+       0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
+       0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
+       0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
+       0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
+       0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
+       0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+       0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
+       0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
+       0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
+       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
+       0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
+       0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
+       0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
+       0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
+       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+       0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+       0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
+       0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
+       0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
+       0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
+       0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
+       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
+       0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
+       0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
+       0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
+       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+       0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
+       0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
+       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+       plain_map, shift_map, altgr_map, NULL,
+       ctrl_map, shift_ctrl_map, NULL, NULL,
+       alt_map, NULL, NULL, NULL,
+       ctrl_alt_map, NULL
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+       '\033', '[', '[', 'A', 0, 
+       '\033', '[', '[', 'B', 0, 
+       '\033', '[', '[', 'C', 0, 
+       '\033', '[', '[', 'D', 0, 
+       '\033', '[', '[', 'E', 0, 
+       '\033', '[', '1', '7', '~', 0, 
+       '\033', '[', '1', '8', '~', 0, 
+       '\033', '[', '1', '9', '~', 0, 
+       '\033', '[', '2', '0', '~', 0, 
+       '\033', '[', '2', '1', '~', 0, 
+       '\033', '[', '2', '3', '~', 0, 
+       '\033', '[', '2', '4', '~', 0, 
+       '\033', '[', '2', '5', '~', 0, 
+       '\033', '[', '2', '6', '~', 0, 
+       '\033', '[', '2', '8', '~', 0, 
+       '\033', '[', '2', '9', '~', 0, 
+       '\033', '[', '3', '1', '~', 0, 
+       '\033', '[', '3', '2', '~', 0, 
+       '\033', '[', '3', '3', '~', 0, 
+       '\033', '[', '3', '4', '~', 0, 
+       '\033', '[', '1', '~', 0, 
+       '\033', '[', '2', '~', 0, 
+       '\033', '[', '3', '~', 0, 
+       '\033', '[', '4', '~', 0, 
+       '\033', '[', '5', '~', 0, 
+       '\033', '[', '6', '~', 0, 
+       '\033', '[', 'M', 0, 
+       '\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+       func_buf + 0,
+       func_buf + 5,
+       func_buf + 10,
+       func_buf + 15,
+       func_buf + 20,
+       func_buf + 25,
+       func_buf + 31,
+       func_buf + 37,
+       func_buf + 43,
+       func_buf + 49,
+       func_buf + 55,
+       func_buf + 61,
+       func_buf + 67,
+       func_buf + 73,
+       func_buf + 79,
+       func_buf + 85,
+       func_buf + 91,
+       func_buf + 97,
+       func_buf + 103,
+       func_buf + 109,
+       func_buf + 115,
+       func_buf + 120,
+       func_buf + 125,
+       func_buf + 130,
+       func_buf + 135,
+       func_buf + 140,
+       func_buf + 145,
+       NULL,
+       NULL,
+       func_buf + 149,
+       NULL,
+};
+
+struct kbdiacruc accent_table[MAX_DIACR] = {
+       {'`', 'A', 0300},       {'`', 'a', 0340},
+       {'\'', 'A', 0301},      {'\'', 'a', 0341},
+       {'^', 'A', 0302},       {'^', 'a', 0342},
+       {'~', 'A', 0303},       {'~', 'a', 0343},
+       {'"', 'A', 0304},       {'"', 'a', 0344},
+       {'O', 'A', 0305},       {'o', 'a', 0345},
+       {'0', 'A', 0305},       {'0', 'a', 0345},
+       {'A', 'A', 0305},       {'a', 'a', 0345},
+       {'A', 'E', 0306},       {'a', 'e', 0346},
+       {',', 'C', 0307},       {',', 'c', 0347},
+       {'`', 'E', 0310},       {'`', 'e', 0350},
+       {'\'', 'E', 0311},      {'\'', 'e', 0351},
+       {'^', 'E', 0312},       {'^', 'e', 0352},
+       {'"', 'E', 0313},       {'"', 'e', 0353},
+       {'`', 'I', 0314},       {'`', 'i', 0354},
+       {'\'', 'I', 0315},      {'\'', 'i', 0355},
+       {'^', 'I', 0316},       {'^', 'i', 0356},
+       {'"', 'I', 0317},       {'"', 'i', 0357},
+       {'-', 'D', 0320},       {'-', 'd', 0360},
+       {'~', 'N', 0321},       {'~', 'n', 0361},
+       {'`', 'O', 0322},       {'`', 'o', 0362},
+       {'\'', 'O', 0323},      {'\'', 'o', 0363},
+       {'^', 'O', 0324},       {'^', 'o', 0364},
+       {'~', 'O', 0325},       {'~', 'o', 0365},
+       {'"', 'O', 0326},       {'"', 'o', 0366},
+       {'/', 'O', 0330},       {'/', 'o', 0370},
+       {'`', 'U', 0331},       {'`', 'u', 0371},
+       {'\'', 'U', 0332},      {'\'', 'u', 0372},
+       {'^', 'U', 0333},       {'^', 'u', 0373},
+       {'"', 'U', 0334},       {'"', 'u', 0374},
+       {'\'', 'Y', 0335},      {'\'', 'y', 0375},
+       {'T', 'H', 0336},       {'t', 'h', 0376},
+       {'s', 's', 0337},       {'"', 'y', 0377},
+       {'s', 'z', 0337},       {'i', 'j', 0377},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/tty/vt/defkeymap.map b/drivers/tty/vt/defkeymap.map
new file mode 100644 (file)
index 0000000..50b30ca
--- /dev/null
@@ -0,0 +1,357 @@
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+#      keymaps 0-2,4-6,8,12
+# in case you want the entries
+#      altgr   control keycode  83 = Boot            
+#      altgr   control keycode 111 = Boot            
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode   1 = Escape           Escape          
+       alt     keycode   1 = Meta_Escape     
+keycode   2 = one              exclam          
+       alt     keycode   2 = Meta_one        
+keycode   3 = two              at               at              
+       control keycode   3 = nul             
+       shift   control keycode   3 = nul             
+       alt     keycode   3 = Meta_two        
+keycode   4 = three            numbersign      
+       control keycode   4 = Escape          
+       alt     keycode   4 = Meta_three      
+keycode   5 = four             dollar           dollar          
+       control keycode   5 = Control_backslash
+       alt     keycode   5 = Meta_four       
+keycode   6 = five             percent         
+       control keycode   6 = Control_bracketright
+       alt     keycode   6 = Meta_five       
+keycode   7 = six              asciicircum     
+       control keycode   7 = Control_asciicircum
+       alt     keycode   7 = Meta_six        
+keycode   8 = seven            ampersand        braceleft       
+       control keycode   8 = Control_underscore
+       alt     keycode   8 = Meta_seven      
+keycode   9 = eight            asterisk         bracketleft     
+       control keycode   9 = Delete          
+       alt     keycode   9 = Meta_eight      
+keycode  10 = nine             parenleft        bracketright    
+       alt     keycode  10 = Meta_nine       
+keycode  11 = zero             parenright       braceright      
+       alt     keycode  11 = Meta_zero       
+keycode  12 = minus            underscore       backslash       
+       control keycode  12 = Control_underscore
+       shift   control keycode  12 = Control_underscore
+       alt     keycode  12 = Meta_minus      
+keycode  13 = equal            plus            
+       alt     keycode  13 = Meta_equal      
+keycode  14 = Delete           Delete          
+       control keycode  14 = BackSpace
+       alt     keycode  14 = Meta_Delete     
+keycode  15 = Tab              Tab             
+       alt     keycode  15 = Meta_Tab        
+keycode  16 = q               
+keycode  17 = w               
+keycode  18 = e
+       altgr   keycode  18 = Hex_E   
+keycode  19 = r               
+keycode  20 = t               
+keycode  21 = y               
+keycode  22 = u               
+keycode  23 = i               
+keycode  24 = o               
+keycode  25 = p               
+keycode  26 = bracketleft      braceleft       
+       control keycode  26 = Escape          
+       alt     keycode  26 = Meta_bracketleft
+keycode  27 = bracketright     braceright       asciitilde      
+       control keycode  27 = Control_bracketright
+       alt     keycode  27 = Meta_bracketright
+keycode  28 = Return          
+       alt     keycode  28 = Meta_Control_m  
+keycode  29 = Control         
+keycode  30 = a
+       altgr   keycode  30 = Hex_A
+keycode  31 = s               
+keycode  32 = d
+       altgr   keycode  32 = Hex_D   
+keycode  33 = f
+       altgr   keycode  33 = Hex_F               
+keycode  34 = g               
+keycode  35 = h               
+keycode  36 = j               
+keycode  37 = k               
+keycode  38 = l               
+keycode  39 = semicolon        colon           
+       alt     keycode  39 = Meta_semicolon  
+keycode  40 = apostrophe       quotedbl        
+       control keycode  40 = Control_g       
+       alt     keycode  40 = Meta_apostrophe 
+keycode  41 = grave            asciitilde      
+       control keycode  41 = nul             
+       alt     keycode  41 = Meta_grave      
+keycode  42 = Shift           
+keycode  43 = backslash        bar             
+       control keycode  43 = Control_backslash
+       alt     keycode  43 = Meta_backslash  
+keycode  44 = z               
+keycode  45 = x               
+keycode  46 = c
+       altgr   keycode  46 = Hex_C   
+keycode  47 = v               
+keycode  48 = b
+       altgr   keycode  48 = Hex_B
+keycode  49 = n               
+keycode  50 = m               
+keycode  51 = comma            less            
+       alt     keycode  51 = Meta_comma      
+keycode  52 = period           greater         
+       control keycode  52 = Compose         
+       alt     keycode  52 = Meta_period     
+keycode  53 = slash            question        
+       control keycode  53 = Delete          
+       alt     keycode  53 = Meta_slash      
+keycode  54 = Shift           
+keycode  55 = KP_Multiply     
+keycode  56 = Alt             
+keycode  57 = space            space           
+       control keycode  57 = nul             
+       alt     keycode  57 = Meta_space      
+keycode  58 = Caps_Lock       
+keycode  59 = F1               F11              Console_13      
+       control keycode  59 = F1              
+       alt     keycode  59 = Console_1       
+       control alt     keycode  59 = Console_1       
+keycode  60 = F2               F12              Console_14      
+       control keycode  60 = F2              
+       alt     keycode  60 = Console_2       
+       control alt     keycode  60 = Console_2       
+keycode  61 = F3               F13              Console_15      
+       control keycode  61 = F3              
+       alt     keycode  61 = Console_3       
+       control alt     keycode  61 = Console_3       
+keycode  62 = F4               F14              Console_16      
+       control keycode  62 = F4              
+       alt     keycode  62 = Console_4       
+       control alt     keycode  62 = Console_4       
+keycode  63 = F5               F15              Console_17      
+       control keycode  63 = F5              
+       alt     keycode  63 = Console_5       
+       control alt     keycode  63 = Console_5       
+keycode  64 = F6               F16              Console_18      
+       control keycode  64 = F6              
+       alt     keycode  64 = Console_6       
+       control alt     keycode  64 = Console_6       
+keycode  65 = F7               F17              Console_19      
+       control keycode  65 = F7              
+       alt     keycode  65 = Console_7       
+       control alt     keycode  65 = Console_7       
+keycode  66 = F8               F18              Console_20      
+       control keycode  66 = F8              
+       alt     keycode  66 = Console_8       
+       control alt     keycode  66 = Console_8       
+keycode  67 = F9               F19              Console_21      
+       control keycode  67 = F9              
+       alt     keycode  67 = Console_9       
+       control alt     keycode  67 = Console_9       
+keycode  68 = F10              F20              Console_22      
+       control keycode  68 = F10             
+       alt     keycode  68 = Console_10      
+       control alt     keycode  68 = Console_10      
+keycode  69 = Num_Lock
+       shift   keycode  69 = Bare_Num_Lock
+keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
+       control keycode  70 = Show_State      
+       alt     keycode  70 = Scroll_Lock     
+keycode  71 = KP_7            
+       alt     keycode  71 = Ascii_7         
+       altgr   keycode  71 = Hex_7         
+keycode  72 = KP_8            
+       alt     keycode  72 = Ascii_8         
+       altgr   keycode  72 = Hex_8         
+keycode  73 = KP_9            
+       alt     keycode  73 = Ascii_9         
+       altgr   keycode  73 = Hex_9         
+keycode  74 = KP_Subtract     
+keycode  75 = KP_4            
+       alt     keycode  75 = Ascii_4         
+       altgr   keycode  75 = Hex_4         
+keycode  76 = KP_5            
+       alt     keycode  76 = Ascii_5         
+       altgr   keycode  76 = Hex_5         
+keycode  77 = KP_6            
+       alt     keycode  77 = Ascii_6         
+       altgr   keycode  77 = Hex_6         
+keycode  78 = KP_Add          
+keycode  79 = KP_1            
+       alt     keycode  79 = Ascii_1         
+       altgr   keycode  79 = Hex_1         
+keycode  80 = KP_2            
+       alt     keycode  80 = Ascii_2         
+       altgr   keycode  80 = Hex_2         
+keycode  81 = KP_3            
+       alt     keycode  81 = Ascii_3         
+       altgr   keycode  81 = Hex_3         
+keycode  82 = KP_0            
+       alt     keycode  82 = Ascii_0         
+       altgr   keycode  82 = Hex_0         
+keycode  83 = KP_Period       
+#      altgr   control keycode  83 = Boot            
+       control alt     keycode  83 = Boot            
+keycode  84 = Last_Console    
+keycode  85 =
+keycode  86 = less             greater          bar             
+       alt     keycode  86 = Meta_less       
+keycode  87 = F11              F11              Console_23      
+       control keycode  87 = F11             
+       alt     keycode  87 = Console_11      
+       control alt     keycode  87 = Console_11      
+keycode  88 = F12              F12              Console_24      
+       control keycode  88 = F12             
+       alt     keycode  88 = Console_12      
+       control alt     keycode  88 = Console_12      
+keycode  89 =
+keycode  90 =
+keycode  91 =
+keycode  92 =
+keycode  93 =
+keycode  94 =
+keycode  95 =
+keycode  96 = KP_Enter        
+keycode  97 = Control         
+keycode  98 = KP_Divide       
+keycode  99 = Control_backslash
+       control keycode  99 = Control_backslash
+       alt     keycode  99 = Control_backslash
+keycode 100 = AltGr           
+keycode 101 = Break           
+keycode 102 = Find            
+keycode 103 = Up              
+keycode 104 = Prior           
+       shift   keycode 104 = Scroll_Backward 
+keycode 105 = Left            
+       alt     keycode 105 = Decr_Console
+keycode 106 = Right           
+       alt     keycode 106 = Incr_Console
+keycode 107 = Select          
+keycode 108 = Down            
+keycode 109 = Next            
+       shift   keycode 109 = Scroll_Forward  
+keycode 110 = Insert          
+keycode 111 = Remove          
+#      altgr   control keycode 111 = Boot            
+       control alt     keycode 111 = Boot            
+keycode 112 = Macro           
+keycode 113 = F13             
+keycode 114 = F14             
+keycode 115 = Help            
+keycode 116 = Do              
+keycode 117 = F17             
+keycode 118 = KP_MinPlus      
+keycode 119 = Pause           
+keycode 120 =
+keycode 121 =
+keycode 122 =
+keycode 123 =
+keycode 124 =
+keycode 125 =
+keycode 126 =
+keycode 127 =
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
new file mode 100644 (file)
index 0000000..e95d787
--- /dev/null
@@ -0,0 +1,1454 @@
+/*
+ * linux/drivers/char/keyboard.c
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting,  Sept 1994
+ * `Sticky' modifier keys, 951006.
+ *
+ * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Modified to provide 'generic' keyboard support by Hamish Macdonald
+ * Merge with the m68k keyboard driver and split-off of the PC low-level
+ * parts by Geert Uytterhoeven, May 1997
+ *
+ * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
+ * 30-07-98: Dead keys redone, aeb@cwi.nl.
+ * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/consolemap.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
+#include <linux/input.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
+
+extern void ctrl_alt_del(void);
+
+/*
+ * Exported functions/variables
+ */
+
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off. On HIL keyboards
+ * of PARISC machines however there is no NumLock key and everyone expects the keypad
+ * to be used for numbers.
+ */
+
+#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#else
+#define KBD_DEFLEDS 0
+#endif
+
+#define KBD_DEFLOCK 0
+
+void compute_shiftstate(void);
+
+/*
+ * Handler Tables.
+ */
+
+#define K_HANDLERS\
+       k_self,         k_fn,           k_spec,         k_pad,\
+       k_dead,         k_cons,         k_cur,          k_shift,\
+       k_meta,         k_ascii,        k_lock,         k_lowercase,\
+       k_slock,        k_dead2,        k_brl,          k_ignore
+
+typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
+                           char up_flag);
+static k_handler_fn K_HANDLERS;
+static k_handler_fn *k_handler[16] = { K_HANDLERS };
+
+#define FN_HANDLERS\
+       fn_null,        fn_enter,       fn_show_ptregs, fn_show_mem,\
+       fn_show_state,  fn_send_intr,   fn_lastcons,    fn_caps_toggle,\
+       fn_num,         fn_hold,        fn_scroll_forw, fn_scroll_back,\
+       fn_boot_it,     fn_caps_on,     fn_compose,     fn_SAK,\
+       fn_dec_console, fn_inc_console, fn_spawn_con,   fn_bare_num
+
+typedef void (fn_handler_fn)(struct vc_data *vc);
+static fn_handler_fn FN_HANDLERS;
+static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
+
+/*
+ * Variables exported for vt_ioctl.c
+ */
+
+/* maximum values each key_handler can handle */
+const int max_vals[] = {
+       255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
+       NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
+       255, NR_LOCK - 1, 255, NR_BRL - 1
+};
+
+const int NR_TYPES = ARRAY_SIZE(max_vals);
+
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
+static struct kbd_struct *kbd = kbd_table;
+
+struct vt_spawn_console vt_spawn_con = {
+       .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
+       .pid  = NULL,
+       .sig  = 0,
+};
+
+/*
+ * Variables exported for vt.c
+ */
+
+int shift_state = 0;
+
+/*
+ * Internal Data.
+ */
+
+static struct input_handler kbd_handler;
+static DEFINE_SPINLOCK(kbd_event_lock);
+static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
+static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
+static bool dead_key_next;
+static int npadch = -1;                                        /* -1 or number assembled on pad */
+static unsigned int diacr;
+static char rep;                                       /* flag telling character repeat */
+
+static unsigned char ledstate = 0xff;                  /* undefined */
+static unsigned char ledioctl;
+
+static struct ledptr {
+       unsigned int *addr;
+       unsigned int mask;
+       unsigned char valid:1;
+} ledptrs[3];
+
+/*
+ * Notifier list for console keyboard events
+ */
+static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
+
+int register_keyboard_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_keyboard_notifier);
+
+int unregister_keyboard_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
+
+/*
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ *  USB keyboards for example have two event devices: one for all "normal"
+ *  keys and one for extra function keys (like "volume up", "make coffee",
+ *  etc.). So this means that scancodes for the extra function keys won't
+ *  be valid for the first event device, but will be for the second.
+ */
+
+struct getset_keycode_data {
+       struct input_keymap_entry ke;
+       int error;
+};
+
+static int getkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_get_keycode(handle->dev, &d->ke);
+
+       return d->error == 0; /* stop as soon as we successfully get one */
+}
+
+int getkeycode(unsigned int scancode)
+{
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = 0,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
+
+       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
+
+       return d.error ?: d.ke.keycode;
+}
+
+static int setkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_set_keycode(handle->dev, &d->ke);
+
+       return d->error == 0; /* stop as soon as we successfully set one */
+}
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = keycode,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
+
+       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
+
+       return d.error;
+}
+
+/*
+ * Making beeps and bells. Note that we prefer beeps to bells, but when
+ * shutting the sound off we do both.
+ */
+
+static int kd_sound_helper(struct input_handle *handle, void *data)
+{
+       unsigned int *hz = data;
+       struct input_dev *dev = handle->dev;
+
+       if (test_bit(EV_SND, dev->evbit)) {
+               if (test_bit(SND_TONE, dev->sndbit)) {
+                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
+                       if (*hz)
+                               return 0;
+               }
+               if (test_bit(SND_BELL, dev->sndbit))
+                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
+       }
+
+       return 0;
+}
+
+static void kd_nosound(unsigned long ignored)
+{
+       static unsigned int zero;
+
+       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
+}
+
+static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
+
+void kd_mksound(unsigned int hz, unsigned int ticks)
+{
+       del_timer_sync(&kd_mksound_timer);
+
+       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
+
+       if (hz && ticks)
+               mod_timer(&kd_mksound_timer, jiffies + ticks);
+}
+EXPORT_SYMBOL(kd_mksound);
+
+/*
+ * Setting the keyboard rate.
+ */
+
+static int kbd_rate_helper(struct input_handle *handle, void *data)
+{
+       struct input_dev *dev = handle->dev;
+       struct kbd_repeat *rep = data;
+
+       if (test_bit(EV_REP, dev->evbit)) {
+
+               if (rep[0].delay > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_DELAY, rep[0].delay);
+               if (rep[0].period > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_PERIOD, rep[0].period);
+
+               rep[1].delay = dev->rep[REP_DELAY];
+               rep[1].period = dev->rep[REP_PERIOD];
+       }
+
+       return 0;
+}
+
+int kbd_rate(struct kbd_repeat *rep)
+{
+       struct kbd_repeat data[2] = { *rep };
+
+       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
+       *rep = data[1]; /* Copy currently used settings */
+
+       return 0;
+}
+
+/*
+ * Helper Functions.
+ */
+static void put_queue(struct vc_data *vc, int ch)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (tty) {
+               tty_insert_flip_char(tty, ch, 0);
+               con_schedule_flip(tty);
+       }
+}
+
+static void puts_queue(struct vc_data *vc, char *cp)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (!tty)
+               return;
+
+       while (*cp) {
+               tty_insert_flip_char(tty, *cp, 0);
+               cp++;
+       }
+       con_schedule_flip(tty);
+}
+
+static void applkey(struct vc_data *vc, int key, char mode)
+{
+       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
+
+       buf[1] = (mode ? 'O' : '[');
+       buf[2] = key;
+       puts_queue(vc, buf);
+}
+
+/*
+ * Many other routines do put_queue, but I think either
+ * they produce ASCII, or they produce some user-assigned
+ * string, and in both cases we might assume that it is
+ * in utf-8 already.
+ */
+static void to_utf8(struct vc_data *vc, uint c)
+{
+       if (c < 0x80)
+               /*  0******* */
+               put_queue(vc, c);
+       else if (c < 0x800) {
+               /* 110***** 10****** */
+               put_queue(vc, 0xc0 | (c >> 6));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       } else if (c < 0x10000) {
+               if (c >= 0xD800 && c < 0xE000)
+                       return;
+               if (c == 0xFFFF)
+                       return;
+               /* 1110**** 10****** 10****** */
+               put_queue(vc, 0xe0 | (c >> 12));
+               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       } else if (c < 0x110000) {
+               /* 11110*** 10****** 10****** 10****** */
+               put_queue(vc, 0xf0 | (c >> 18));
+               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
+               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       }
+}
+
+/*
+ * Called after returning from RAW mode or when changing consoles - recompute
+ * shift_down[] and shift_state from key_down[] maybe called when keymap is
+ * undefined, so that shiftkey release is seen
+ */
+void compute_shiftstate(void)
+{
+       unsigned int i, j, k, sym, val;
+
+       shift_state = 0;
+       memset(shift_down, 0, sizeof(shift_down));
+
+       for (i = 0; i < ARRAY_SIZE(key_down); i++) {
+
+               if (!key_down[i])
+                       continue;
+
+               k = i * BITS_PER_LONG;
+
+               for (j = 0; j < BITS_PER_LONG; j++, k++) {
+
+                       if (!test_bit(k, key_down))
+                               continue;
+
+                       sym = U(key_maps[0][k]);
+                       if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
+                               continue;
+
+                       val = KVAL(sym);
+                       if (val == KVAL(K_CAPSSHIFT))
+                               val = KVAL(K_SHIFT);
+
+                       shift_down[val]++;
+                       shift_state |= (1 << val);
+               }
+       }
+}
+
+/*
+ * We have a combining character DIACR here, followed by the character CH.
+ * If the combination occurs in the table, return the corresponding value.
+ * Otherwise, if CH is a space or equals DIACR, return DIACR.
+ * Otherwise, conclude that DIACR was not combining after all,
+ * queue it and return CH.
+ */
+static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
+{
+       unsigned int d = diacr;
+       unsigned int i;
+
+       diacr = 0;
+
+       if ((d & ~0xff) == BRL_UC_ROW) {
+               if ((ch & ~0xff) == BRL_UC_ROW)
+                       return d | ch;
+       } else {
+               for (i = 0; i < accent_table_size; i++)
+                       if (accent_table[i].diacr == d && accent_table[i].base == ch)
+                               return accent_table[i].result;
+       }
+
+       if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
+               return d;
+
+       if (kbd->kbdmode == VC_UNICODE)
+               to_utf8(vc, d);
+       else {
+               int c = conv_uni_to_8bit(d);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
+
+       return ch;
+}
+
+/*
+ * Special function handlers
+ */
+static void fn_enter(struct vc_data *vc)
+{
+       if (diacr) {
+               if (kbd->kbdmode == VC_UNICODE)
+                       to_utf8(vc, diacr);
+               else {
+                       int c = conv_uni_to_8bit(diacr);
+                       if (c != -1)
+                               put_queue(vc, c);
+               }
+               diacr = 0;
+       }
+
+       put_queue(vc, 13);
+       if (vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(vc, 10);
+}
+
+static void fn_caps_toggle(struct vc_data *vc)
+{
+       if (rep)
+               return;
+
+       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void fn_caps_on(struct vc_data *vc)
+{
+       if (rep)
+               return;
+
+       set_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void fn_show_ptregs(struct vc_data *vc)
+{
+       struct pt_regs *regs = get_irq_regs();
+
+       if (regs)
+               show_regs(regs);
+}
+
+static void fn_hold(struct vc_data *vc)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (rep || !tty)
+               return;
+
+       /*
+        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
+        * these routines are also activated by ^S/^Q.
+        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
+        */
+       if (tty->stopped)
+               start_tty(tty);
+       else
+               stop_tty(tty);
+}
+
+static void fn_num(struct vc_data *vc)
+{
+       if (vc_kbd_mode(kbd, VC_APPLIC))
+               applkey(vc, 'P', 1);
+       else
+               fn_bare_num(vc);
+}
+
+/*
+ * Bind this to Shift-NumLock if you work in application keypad mode
+ * but want to be able to change the NumLock flag.
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+static void fn_bare_num(struct vc_data *vc)
+{
+       if (!rep)
+               chg_vc_kbd_led(kbd, VC_NUMLOCK);
+}
+
+static void fn_lastcons(struct vc_data *vc)
+{
+       /* switch to the last used console, ChN */
+       set_console(last_console);
+}
+
+static void fn_dec_console(struct vc_data *vc)
+{
+       int i, cur = fg_console;
+
+       /* Currently switching?  Queue this next switch relative to that. */
+       if (want_console != -1)
+               cur = want_console;
+
+       for (i = cur - 1; i != cur; i--) {
+               if (i == -1)
+                       i = MAX_NR_CONSOLES - 1;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void fn_inc_console(struct vc_data *vc)
+{
+       int i, cur = fg_console;
+
+       /* Currently switching?  Queue this next switch relative to that. */
+       if (want_console != -1)
+               cur = want_console;
+
+       for (i = cur+1; i != cur; i++) {
+               if (i == MAX_NR_CONSOLES)
+                       i = 0;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void fn_send_intr(struct vc_data *vc)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (!tty)
+               return;
+       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       con_schedule_flip(tty);
+}
+
+static void fn_scroll_forw(struct vc_data *vc)
+{
+       scrollfront(vc, 0);
+}
+
+static void fn_scroll_back(struct vc_data *vc)
+{
+       scrollback(vc, 0);
+}
+
+static void fn_show_mem(struct vc_data *vc)
+{
+       show_mem();
+}
+
+static void fn_show_state(struct vc_data *vc)
+{
+       show_state();
+}
+
+static void fn_boot_it(struct vc_data *vc)
+{
+       ctrl_alt_del();
+}
+
+static void fn_compose(struct vc_data *vc)
+{
+       dead_key_next = true;
+}
+
+static void fn_spawn_con(struct vc_data *vc)
+{
+       spin_lock(&vt_spawn_con.lock);
+       if (vt_spawn_con.pid)
+               if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
+                       put_pid(vt_spawn_con.pid);
+                       vt_spawn_con.pid = NULL;
+               }
+       spin_unlock(&vt_spawn_con.lock);
+}
+
+static void fn_SAK(struct vc_data *vc)
+{
+       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+       schedule_work(SAK_work);
+}
+
+static void fn_null(struct vc_data *vc)
+{
+       compute_shiftstate();
+}
+
+/*
+ * Special key handlers
+ */
+static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
+{
+}
+
+static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+       if (value >= ARRAY_SIZE(fn_handler))
+               return;
+       if ((kbd->kbdmode == VC_RAW ||
+            kbd->kbdmode == VC_MEDIUMRAW) &&
+            value != KVAL(K_SAK))
+               return;         /* SAK is allowed even in raw mode */
+       fn_handler[value](vc);
+}
+
+static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       pr_err("k_lowercase was called - impossible\n");
+}
+
+static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
+{
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       if (diacr)
+               value = handle_diacr(vc, value);
+
+       if (dead_key_next) {
+               dead_key_next = false;
+               diacr = value;
+               return;
+       }
+       if (kbd->kbdmode == VC_UNICODE)
+               to_utf8(vc, value);
+       else {
+               int c = conv_uni_to_8bit(value);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
+}
+
+/*
+ * Handle dead key. Note that we now may have several
+ * dead keys modifying the same character. Very useful
+ * for Vietnamese.
+ */
+static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       diacr = (diacr ? handle_diacr(vc, value) : value);
+}
+
+static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
+}
+
+static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_deadunicode(vc, value, up_flag);
+}
+
+/*
+ * Obsolete - for backwards compatibility only
+ */
+static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+
+       k_deadunicode(vc, ret_diacr[value], up_flag);
+}
+
+static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       set_console(value);
+}
+
+static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if ((unsigned)value < ARRAY_SIZE(func_table)) {
+               if (func_table[value])
+                       puts_queue(vc, func_table[value]);
+       } else
+               pr_err("k_fn called with value=%d\n", value);
+}
+
+static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const char cur_chars[] = "BDCA";
+
+       if (up_flag)
+               return;
+
+       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+}
+
+static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const char pad_chars[] = "0123456789+-*/\015,.?()#";
+       static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
+
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       /* kludge... shift forces cursor/number keys */
+       if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
+               applkey(vc, app_map[value], 1);
+               return;
+       }
+
+       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
+
+               switch (value) {
+               case KVAL(K_PCOMMA):
+               case KVAL(K_PDOT):
+                       k_fn(vc, KVAL(K_REMOVE), 0);
+                       return;
+               case KVAL(K_P0):
+                       k_fn(vc, KVAL(K_INSERT), 0);
+                       return;
+               case KVAL(K_P1):
+                       k_fn(vc, KVAL(K_SELECT), 0);
+                       return;
+               case KVAL(K_P2):
+                       k_cur(vc, KVAL(K_DOWN), 0);
+                       return;
+               case KVAL(K_P3):
+                       k_fn(vc, KVAL(K_PGDN), 0);
+                       return;
+               case KVAL(K_P4):
+                       k_cur(vc, KVAL(K_LEFT), 0);
+                       return;
+               case KVAL(K_P6):
+                       k_cur(vc, KVAL(K_RIGHT), 0);
+                       return;
+               case KVAL(K_P7):
+                       k_fn(vc, KVAL(K_FIND), 0);
+                       return;
+               case KVAL(K_P8):
+                       k_cur(vc, KVAL(K_UP), 0);
+                       return;
+               case KVAL(K_P9):
+                       k_fn(vc, KVAL(K_PGUP), 0);
+                       return;
+               case KVAL(K_P5):
+                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
+                       return;
+               }
+       }
+
+       put_queue(vc, pad_chars[value]);
+       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(vc, 10);
+}
+
+static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       int old_state = shift_state;
+
+       if (rep)
+               return;
+       /*
+        * Mimic typewriter:
+        * a CapsShift key acts like Shift but undoes CapsLock
+        */
+       if (value == KVAL(K_CAPSSHIFT)) {
+               value = KVAL(K_SHIFT);
+               if (!up_flag)
+                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
+       }
+
+       if (up_flag) {
+               /*
+                * handle the case that two shift or control
+                * keys are depressed simultaneously
+                */
+               if (shift_down[value])
+                       shift_down[value]--;
+       } else
+               shift_down[value]++;
+
+       if (shift_down[value])
+               shift_state |= (1 << value);
+       else
+               shift_state &= ~(1 << value);
+
+       /* kludge */
+       if (up_flag && shift_state != old_state && npadch != -1) {
+               if (kbd->kbdmode == VC_UNICODE)
+                       to_utf8(vc, npadch);
+               else
+                       put_queue(vc, npadch & 0xff);
+               npadch = -1;
+       }
+}
+
+static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if (vc_kbd_mode(kbd, VC_META)) {
+               put_queue(vc, '\033');
+               put_queue(vc, value);
+       } else
+               put_queue(vc, value | 0x80);
+}
+
+static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       int base;
+
+       if (up_flag)
+               return;
+
+       if (value < 10) {
+               /* decimal input of code, while Alt depressed */
+               base = 10;
+       } else {
+               /* hexadecimal input of code, while AltGr depressed */
+               value -= 10;
+               base = 16;
+       }
+
+       if (npadch == -1)
+               npadch = value;
+       else
+               npadch = npadch * base + value;
+}
+
+static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag || rep)
+               return;
+
+       chg_vc_kbd_lock(kbd, value);
+}
+
+static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_shift(vc, value, up_flag);
+       if (up_flag || rep)
+               return;
+
+       chg_vc_kbd_slock(kbd, value);
+       /* try to make Alt, oops, AltGr and such work */
+       if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
+               kbd->slockstate = 0;
+               chg_vc_kbd_slock(kbd, value);
+       }
+}
+
+/* by default, 300ms interval for combination release */
+static unsigned brl_timeout = 300;
+MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
+module_param(brl_timeout, uint, 0644);
+
+static unsigned brl_nbchords = 1;
+MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
+module_param(brl_nbchords, uint, 0644);
+
+static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
+{
+       static unsigned long chords;
+       static unsigned committed;
+
+       if (!brl_nbchords)
+               k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
+       else {
+               committed |= pattern;
+               chords++;
+               if (chords == brl_nbchords) {
+                       k_unicode(vc, BRL_UC_ROW | committed, up_flag);
+                       chords = 0;
+                       committed = 0;
+               }
+       }
+}
+
+static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static unsigned pressed, committing;
+       static unsigned long releasestart;
+
+       if (kbd->kbdmode != VC_UNICODE) {
+               if (!up_flag)
+                       pr_warning("keyboard mode must be unicode for braille patterns\n");
+               return;
+       }
+
+       if (!value) {
+               k_unicode(vc, BRL_UC_ROW, up_flag);
+               return;
+       }
+
+       if (value > 8)
+               return;
+
+       if (!up_flag) {
+               pressed |= 1 << (value - 1);
+               if (!brl_timeout)
+                       committing = pressed;
+       } else if (brl_timeout) {
+               if (!committing ||
+                   time_after(jiffies,
+                              releasestart + msecs_to_jiffies(brl_timeout))) {
+                       committing = pressed;
+                       releasestart = jiffies;
+               }
+               pressed &= ~(1 << (value - 1));
+               if (!pressed && committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+       } else {
+               if (committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+               pressed &= ~(1 << (value - 1));
+       }
+}
+
+/*
+ * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+ * or (ii) whatever pattern of lights people want to show using KDSETLED,
+ * or (iii) specified bits of specified words in kernel memory.
+ */
+unsigned char getledstate(void)
+{
+       return ledstate;
+}
+
+void setledstate(struct kbd_struct *kbd, unsigned int led)
+{
+       if (!(led & ~7)) {
+               ledioctl = led;
+               kbd->ledmode = LED_SHOW_IOCTL;
+       } else
+               kbd->ledmode = LED_SHOW_FLAGS;
+
+       set_leds();
+}
+
+static inline unsigned char getleds(void)
+{
+       struct kbd_struct *kbd = kbd_table + fg_console;
+       unsigned char leds;
+       int i;
+
+       if (kbd->ledmode == LED_SHOW_IOCTL)
+               return ledioctl;
+
+       leds = kbd->ledflagstate;
+
+       if (kbd->ledmode == LED_SHOW_MEM) {
+               for (i = 0; i < 3; i++)
+                       if (ledptrs[i].valid) {
+                               if (*ledptrs[i].addr & ledptrs[i].mask)
+                                       leds |= (1 << i);
+                               else
+                                       leds &= ~(1 << i);
+                       }
+       }
+       return leds;
+}
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+       unsigned char leds = *(unsigned char *)data;
+
+       if (test_bit(EV_LED, handle->dev->evbit)) {
+               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
+               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * This is the tasklet that updates LED state on all keyboards
+ * attached to the box. The reason we use tasklet is that we
+ * need to handle the scenario when keyboard handler is not
+ * registered yet but we already getting updates form VT to
+ * update led state.
+ */
+static void kbd_bh(unsigned long dummy)
+{
+       unsigned char leds = getleds();
+
+       if (leds != ledstate) {
+               input_handler_for_each_handle(&kbd_handler, &leds,
+                                             kbd_update_leds_helper);
+               ledstate = leds;
+       }
+}
+
+DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
+
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
+    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
+    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
+    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
+    defined(CONFIG_AVR32)
+
+#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
+                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+
+static const unsigned short x86_keycodes[256] =
+       { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+        80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
+       284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
+       367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
+       360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
+       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
+       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
+       264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
+       377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
+       308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
+       332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
+
+#ifdef CONFIG_SPARC
+static int sparc_l1_a_state;
+extern void sun_do_break(void);
+#endif
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode,
+                      unsigned char up_flag)
+{
+       int code;
+
+       switch (keycode) {
+
+       case KEY_PAUSE:
+               put_queue(vc, 0xe1);
+               put_queue(vc, 0x1d | up_flag);
+               put_queue(vc, 0x45 | up_flag);
+               break;
+
+       case KEY_HANGEUL:
+               if (!up_flag)
+                       put_queue(vc, 0xf2);
+               break;
+
+       case KEY_HANJA:
+               if (!up_flag)
+                       put_queue(vc, 0xf1);
+               break;
+
+       case KEY_SYSRQ:
+               /*
+                * Real AT keyboards (that's what we're trying
+                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
+                * pressing PrtSc/SysRq alone, but simply 0x54
+                * when pressing Alt+PrtSc/SysRq.
+                */
+               if (test_bit(KEY_LEFTALT, key_down) ||
+                   test_bit(KEY_RIGHTALT, key_down)) {
+                       put_queue(vc, 0x54 | up_flag);
+               } else {
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x2a | up_flag);
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x37 | up_flag);
+               }
+               break;
+
+       default:
+               if (keycode > 255)
+                       return -1;
+
+               code = x86_keycodes[keycode];
+               if (!code)
+                       return -1;
+
+               if (code & 0x100)
+                       put_queue(vc, 0xe0);
+               put_queue(vc, (code & 0x7f) | up_flag);
+
+               break;
+       }
+
+       return 0;
+}
+
+#else
+
+#define HW_RAW(dev)    0
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
+{
+       if (keycode > 127)
+               return -1;
+
+       put_queue(vc, keycode | up_flag);
+       return 0;
+}
+#endif
+
+static void kbd_rawcode(unsigned char data)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+
+       kbd = kbd_table + vc->vc_num;
+       if (kbd->kbdmode == VC_RAW)
+               put_queue(vc, data);
+}
+
+static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       unsigned short keysym, *key_map;
+       unsigned char type;
+       bool raw_mode;
+       struct tty_struct *tty;
+       int shift_final;
+       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
+       int rc;
+
+       tty = vc->port.tty;
+
+       if (tty && (!tty->driver_data)) {
+               /* No driver data? Strange. Okay we fix it then. */
+               tty->driver_data = vc;
+       }
+
+       kbd = kbd_table + vc->vc_num;
+
+#ifdef CONFIG_SPARC
+       if (keycode == KEY_STOP)
+               sparc_l1_a_state = down;
+#endif
+
+       rep = (down == 2);
+
+       raw_mode = (kbd->kbdmode == VC_RAW);
+       if (raw_mode && !hw_raw)
+               if (emulate_raw(vc, keycode, !down << 7))
+                       if (keycode < BTN_MISC && printk_ratelimit())
+                               pr_warning("can't emulate rawmode for keycode %d\n",
+                                          keycode);
+
+#ifdef CONFIG_SPARC
+       if (keycode == KEY_A && sparc_l1_a_state) {
+               sparc_l1_a_state = false;
+               sun_do_break();
+       }
+#endif
+
+       if (kbd->kbdmode == VC_MEDIUMRAW) {
+               /*
+                * This is extended medium raw mode, with keys above 127
+                * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
+                * the 'up' flag if needed. 0 is reserved, so this shouldn't
+                * interfere with anything else. The two bytes after 0 will
+                * always have the up flag set not to interfere with older
+                * applications. This allows for 16384 different keycodes,
+                * which should be enough.
+                */
+               if (keycode < 128) {
+                       put_queue(vc, keycode | (!down << 7));
+               } else {
+                       put_queue(vc, !down << 7);
+                       put_queue(vc, (keycode >> 7) | 0x80);
+                       put_queue(vc, keycode | 0x80);
+               }
+               raw_mode = true;
+       }
+
+       if (down)
+               set_bit(keycode, key_down);
+       else
+               clear_bit(keycode, key_down);
+
+       if (rep &&
+           (!vc_kbd_mode(kbd, VC_REPEAT) ||
+            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
+               /*
+                * Don't repeat a key if the input buffers are not empty and the
+                * characters get aren't echoed locally. This makes key repeat
+                * usable with slow applications and under heavy loads.
+                */
+               return;
+       }
+
+       param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+       param.ledstate = kbd->ledflagstate;
+       key_map = key_maps[shift_final];
+
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYCODE, &param);
+       if (rc == NOTIFY_STOP || !key_map) {
+               atomic_notifier_call_chain(&keyboard_notifier_list,
+                                          KBD_UNBOUND_KEYCODE, &param);
+               compute_shiftstate();
+               kbd->slockstate = 0;
+               return;
+       }
+
+       if (keycode < NR_KEYS)
+               keysym = key_map[keycode];
+       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
+               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
+       else
+               return;
+
+       type = KTYP(keysym);
+
+       if (type < 0xf0) {
+               param.value = keysym;
+               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                               KBD_UNICODE, &param);
+               if (rc != NOTIFY_STOP)
+                       if (down && !raw_mode)
+                               to_utf8(vc, keysym);
+               return;
+       }
+
+       type -= 0xf0;
+
+       if (type == KT_LETTER) {
+               type = KT_LATIN;
+               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+                       key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+                       if (key_map)
+                               keysym = key_map[keycode];
+               }
+       }
+
+       param.value = keysym;
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYSYM, &param);
+       if (rc == NOTIFY_STOP)
+               return;
+
+       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+               return;
+
+       (*k_handler[type])(vc, keysym & 0xff, !down);
+
+       param.ledstate = kbd->ledflagstate;
+       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
+
+       if (type != KT_SLOCK)
+               kbd->slockstate = 0;
+}
+
+static void kbd_event(struct input_handle *handle, unsigned int event_type,
+                     unsigned int event_code, int value)
+{
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&kbd_event_lock);
+
+       if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
+               kbd_rawcode(value);
+       if (event_type == EV_KEY)
+               kbd_keycode(event_code, value, HW_RAW(handle->dev));
+
+       spin_unlock(&kbd_event_lock);
+
+       tasklet_schedule(&keyboard_tasklet);
+       do_poke_blanked_console = 1;
+       schedule_console_callback();
+}
+
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+       int i;
+
+       if (test_bit(EV_SND, dev->evbit))
+               return true;
+
+       if (test_bit(EV_KEY, dev->evbit)) {
+               for (i = KEY_RESERVED; i < BTN_MISC; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+       }
+
+       return false;
+}
+
+/*
+ * When a keyboard (or other input device) is found, the kbd_connect
+ * function is called. The function then looks at the device, and if it
+ * likes it, it can open it and get events from it. In this (kbd_connect)
+ * function, we should decide which VT to bind that keyboard to initially.
+ */
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+                       const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "kbd";
+
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
+
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
+
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
+}
+
+static void kbd_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+/*
+ * Start keyboard handler on the new keyboard by refreshing LED state to
+ * match the rest of the system.
+ */
+static void kbd_start(struct input_handle *handle)
+{
+       tasklet_disable(&keyboard_tasklet);
+
+       if (ledstate != 0xff)
+               kbd_update_leds_helper(handle, &ledstate);
+
+       tasklet_enable(&keyboard_tasklet);
+}
+
+static const struct input_device_id kbd_ids[] = {
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_KEY) },
+        },
+
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_SND) },
+        },
+
+       { },    /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, kbd_ids);
+
+static struct input_handler kbd_handler = {
+       .event          = kbd_event,
+       .match          = kbd_match,
+       .connect        = kbd_connect,
+       .disconnect     = kbd_disconnect,
+       .start          = kbd_start,
+       .name           = "kbd",
+       .id_table       = kbd_ids,
+};
+
+int __init kbd_init(void)
+{
+       int i;
+       int error;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               kbd_table[i].ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].ledmode = LED_SHOW_FLAGS;
+               kbd_table[i].lockstate = KBD_DEFLOCK;
+               kbd_table[i].slockstate = 0;
+               kbd_table[i].modeflags = KBD_DEFMODE;
+               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+       }
+
+       error = input_register_handler(&kbd_handler);
+       if (error)
+               return error;
+
+       tasklet_enable(&keyboard_tasklet);
+       tasklet_schedule(&keyboard_tasklet);
+
+       return 0;
+}
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
new file mode 100644 (file)
index 0000000..ebae344
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * linux/drivers/char/selection.c
+ *
+ * This module exports the functions:
+ *
+ *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
+ *     'void clear_selection(void)'
+ *     'int paste_selection(struct tty_struct *)'
+ *     'int sel_loadlut(char __user *)'
+ *
+ * Now that /dev/vcs exists, most of this can disappear again.
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/tiocl.h>
+#include <linux/console.h>
+#include <linux/smp_lock.h>
+
+/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
+#define isspace(c)     ((c) == ' ')
+
+extern void poke_blanked_console(void);
+
+/* Variables for selection control. */
+/* Use a dynamic buffer, instead of static (Dec 1994) */
+struct vc_data *sel_cons;              /* must not be deallocated */
+static int use_unicode;
+static volatile int sel_start = -1;    /* cleared by clear_selection */
+static int sel_end;
+static int sel_buffer_lth;
+static char *sel_buffer;
+
+/* clear_selection, highlight and highlight_pointer can be called
+   from interrupt (via scrollback/front) */
+
+/* set reverse video on characters s-e of console with selection. */
+static inline void highlight(const int s, const int e)
+{
+       invert_screen(sel_cons, s, e-s+2, 1);
+}
+
+/* use complementary color to show the pointer */
+static inline void highlight_pointer(const int where)
+{
+       complement_pos(sel_cons, where);
+}
+
+static u16
+sel_pos(int n)
+{
+       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
+                               use_unicode);
+}
+
+/* remove the current selection highlight, if any,
+   from the console holding the selection. */
+void
+clear_selection(void) {
+       highlight_pointer(-1); /* hide the pointer */
+       if (sel_start != -1) {
+               highlight(sel_start, sel_end);
+               sel_start = -1;
+       }
+}
+
+/*
+ * User settable table: what characters are to be considered alphabetic?
+ * 256 bits
+ */
+static u32 inwordLut[8]={
+  0x00000000, /* control chars     */
+  0x03FF0000, /* digits            */
+  0x87FFFFFE, /* uppercase and '_' */
+  0x07FFFFFE, /* lowercase         */
+  0x00000000,
+  0x00000000,
+  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
+  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
+};
+
+static inline int inword(const u16 c) {
+       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
+}
+
+/* set inwordLut contents. Invoked by ioctl(). */
+int sel_loadlut(char __user *p)
+{
+       return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
+}
+
+/* does screen address p correspond to character at LH/RH edge of screen? */
+static inline int atedge(const int p, int size_row)
+{
+       return (!(p % size_row) || !((p + 2) % size_row));
+}
+
+/* constrain v such that v <= u */
+static inline unsigned short limit(const unsigned short v, const unsigned short u)
+{
+       return (v > u) ? u : v;
+}
+
+/* stores the char in UTF8 and returns the number of bytes used (1-3) */
+static int store_utf8(u16 c, char *p)
+{
+       if (c < 0x80) {
+               /*  0******* */
+               p[0] = c;
+               return 1;
+       } else if (c < 0x800) {
+               /* 110***** 10****** */
+               p[0] = 0xc0 | (c >> 6);
+               p[1] = 0x80 | (c & 0x3f);
+               return 2;
+       } else {
+               /* 1110**** 10****** 10****** */
+               p[0] = 0xe0 | (c >> 12);
+               p[1] = 0x80 | ((c >> 6) & 0x3f);
+               p[2] = 0x80 | (c & 0x3f);
+               return 3;
+       }
+}
+
+/* set the current selection. Invoked by ioctl() or by kernel code. */
+int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       int sel_mode, new_sel_start, new_sel_end, spc;
+       char *bp, *obp;
+       int i, ps, pe, multiplier;
+       u16 c;
+       struct kbd_struct *kbd = kbd_table + fg_console;
+
+       poke_blanked_console();
+
+       { unsigned short xs, ys, xe, ye;
+
+         if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
+               return -EFAULT;
+         __get_user(xs, &sel->xs);
+         __get_user(ys, &sel->ys);
+         __get_user(xe, &sel->xe);
+         __get_user(ye, &sel->ye);
+         __get_user(sel_mode, &sel->sel_mode);
+         xs--; ys--; xe--; ye--;
+         xs = limit(xs, vc->vc_cols - 1);
+         ys = limit(ys, vc->vc_rows - 1);
+         xe = limit(xe, vc->vc_cols - 1);
+         ye = limit(ye, vc->vc_rows - 1);
+         ps = ys * vc->vc_size_row + (xs << 1);
+         pe = ye * vc->vc_size_row + (xe << 1);
+
+         if (sel_mode == TIOCL_SELCLEAR) {
+             /* useful for screendump without selection highlights */
+             clear_selection();
+             return 0;
+         }
+
+         if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
+             mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
+             return 0;
+         }
+        }
+
+       if (ps > pe)    /* make sel_start <= sel_end */
+       {
+               int tmp = ps;
+               ps = pe;
+               pe = tmp;
+       }
+
+       if (sel_cons != vc_cons[fg_console].d) {
+               clear_selection();
+               sel_cons = vc_cons[fg_console].d;
+       }
+       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
+
+       switch (sel_mode)
+       {
+               case TIOCL_SELCHAR:     /* character-by-character selection */
+                       new_sel_start = ps;
+                       new_sel_end = pe;
+                       break;
+               case TIOCL_SELWORD:     /* word-by-word selection */
+                       spc = isspace(sel_pos(ps));
+                       for (new_sel_start = ps; ; ps -= 2)
+                       {
+                               if ((spc && !isspace(sel_pos(ps))) ||
+                                   (!spc && !inword(sel_pos(ps))))
+                                       break;
+                               new_sel_start = ps;
+                               if (!(ps % vc->vc_size_row))
+                                       break;
+                       }
+                       spc = isspace(sel_pos(pe));
+                       for (new_sel_end = pe; ; pe += 2)
+                       {
+                               if ((spc && !isspace(sel_pos(pe))) ||
+                                   (!spc && !inword(sel_pos(pe))))
+                                       break;
+                               new_sel_end = pe;
+                               if (!((pe + 2) % vc->vc_size_row))
+                                       break;
+                       }
+                       break;
+               case TIOCL_SELLINE:     /* line-by-line selection */
+                       new_sel_start = ps - ps % vc->vc_size_row;
+                       new_sel_end = pe + vc->vc_size_row
+                                   - pe % vc->vc_size_row - 2;
+                       break;
+               case TIOCL_SELPOINTER:
+                       highlight_pointer(pe);
+                       return 0;
+               default:
+                       return -EINVAL;
+       }
+
+       /* remove the pointer */
+       highlight_pointer(-1);
+
+       /* select to end of line if on trailing space */
+       if (new_sel_end > new_sel_start &&
+               !atedge(new_sel_end, vc->vc_size_row) &&
+               isspace(sel_pos(new_sel_end))) {
+               for (pe = new_sel_end + 2; ; pe += 2)
+                       if (!isspace(sel_pos(pe)) ||
+                           atedge(pe, vc->vc_size_row))
+                               break;
+               if (isspace(sel_pos(pe)))
+                       new_sel_end = pe;
+       }
+       if (sel_start == -1)    /* no current selection */
+               highlight(new_sel_start, new_sel_end);
+       else if (new_sel_start == sel_start)
+       {
+               if (new_sel_end == sel_end)     /* no action required */
+                       return 0;
+               else if (new_sel_end > sel_end) /* extend to right */
+                       highlight(sel_end + 2, new_sel_end);
+               else                            /* contract from right */
+                       highlight(new_sel_end + 2, sel_end);
+       }
+       else if (new_sel_end == sel_end)
+       {
+               if (new_sel_start < sel_start)  /* extend to left */
+                       highlight(new_sel_start, sel_start - 2);
+               else                            /* contract from left */
+                       highlight(sel_start, new_sel_start - 2);
+       }
+       else    /* some other case; start selection from scratch */
+       {
+               clear_selection();
+               highlight(new_sel_start, new_sel_end);
+       }
+       sel_start = new_sel_start;
+       sel_end = new_sel_end;
+
+       /* Allocate a new buffer before freeing the old one ... */
+       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
+       bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
+       if (!bp) {
+               printk(KERN_WARNING "selection: kmalloc() failed\n");
+               clear_selection();
+               return -ENOMEM;
+       }
+       kfree(sel_buffer);
+       sel_buffer = bp;
+
+       obp = bp;
+       for (i = sel_start; i <= sel_end; i += 2) {
+               c = sel_pos(i);
+               if (use_unicode)
+                       bp += store_utf8(c, bp);
+               else
+                       *bp++ = c;
+               if (!isspace(c))
+                       obp = bp;
+               if (! ((i + 2) % vc->vc_size_row)) {
+                       /* strip trailing blanks from line and add newline,
+                          unless non-space at end of line. */
+                       if (obp != bp) {
+                               bp = obp;
+                               *bp++ = '\r';
+                       }
+                       obp = bp;
+               }
+       }
+       sel_buffer_lth = bp - sel_buffer;
+       return 0;
+}
+
+/* Insert the contents of the selection buffer into the
+ * queue of the tty associated with the current console.
+ * Invoked by ioctl().
+ */
+int paste_selection(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       int     pasted = 0;
+       unsigned int count;
+       struct  tty_ldisc *ld;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /* always called with BTM from vt_ioctl */
+       WARN_ON(!tty_locked());
+
+       acquire_console_sem();
+       poke_blanked_console();
+       release_console_sem();
+
+       ld = tty_ldisc_ref(tty);
+       if (!ld) {
+               tty_unlock();
+               ld = tty_ldisc_ref_wait(tty);
+               tty_lock();
+       }
+
+       add_wait_queue(&vc->paste_wait, &wait);
+       while (sel_buffer && sel_buffer_lth > pasted) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (test_bit(TTY_THROTTLED, &tty->flags)) {
+                       schedule();
+                       continue;
+               }
+               count = sel_buffer_lth - pasted;
+               count = min(count, tty->receive_room);
+               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+                                                               NULL, count);
+               pasted += count;
+       }
+       remove_wait_queue(&vc->paste_wait, &wait);
+       __set_current_state(TASK_RUNNING);
+
+       tty_ldisc_deref(ld);
+       return 0;
+}
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
new file mode 100644 (file)
index 0000000..eab3a1f
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * linux/drivers/char/vc_screen.c
+ *
+ * Provide access to virtual console memory.
+ * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
+ * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
+ *            [minor: N]
+ *
+ * /dev/vcsaN: idem, but including attributes, and prefixed with
+ *     the 4 bytes lines,columns,x,y (as screendump used to give).
+ *     Attribute/character pair is in native endianity.
+ *            [minor: N+128]
+ *
+ * This replaces screendump and part of selection, so that the system
+ * administrator can control access using file system permissions.
+ *
+ * aeb@cwi.nl - efter Friedas begravelse - 950211
+ *
+ * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
+ *      - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
+ *      - making it shorter - scr_readw are macros which expand in PRETTY long code
+ */
+
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/kbd_kern.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+#undef attr
+#undef org
+#undef addr
+#define HEADER_SIZE    4
+
+struct vcs_poll_data {
+       struct notifier_block notifier;
+       unsigned int cons_num;
+       bool seen_last_update;
+       wait_queue_head_t waitq;
+       struct fasync_struct *fasync;
+};
+
+static int
+vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
+{
+       struct vt_notifier_param *param = _param;
+       struct vc_data *vc = param->vc;
+       struct vcs_poll_data *poll =
+               container_of(nb, struct vcs_poll_data, notifier);
+       int currcons = poll->cons_num;
+
+       if (code != VT_UPDATE)
+               return NOTIFY_DONE;
+
+       if (currcons == 0)
+               currcons = fg_console;
+       else
+               currcons--;
+       if (currcons != vc->vc_num)
+               return NOTIFY_DONE;
+
+       poll->seen_last_update = false;
+       wake_up_interruptible(&poll->waitq);
+       kill_fasync(&poll->fasync, SIGIO, POLL_IN);
+       return NOTIFY_OK;
+}
+
+static void
+vcs_poll_data_free(struct vcs_poll_data *poll)
+{
+       unregister_vt_notifier(&poll->notifier);
+       kfree(poll);
+}
+
+static struct vcs_poll_data *
+vcs_poll_data_get(struct file *file)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (poll)
+               return poll;
+
+       poll = kzalloc(sizeof(*poll), GFP_KERNEL);
+       if (!poll)
+               return NULL;
+       poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
+       init_waitqueue_head(&poll->waitq);
+       poll->notifier.notifier_call = vcs_notifier;
+       if (register_vt_notifier(&poll->notifier) != 0) {
+               kfree(poll);
+               return NULL;
+       }
+
+       /*
+        * This code may be called either through ->poll() or ->fasync().
+        * If we have two threads using the same file descriptor, they could
+        * both enter this function, both notice that the structure hasn't
+        * been allocated yet and go ahead allocating it in parallel, but
+        * only one of them must survive and be shared otherwise we'd leak
+        * memory with a dangling notifier callback.
+        */
+       spin_lock(&file->f_lock);
+       if (!file->private_data) {
+               file->private_data = poll;
+       } else {
+               /* someone else raced ahead of us */
+               vcs_poll_data_free(poll);
+               poll = file->private_data;
+       }
+       spin_unlock(&file->f_lock);
+
+       return poll;
+}
+
+static int
+vcs_size(struct inode *inode)
+{
+       int size;
+       int minor = iminor(inode);
+       int currcons = minor & 127;
+       struct vc_data *vc;
+
+       if (currcons == 0)
+               currcons = fg_console;
+       else
+               currcons--;
+       if (!vc_cons_allocated(currcons))
+               return -ENXIO;
+       vc = vc_cons[currcons].d;
+
+       size = vc->vc_rows * vc->vc_cols;
+
+       if (minor & 128)
+               size = 2*size + HEADER_SIZE;
+       return size;
+}
+
+static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
+{
+       int size;
+
+       mutex_lock(&con_buf_mtx);
+       size = vcs_size(file->f_path.dentry->d_inode);
+       switch (orig) {
+               default:
+                       mutex_unlock(&con_buf_mtx);
+                       return -EINVAL;
+               case 2:
+                       offset += size;
+                       break;
+               case 1:
+                       offset += file->f_pos;
+               case 0:
+                       break;
+       }
+       if (offset < 0 || offset > size) {
+               mutex_unlock(&con_buf_mtx);
+               return -EINVAL;
+       }
+       file->f_pos = offset;
+       mutex_unlock(&con_buf_mtx);
+       return file->f_pos;
+}
+
+
+static ssize_t
+vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       unsigned int currcons = iminor(inode);
+       struct vc_data *vc;
+       struct vcs_poll_data *poll;
+       long pos;
+       long viewed, attr, read;
+       int col, maxcol;
+       unsigned short *org = NULL;
+       ssize_t ret;
+
+       mutex_lock(&con_buf_mtx);
+
+       pos = *ppos;
+
+       /* Select the proper current console and verify
+        * sanity of the situation under the console lock.
+        */
+       acquire_console_sem();
+
+       attr = (currcons & 128);
+       currcons = (currcons & 127);
+       if (currcons == 0) {
+               currcons = fg_console;
+               viewed = 1;
+       } else {
+               currcons--;
+               viewed = 0;
+       }
+       ret = -ENXIO;
+       if (!vc_cons_allocated(currcons))
+               goto unlock_out;
+       vc = vc_cons[currcons].d;
+
+       ret = -EINVAL;
+       if (pos < 0)
+               goto unlock_out;
+       poll = file->private_data;
+       if (count && poll)
+               poll->seen_last_update = true;
+       read = 0;
+       ret = 0;
+       while (count) {
+               char *con_buf0, *con_buf_start;
+               long this_round, size;
+               ssize_t orig_count;
+               long p = pos;
+
+               /* Check whether we are above size each round,
+                * as copy_to_user at the end of this loop
+                * could sleep.
+                */
+               size = vcs_size(inode);
+               if (pos >= size)
+                       break;
+               if (count > size - pos)
+                       count = size - pos;
+
+               this_round = count;
+               if (this_round > CON_BUF_SIZE)
+                       this_round = CON_BUF_SIZE;
+
+               /* Perform the whole read into the local con_buf.
+                * Then we can drop the console spinlock and safely
+                * attempt to move it to userspace.
+                */
+
+               con_buf_start = con_buf0 = con_buf;
+               orig_count = this_round;
+               maxcol = vc->vc_cols;
+               if (!attr) {
+                       org = screen_pos(vc, p, viewed);
+                       col = p % maxcol;
+                       p += maxcol - col;
+                       while (this_round-- > 0) {
+                               *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+               } else {
+                       if (p < HEADER_SIZE) {
+                               size_t tmp_count;
+
+                               con_buf0[0] = (char)vc->vc_rows;
+                               con_buf0[1] = (char)vc->vc_cols;
+                               getconsxy(vc, con_buf0 + 2);
+
+                               con_buf_start += p;
+                               this_round += p;
+                               if (this_round > CON_BUF_SIZE) {
+                                       this_round = CON_BUF_SIZE;
+                                       orig_count = this_round - p;
+                               }
+
+                               tmp_count = HEADER_SIZE;
+                               if (tmp_count > this_round)
+                                       tmp_count = this_round;
+
+                               /* Advance state pointers and move on. */
+                               this_round -= tmp_count;
+                               p = HEADER_SIZE;
+                               con_buf0 = con_buf + HEADER_SIZE;
+                               /* If this_round >= 0, then p is even... */
+                       } else if (p & 1) {
+                               /* Skip first byte for output if start address is odd
+                                * Update region sizes up/down depending on free
+                                * space in buffer.
+                                */
+                               con_buf_start++;
+                               if (this_round < CON_BUF_SIZE)
+                                       this_round++;
+                               else
+                                       orig_count--;
+                       }
+                       if (this_round > 0) {
+                               unsigned short *tmp_buf = (unsigned short *)con_buf0;
+
+                               p -= HEADER_SIZE;
+                               p /= 2;
+                               col = p % maxcol;
+
+                               org = screen_pos(vc, p, viewed);
+                               p += maxcol - col;
+
+                               /* Buffer has even length, so we can always copy
+                                * character + attribute. We do not copy last byte
+                                * to userspace if this_round is odd.
+                                */
+                               this_round = (this_round + 1) >> 1;
+
+                               while (this_round) {
+                                       *tmp_buf++ = vcs_scr_readw(vc, org++);
+                                       this_round --;
+                                       if (++col == maxcol) {
+                                               org = screen_pos(vc, p, viewed);
+                                               col = 0;
+                                               p += maxcol;
+                                       }
+                               }
+                       }
+               }
+
+               /* Finally, release the console semaphore while we push
+                * all the data to userspace from our temporary buffer.
+                *
+                * AKPM: Even though it's a semaphore, we should drop it because
+                * the pagefault handling code may want to call printk().
+                */
+
+               release_console_sem();
+               ret = copy_to_user(buf, con_buf_start, orig_count);
+               acquire_console_sem();
+
+               if (ret) {
+                       read += (orig_count - ret);
+                       ret = -EFAULT;
+                       break;
+               }
+               buf += orig_count;
+               pos += orig_count;
+               read += orig_count;
+               count -= orig_count;
+       }
+       *ppos += read;
+       if (read)
+               ret = read;
+unlock_out:
+       release_console_sem();
+       mutex_unlock(&con_buf_mtx);
+       return ret;
+}
+
+static ssize_t
+vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       unsigned int currcons = iminor(inode);
+       struct vc_data *vc;
+       long pos;
+       long viewed, attr, size, written;
+       char *con_buf0;
+       int col, maxcol;
+       u16 *org0 = NULL, *org = NULL;
+       size_t ret;
+
+       mutex_lock(&con_buf_mtx);
+
+       pos = *ppos;
+
+       /* Select the proper current console and verify
+        * sanity of the situation under the console lock.
+        */
+       acquire_console_sem();
+
+       attr = (currcons & 128);
+       currcons = (currcons & 127);
+
+       if (currcons == 0) {
+               currcons = fg_console;
+               viewed = 1;
+       } else {
+               currcons--;
+               viewed = 0;
+       }
+       ret = -ENXIO;
+       if (!vc_cons_allocated(currcons))
+               goto unlock_out;
+       vc = vc_cons[currcons].d;
+
+       size = vcs_size(inode);
+       ret = -EINVAL;
+       if (pos < 0 || pos > size)
+               goto unlock_out;
+       if (count > size - pos)
+               count = size - pos;
+       written = 0;
+       while (count) {
+               long this_round = count;
+               size_t orig_count;
+               long p;
+
+               if (this_round > CON_BUF_SIZE)
+                       this_round = CON_BUF_SIZE;
+
+               /* Temporarily drop the console lock so that we can read
+                * in the write data from userspace safely.
+                */
+               release_console_sem();
+               ret = copy_from_user(con_buf, buf, this_round);
+               acquire_console_sem();
+
+               if (ret) {
+                       this_round -= ret;
+                       if (!this_round) {
+                               /* Abort loop if no data were copied. Otherwise
+                                * fail with -EFAULT.
+                                */
+                               if (written)
+                                       break;
+                               ret = -EFAULT;
+                               goto unlock_out;
+                       }
+               }
+
+               /* The vcs_size might have changed while we slept to grab
+                * the user buffer, so recheck.
+                * Return data written up to now on failure.
+                */
+               size = vcs_size(inode);
+               if (pos >= size)
+                       break;
+               if (this_round > size - pos)
+                       this_round = size - pos;
+
+               /* OK, now actually push the write to the console
+                * under the lock using the local kernel buffer.
+                */
+
+               con_buf0 = con_buf;
+               orig_count = this_round;
+               maxcol = vc->vc_cols;
+               p = pos;
+               if (!attr) {
+                       org0 = org = screen_pos(vc, p, viewed);
+                       col = p % maxcol;
+                       p += maxcol - col;
+
+                       while (this_round > 0) {
+                               unsigned char c = *con_buf0++;
+
+                               this_round--;
+                               vcs_scr_writew(vc,
+                                              (vcs_scr_readw(vc, org) & 0xff00) | c, org);
+                               org++;
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+               } else {
+                       if (p < HEADER_SIZE) {
+                               char header[HEADER_SIZE];
+
+                               getconsxy(vc, header + 2);
+                               while (p < HEADER_SIZE && this_round > 0) {
+                                       this_round--;
+                                       header[p++] = *con_buf0++;
+                               }
+                               if (!viewed)
+                                       putconsxy(vc, header + 2);
+                       }
+                       p -= HEADER_SIZE;
+                       col = (p/2) % maxcol;
+                       if (this_round > 0) {
+                               org0 = org = screen_pos(vc, p/2, viewed);
+                               if ((p & 1) && this_round > 0) {
+                                       char c;
+
+                                       this_round--;
+                                       c = *con_buf0++;
+#ifdef __BIG_ENDIAN
+                                       vcs_scr_writew(vc, c |
+                                            (vcs_scr_readw(vc, org) & 0xff00), org);
+#else
+                                       vcs_scr_writew(vc, (c << 8) |
+                                            (vcs_scr_readw(vc, org) & 0xff), org);
+#endif
+                                       org++;
+                                       p++;
+                                       if (++col == maxcol) {
+                                               org = screen_pos(vc, p/2, viewed);
+                                               col = 0;
+                                       }
+                               }
+                               p /= 2;
+                               p += maxcol - col;
+                       }
+                       while (this_round > 1) {
+                               unsigned short w;
+
+                               w = get_unaligned(((unsigned short *)con_buf0));
+                               vcs_scr_writew(vc, w, org++);
+                               con_buf0 += 2;
+                               this_round -= 2;
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+                       if (this_round > 0) {
+                               unsigned char c;
+
+                               c = *con_buf0++;
+#ifdef __BIG_ENDIAN
+                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
+#else
+                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
+#endif
+                       }
+               }
+               count -= orig_count;
+               written += orig_count;
+               buf += orig_count;
+               pos += orig_count;
+               if (org0)
+                       update_region(vc, (unsigned long)(org0), org - org0);
+       }
+       *ppos += written;
+       ret = written;
+       if (written)
+               vcs_scr_updated(vc);
+
+unlock_out:
+       release_console_sem();
+
+       mutex_unlock(&con_buf_mtx);
+
+       return ret;
+}
+
+static unsigned int
+vcs_poll(struct file *file, poll_table *wait)
+{
+       struct vcs_poll_data *poll = vcs_poll_data_get(file);
+       int ret = DEFAULT_POLLMASK|POLLERR|POLLPRI;
+
+       if (poll) {
+               poll_wait(file, &poll->waitq, wait);
+               if (poll->seen_last_update)
+                       ret = DEFAULT_POLLMASK;
+       }
+       return ret;
+}
+
+static int
+vcs_fasync(int fd, struct file *file, int on)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (!poll) {
+               /* don't allocate anything if all we want is disable fasync */
+               if (!on)
+                       return 0;
+               poll = vcs_poll_data_get(file);
+               if (!poll)
+                       return -ENOMEM;
+       }
+
+       return fasync_helper(fd, file, on, &poll->fasync);
+}
+
+static int
+vcs_open(struct inode *inode, struct file *filp)
+{
+       unsigned int currcons = iminor(inode) & 127;
+       int ret = 0;
+       
+       tty_lock();
+       if(currcons && !vc_cons_allocated(currcons-1))
+               ret = -ENXIO;
+       tty_unlock();
+       return ret;
+}
+
+static int vcs_release(struct inode *inode, struct file *file)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (poll)
+               vcs_poll_data_free(poll);
+       return 0;
+}
+
+static const struct file_operations vcs_fops = {
+       .llseek         = vcs_lseek,
+       .read           = vcs_read,
+       .write          = vcs_write,
+       .poll           = vcs_poll,
+       .fasync         = vcs_fasync,
+       .open           = vcs_open,
+       .release        = vcs_release,
+};
+
+static struct class *vc_class;
+
+void vcs_make_sysfs(int index)
+{
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
+                     "vcs%u", index + 1);
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
+                     "vcsa%u", index + 1);
+}
+
+void vcs_remove_sysfs(int index)
+{
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
+}
+
+int __init vcs_init(void)
+{
+       unsigned int i;
+
+       if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
+               panic("unable to get major %d for vcs device", VCS_MAJOR);
+       vc_class = class_create(THIS_MODULE, "vc");
+
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+       for (i = 0; i < MIN_NR_CONSOLES; i++)
+               vcs_make_sysfs(i);
+       return 0;
+}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
new file mode 100644 (file)
index 0000000..a8ec48e
--- /dev/null
@@ -0,0 +1,4209 @@
+/*
+ *  linux/drivers/char/vt.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * Hopefully this will be a rather complete VT102 implementation.
+ *
+ * Beeping thanks to John T Kohl.
+ *
+ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
+ *   Chars, and VT100 enhancements by Peter MacDonald.
+ *
+ * Copy and paste function by Andrew Haylett,
+ *   some enhancements by Alessandro Rubini.
+ *
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ *
+ * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
+ * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
+ *
+ * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
+ * Resizing of consoles, aeb, 940926
+ *
+ * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
+ * <poe@daimi.aau.dk>
+ *
+ * User-defined bell sound, new setterm control sequences and printk
+ * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
+ *
+ * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
+ *
+ * Merge with the abstract console driver by Geert Uytterhoeven
+ * <geert@linux-m68k.org>, Jan 1997.
+ *
+ *   Original m68k console driver modifications by
+ *
+ *     - Arno Griffioen <arno@usn.nl>
+ *     - David Carter <carter@cs.bris.ac.uk>
+ * 
+ *   The abstract console driver provides a generic interface for a text
+ *   console. It supports VGA text mode, frame buffer based graphical consoles
+ *   and special graphics processors that are only accessible through some
+ *   registers (e.g. a TMS340x0 GSP).
+ *
+ *   The interface to the hardware is specified using a special structure
+ *   (struct consw) which contains function pointers to console operations
+ *   (see <linux/console.h> for more information).
+ *
+ * Support for changeable cursor shape
+ * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
+ *
+ * Ported to i386 and con_scrolldelta fixed
+ * by Emmanuel Marty <core@ggi-project.org>, April 1998
+ *
+ * Resurrected character buffers in videoram plus lots of other trickery
+ * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
+ *
+ * Removed old-style timers, introduced console_timer, made timer
+ * deletion SMP-safe.  17Jun00, Andrew Morton
+ *
+ * Removed console_lock, enabled interrupts across all console operations
+ * 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/smp_lock.h>
+#include <linux/tiocl.h>
+#include <linux/kbd_kern.h>
+#include <linux/consolemap.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/font.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/kdb.h>
+#include <linux/ctype.h>
+
+#define MAX_NR_CON_DRIVER 16
+
+#define CON_DRIVER_FLAG_MODULE 1
+#define CON_DRIVER_FLAG_INIT   2
+#define CON_DRIVER_FLAG_ATTR   4
+
+struct con_driver {
+       const struct consw *con;
+       const char *desc;
+       struct device *dev;
+       int node;
+       int first;
+       int last;
+       int flag;
+};
+
+static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
+const struct consw *conswitchp;
+
+/* A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action
+ * (such as cursor movement) and should not be displayed as a
+ * glyph unless the disp_ctrl mode is explicitly enabled.
+ */
+#define CTRL_ACTION 0x0d00ff81
+#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
+
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH     750
+#define DEFAULT_BELL_DURATION  (HZ/8)
+
+struct vc vc_cons [MAX_NR_CONSOLES];
+
+#ifndef VT_SINGLE_DRIVER
+static const struct consw *con_driver_map[MAX_NR_CONSOLES];
+#endif
+
+static int con_open(struct tty_struct *, struct file *);
+static void vc_init(struct vc_data *vc, unsigned int rows,
+                   unsigned int cols, int do_clear);
+static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void save_cur(struct vc_data *vc);
+static void reset_terminal(struct vc_data *vc, int do_clear);
+static void con_flush_chars(struct tty_struct *tty);
+static int set_vesa_blanking(char __user *p);
+static void set_cursor(struct vc_data *vc);
+static void hide_cursor(struct vc_data *vc);
+static void console_callback(struct work_struct *ignored);
+static void blank_screen_t(unsigned long dummy);
+static void set_palette(struct vc_data *vc);
+
+static int printable;          /* Is console ready for printing? */
+int default_utf8 = true;
+module_param(default_utf8, int, S_IRUGO | S_IWUSR);
+int global_cursor_default = -1;
+module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
+
+static int cur_default = CUR_DEFAULT;
+module_param(cur_default, int, S_IRUGO | S_IWUSR);
+
+/*
+ * ignore_poke: don't unblank the screen when things are typed.  This is
+ * mainly for the privacy of braille terminal users.
+ */
+static int ignore_poke;
+
+int do_poke_blanked_console;
+int console_blanked;
+
+static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+static int vesa_off_interval;
+static int blankinterval = 10*60;
+core_param(consoleblank, blankinterval, int, 0444);
+
+static DECLARE_WORK(console_work, console_callback);
+
+/*
+ * fg_console is the current virtual console,
+ * last_console is the last used one,
+ * want_console is the console we want to switch to,
+ * saved_* variants are for save/restore around kernel debugger enter/leave
+ */
+int fg_console;
+int last_console;
+int want_console = -1;
+static int saved_fg_console;
+static int saved_last_console;
+static int saved_want_console;
+static int saved_vc_mode;
+static int saved_console_blanked;
+
+/*
+ * For each existing display, we have a pointer to console currently visible
+ * on that display, allowing consoles other than fg_console to be refreshed
+ * appropriately. Unless the low-level driver supplies its own display_fg
+ * variable, we use this one for the "master display".
+ */
+static struct vc_data *master_display_fg;
+
+/*
+ * Unfortunately, we need to delay tty echo when we're currently writing to the
+ * console since the code is (and always was) not re-entrant, so we schedule
+ * all flip requests to process context with schedule-task() and run it from
+ * console_callback().
+ */
+
+/*
+ * For the same reason, we defer scrollback to the console callback.
+ */
+static int scrollback_delta;
+
+/*
+ * Hook so that the power management routines can (un)blank
+ * the console on our behalf.
+ */
+int (*console_blank_hook)(int);
+
+static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
+static int blank_state;
+static int blank_timer_expired;
+enum {
+       blank_off = 0,
+       blank_normal_wait,
+       blank_vesa_wait,
+};
+
+/*
+ * Notifier list for console events.
+ */
+static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
+
+int register_vt_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_vt_notifier);
+
+int unregister_vt_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_vt_notifier);
+
+static void notify_write(struct vc_data *vc, unsigned int unicode)
+{
+       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
+       atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
+}
+
+static void notify_update(struct vc_data *vc)
+{
+       struct vt_notifier_param param = { .vc = vc };
+       atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
+}
+/*
+ *     Low-Level Functions
+ */
+
+#define IS_FG(vc)      ((vc)->vc_num == fg_console)
+
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE(vc)  0
+#else
+#define DO_UPDATE(vc)  (CON_IS_VISIBLE(vc) && !console_blanked)
+#endif
+
+static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
+{
+       unsigned short *p;
+       
+       if (!viewed)
+               p = (unsigned short *)(vc->vc_origin + offset);
+       else if (!vc->vc_sw->con_screen_pos)
+               p = (unsigned short *)(vc->vc_visible_origin + offset);
+       else
+               p = vc->vc_sw->con_screen_pos(vc, offset);
+       return p;
+}
+
+/* Called  from the keyboard irq path.. */
+static inline void scrolldelta(int lines)
+{
+       /* FIXME */
+       /* scrolldelta needs some kind of consistency lock, but the BKL was
+          and still is not protecting versus the scheduled back end */
+       scrollback_delta += lines;
+       schedule_console_callback();
+}
+
+void schedule_console_callback(void)
+{
+       schedule_work(&console_work);
+}
+
+static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
+{
+       unsigned short *d, *s;
+
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > vc->vc_rows || t >= b || nr < 1)
+               return;
+       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
+               return;
+       d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
+       scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
+       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+                   vc->vc_size_row * nr);
+}
+
+static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
+{
+       unsigned short *s;
+       unsigned int step;
+
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > vc->vc_rows || t >= b || nr < 1)
+               return;
+       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
+               return;
+       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+       step = vc->vc_cols * nr;
+       scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
+       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
+}
+
+static void do_update_region(struct vc_data *vc, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+       unsigned int xx, yy, offset;
+       u16 *p;
+
+       p = (u16 *) start;
+       if (!vc->vc_sw->con_getxy) {
+               offset = (start - vc->vc_origin) / 2;
+               xx = offset % vc->vc_cols;
+               yy = offset / vc->vc_cols;
+       } else {
+               int nxx, nyy;
+               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
+               xx = nxx; yy = nyy;
+       }
+       for(;;) {
+               u16 attrib = scr_readw(p) & 0xff00;
+               int startx = xx;
+               u16 *q = p;
+               while (xx < vc->vc_cols && count) {
+                       if (attrib != (scr_readw(p) & 0xff00)) {
+                               if (p > q)
+                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+                               startx = xx;
+                               q = p;
+                               attrib = scr_readw(p) & 0xff00;
+                       }
+                       p++;
+                       xx++;
+                       count--;
+               }
+               if (p > q)
+                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+               if (!count)
+                       break;
+               xx = 0;
+               yy++;
+               if (vc->vc_sw->con_getxy) {
+                       p = (u16 *)start;
+                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
+               }
+       }
+#endif
+}
+
+void update_region(struct vc_data *vc, unsigned long start, int count)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (DO_UPDATE(vc)) {
+               hide_cursor(vc);
+               do_update_region(vc, start, count);
+               set_cursor(vc);
+       }
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
+    u8 _underline, u8 _reverse, u8 _italic)
+{
+       if (vc->vc_sw->con_build_attr)
+               return vc->vc_sw->con_build_attr(vc, _color, _intensity,
+                      _blink, _underline, _reverse, _italic);
+
+#ifndef VT_BUF_VRAM_ONLY
+/*
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ *  Bit 0..1: intensity (0..2)
+ *  Bit 2   : underline
+ *  Bit 3   : reverse
+ *  Bit 7   : blink
+ */
+       {
+       u8 a = _color;
+       if (!vc->vc_can_do_color)
+               return _intensity |
+                      (_italic ? 2 : 0) |
+                      (_underline ? 4 : 0) |
+                      (_reverse ? 8 : 0) |
+                      (_blink ? 0x80 : 0);
+       if (_italic)
+               a = (a & 0xF0) | vc->vc_itcolor;
+       else if (_underline)
+               a = (a & 0xf0) | vc->vc_ulcolor;
+       else if (_intensity == 0)
+               a = (a & 0xf0) | vc->vc_ulcolor;
+       if (_reverse)
+               a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+       if (_blink)
+               a ^= 0x80;
+       if (_intensity == 2)
+               a ^= 0x08;
+       if (vc->vc_hi_font_mask == 0x100)
+               a <<= 1;
+       return a;
+       }
+#else
+       return 0;
+#endif
+}
+
+static void update_attr(struct vc_data *vc)
+{
+       vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
+                     vc->vc_blink, vc->vc_underline,
+                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+       vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
+}
+
+/* Note: inverting the screen twice should revert to the original state */
+void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
+{
+       unsigned short *p;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       count /= 2;
+       p = screenpos(vc, offset, viewed);
+       if (vc->vc_sw->con_invert_region)
+               vc->vc_sw->con_invert_region(vc, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+       else {
+               u16 *q = p;
+               int cnt = count;
+               u16 a;
+
+               if (!vc->vc_can_do_color) {
+                       while (cnt--) {
+                           a = scr_readw(q);
+                           a ^= 0x0800;
+                           scr_writew(a, q);
+                           q++;
+                       }
+               } else if (vc->vc_hi_font_mask == 0x100) {
+                       while (cnt--) {
+                               a = scr_readw(q);
+                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+                               scr_writew(a, q);
+                               q++;
+                       }
+               } else {
+                       while (cnt--) {
+                               a = scr_readw(q);
+                               a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+                               scr_writew(a, q);
+                               q++;
+                       }
+               }
+       }
+#endif
+       if (DO_UPDATE(vc))
+               do_update_region(vc, (unsigned long) p, count);
+}
+
+/* used by selection: complement pointer position */
+void complement_pos(struct vc_data *vc, int offset)
+{
+       static int old_offset = -1;
+       static unsigned short old;
+       static unsigned short oldx, oldy;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (old_offset != -1 && old_offset >= 0 &&
+           old_offset < vc->vc_screenbuf_size) {
+               scr_writew(old, screenpos(vc, old_offset, 1));
+               if (DO_UPDATE(vc))
+                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
+       }
+
+       old_offset = offset;
+
+       if (offset != -1 && offset >= 0 &&
+           offset < vc->vc_screenbuf_size) {
+               unsigned short new;
+               unsigned short *p;
+               p = screenpos(vc, offset, 1);
+               old = scr_readw(p);
+               new = old ^ vc->vc_complement_mask;
+               scr_writew(new, p);
+               if (DO_UPDATE(vc)) {
+                       oldx = (offset >> 1) % vc->vc_cols;
+                       oldy = (offset >> 1) / vc->vc_cols;
+                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
+               }
+       }
+
+}
+
+static void insert_char(struct vc_data *vc, unsigned int nr)
+{
+       unsigned short *p, *q = (unsigned short *)vc->vc_pos;
+
+       p = q + vc->vc_cols - nr - vc->vc_x;
+       while (--p >= q)
+               scr_writew(scr_readw(p), p + nr);
+       scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+       vc->vc_need_wrap = 0;
+       if (DO_UPDATE(vc)) {
+               unsigned short oldattr = vc->vc_attr;
+               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
+                                    vc->vc_cols - vc->vc_x - nr);
+               vc->vc_attr = vc->vc_video_erase_char >> 8;
+               while (nr--)
+                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
+               vc->vc_attr = oldattr;
+       }
+}
+
+static void delete_char(struct vc_data *vc, unsigned int nr)
+{
+       unsigned int i = vc->vc_x;
+       unsigned short *p = (unsigned short *)vc->vc_pos;
+
+       while (++i <= vc->vc_cols - nr) {
+               scr_writew(scr_readw(p+nr), p);
+               p++;
+       }
+       scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+       vc->vc_need_wrap = 0;
+       if (DO_UPDATE(vc)) {
+               unsigned short oldattr = vc->vc_attr;
+               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
+                                    vc->vc_cols - vc->vc_x - nr);
+               vc->vc_attr = vc->vc_video_erase_char >> 8;
+               while (nr--)
+                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
+                                    vc->vc_cols - 1 - nr);
+               vc->vc_attr = oldattr;
+       }
+}
+
+static int softcursor_original;
+
+static void add_softcursor(struct vc_data *vc)
+{
+       int i = scr_readw((u16 *) vc->vc_pos);
+       u32 type = vc->vc_cursor_type;
+
+       if (! (type & 0x10)) return;
+       if (softcursor_original != -1) return;
+       softcursor_original = i;
+       i |= ((type >> 8) & 0xff00 );
+       i ^= ((type) & 0xff00 );
+       if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+       if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+       scr_writew(i, (u16 *) vc->vc_pos);
+       if (DO_UPDATE(vc))
+               vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
+}
+
+static void hide_softcursor(struct vc_data *vc)
+{
+       if (softcursor_original != -1) {
+               scr_writew(softcursor_original, (u16 *)vc->vc_pos);
+               if (DO_UPDATE(vc))
+                       vc->vc_sw->con_putc(vc, softcursor_original,
+                                       vc->vc_y, vc->vc_x);
+               softcursor_original = -1;
+       }
+}
+
+static void hide_cursor(struct vc_data *vc)
+{
+       if (vc == sel_cons)
+               clear_selection();
+       vc->vc_sw->con_cursor(vc, CM_ERASE);
+       hide_softcursor(vc);
+}
+
+static void set_cursor(struct vc_data *vc)
+{
+       if (!IS_FG(vc) || console_blanked ||
+           vc->vc_mode == KD_GRAPHICS)
+               return;
+       if (vc->vc_deccm) {
+               if (vc == sel_cons)
+                       clear_selection();
+               add_softcursor(vc);
+               if ((vc->vc_cursor_type & 0x0f) != 1)
+                       vc->vc_sw->con_cursor(vc, CM_DRAW);
+       } else
+               hide_cursor(vc);
+}
+
+static void set_origin(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!CON_IS_VISIBLE(vc) ||
+           !vc->vc_sw->con_set_origin ||
+           !vc->vc_sw->con_set_origin(vc))
+               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+       vc->vc_visible_origin = vc->vc_origin;
+       vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+       vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
+}
+
+static inline void save_screen(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc->vc_sw->con_save_screen)
+               vc->vc_sw->con_save_screen(vc);
+}
+
+/*
+ *     Redrawing of screen
+ */
+
+static void clear_buffer_attributes(struct vc_data *vc)
+{
+       unsigned short *p = (unsigned short *)vc->vc_origin;
+       int count = vc->vc_screenbuf_size / 2;
+       int mask = vc->vc_hi_font_mask | 0xff;
+
+       for (; count > 0; count--, p++) {
+               scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
+       }
+}
+
+void redraw_screen(struct vc_data *vc, int is_switch)
+{
+       int redraw = 0;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!vc) {
+               /* strange ... */
+               /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
+               return;
+       }
+
+       if (is_switch) {
+               struct vc_data *old_vc = vc_cons[fg_console].d;
+               if (old_vc == vc)
+                       return;
+               if (!CON_IS_VISIBLE(vc))
+                       redraw = 1;
+               *vc->vc_display_fg = vc;
+               fg_console = vc->vc_num;
+               hide_cursor(old_vc);
+               if (!CON_IS_VISIBLE(old_vc)) {
+                       save_screen(old_vc);
+                       set_origin(old_vc);
+               }
+       } else {
+               hide_cursor(vc);
+               redraw = 1;
+       }
+
+       if (redraw) {
+               int update;
+               int old_was_color = vc->vc_can_do_color;
+
+               set_origin(vc);
+               update = vc->vc_sw->con_switch(vc);
+               set_palette(vc);
+               /*
+                * If console changed from mono<->color, the best we can do
+                * is to clear the buffer attributes. As it currently stands,
+                * rebuilding new attributes from the old buffer is not doable
+                * without overly complex code.
+                */
+               if (old_was_color != vc->vc_can_do_color) {
+                       update_attr(vc);
+                       clear_buffer_attributes(vc);
+               }
+
+               /* Forcibly update if we're panicing */
+               if ((update && vc->vc_mode != KD_GRAPHICS) ||
+                   vt_force_oops_output(vc))
+                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+       }
+       set_cursor(vc);
+       if (is_switch) {
+               set_leds();
+               compute_shiftstate();
+               notify_update(vc);
+       }
+}
+
+/*
+ *     Allocation, freeing and resizing of VTs.
+ */
+
+int vc_cons_allocated(unsigned int i)
+{
+       return (i < MAX_NR_CONSOLES && vc_cons[i].d);
+}
+
+static void visual_init(struct vc_data *vc, int num, int init)
+{
+       /* ++Geert: vc->vc_sw->con_init determines console size */
+       if (vc->vc_sw)
+               module_put(vc->vc_sw->owner);
+       vc->vc_sw = conswitchp;
+#ifndef VT_SINGLE_DRIVER
+       if (con_driver_map[num])
+               vc->vc_sw = con_driver_map[num];
+#endif
+       __module_get(vc->vc_sw->owner);
+       vc->vc_num = num;
+       vc->vc_display_fg = &master_display_fg;
+       vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
+       vc->vc_uni_pagedir = 0;
+       vc->vc_hi_font_mask = 0;
+       vc->vc_complement_mask = 0;
+       vc->vc_can_do_color = 0;
+       vc->vc_panic_force_write = false;
+       vc->vc_sw->con_init(vc, init);
+       if (!vc->vc_complement_mask)
+               vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+       vc->vc_s_complement_mask = vc->vc_complement_mask;
+       vc->vc_size_row = vc->vc_cols << 1;
+       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+}
+
+int vc_allocate(unsigned int currcons) /* return 0 on success */
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (currcons >= MAX_NR_CONSOLES)
+               return -ENXIO;
+       if (!vc_cons[currcons].d) {
+           struct vc_data *vc;
+           struct vt_notifier_param param;
+
+           /* prevent users from taking too much memory */
+           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
+             return -EPERM;
+
+           /* due to the granularity of kmalloc, we waste some memory here */
+           /* the alloc is done in two steps, to optimize the common situation
+              of a 25x80 console (structsize=216, screenbuf_size=4000) */
+           /* although the numbers above are not valid since long ago, the
+              point is still up-to-date and the comment still has its value
+              even if only as a historical artifact.  --mj, July 1998 */
+           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
+           if (!vc)
+               return -ENOMEM;
+           vc_cons[currcons].d = vc;
+           tty_port_init(&vc->port);
+           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+           visual_init(vc, currcons, 1);
+           if (!*vc->vc_uni_pagedir_loc)
+               con_set_default_unimap(vc);
+           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+           if (!vc->vc_screenbuf) {
+               kfree(vc);
+               vc_cons[currcons].d = NULL;
+               return -ENOMEM;
+           }
+
+           /* If no drivers have overridden us and the user didn't pass a
+              boot option, default to displaying the cursor */
+           if (global_cursor_default == -1)
+                   global_cursor_default = 1;
+
+           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+           vcs_make_sysfs(currcons);
+           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
+       }
+       return 0;
+}
+
+static inline int resize_screen(struct vc_data *vc, int width, int height,
+                               int user)
+{
+       /* Resizes the resolution of the display adapater */
+       int err = 0;
+
+       if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
+               err = vc->vc_sw->con_resize(vc, width, height, user);
+
+       return err;
+}
+
+/*
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
+ * [this is to be used together with some user program
+ * like resize that changes the hardware videomode]
+ */
+#define VC_RESIZE_MAXCOL (32767)
+#define VC_RESIZE_MAXROW (32767)
+
+/**
+ *     vc_do_resize    -       resizing method for the tty
+ *     @tty: tty being resized
+ *     @real_tty: real tty (different to tty if a pty/tty pair)
+ *     @vc: virtual console private data
+ *     @cols: columns
+ *     @lines: lines
+ *
+ *     Resize a virtual console, clipping according to the actual constraints.
+ *     If the caller passes a tty structure then update the termios winsize
+ *     information and perform any necessary signal handling.
+ *
+ *     Caller must hold the console semaphore. Takes the termios mutex and
+ *     ctrl_lock of the tty IFF a tty is passed.
+ */
+
+static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
+                               unsigned int cols, unsigned int lines)
+{
+       unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
+       unsigned long end;
+       unsigned int old_cols, old_rows, old_row_size, old_screen_size;
+       unsigned int new_cols, new_rows, new_row_size, new_screen_size;
+       unsigned int user;
+       unsigned short *newscreen;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!vc)
+               return -ENXIO;
+
+       user = vc->vc_resize_user;
+       vc->vc_resize_user = 0;
+
+       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+               return -EINVAL;
+
+       new_cols = (cols ? cols : vc->vc_cols);
+       new_rows = (lines ? lines : vc->vc_rows);
+       new_row_size = new_cols << 1;
+       new_screen_size = new_row_size * new_rows;
+
+       if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
+               return 0;
+
+       newscreen = kmalloc(new_screen_size, GFP_USER);
+       if (!newscreen)
+               return -ENOMEM;
+
+       old_rows = vc->vc_rows;
+       old_cols = vc->vc_cols;
+       old_row_size = vc->vc_size_row;
+       old_screen_size = vc->vc_screenbuf_size;
+
+       err = resize_screen(vc, new_cols, new_rows, user);
+       if (err) {
+               kfree(newscreen);
+               return err;
+       }
+
+       vc->vc_rows = new_rows;
+       vc->vc_cols = new_cols;
+       vc->vc_size_row = new_row_size;
+       vc->vc_screenbuf_size = new_screen_size;
+
+       rlth = min(old_row_size, new_row_size);
+       rrem = new_row_size - rlth;
+       old_origin = vc->vc_origin;
+       new_origin = (long) newscreen;
+       new_scr_end = new_origin + new_screen_size;
+
+       if (vc->vc_y > new_rows) {
+               if (old_rows - vc->vc_y < new_rows) {
+                       /*
+                        * Cursor near the bottom, copy contents from the
+                        * bottom of buffer
+                        */
+                       old_origin += (old_rows - new_rows) * old_row_size;
+               } else {
+                       /*
+                        * Cursor is in no man's land, copy 1/2 screenful
+                        * from the top and bottom of cursor position
+                        */
+                       old_origin += (vc->vc_y - new_rows/2) * old_row_size;
+               }
+       }
+
+       end = old_origin + old_row_size * min(old_rows, new_rows);
+
+       update_attr(vc);
+
+       while (old_origin < end) {
+               scr_memcpyw((unsigned short *) new_origin,
+                           (unsigned short *) old_origin, rlth);
+               if (rrem)
+                       scr_memsetw((void *)(new_origin + rlth),
+                                   vc->vc_video_erase_char, rrem);
+               old_origin += old_row_size;
+               new_origin += new_row_size;
+       }
+       if (new_scr_end > new_origin)
+               scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
+                           new_scr_end - new_origin);
+       kfree(vc->vc_screenbuf);
+       vc->vc_screenbuf = newscreen;
+       vc->vc_screenbuf_size = new_screen_size;
+       set_origin(vc);
+
+       /* do part of a reset_terminal() */
+       vc->vc_top = 0;
+       vc->vc_bottom = vc->vc_rows;
+       gotoxy(vc, vc->vc_x, vc->vc_y);
+       save_cur(vc);
+
+       if (tty) {
+               /* Rewrite the requested winsize data with the actual
+                  resulting sizes */
+               struct winsize ws;
+               memset(&ws, 0, sizeof(ws));
+               ws.ws_row = vc->vc_rows;
+               ws.ws_col = vc->vc_cols;
+               ws.ws_ypixel = vc->vc_scan_lines;
+               tty_do_resize(tty, &ws);
+       }
+
+       if (CON_IS_VISIBLE(vc))
+               update_screen(vc);
+       vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
+       return err;
+}
+
+/**
+ *     vc_resize               -       resize a VT
+ *     @vc: virtual console
+ *     @cols: columns
+ *     @rows: rows
+ *
+ *     Resize a virtual console as seen from the console end of things. We
+ *     use the common vc_do_resize methods to update the structures. The
+ *     caller must hold the console sem to protect console internals and
+ *     vc->port.tty
+ */
+
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+{
+       return vc_do_resize(vc->port.tty, vc, cols, rows);
+}
+
+/**
+ *     vt_resize               -       resize a VT
+ *     @tty: tty to resize
+ *     @ws: winsize attributes
+ *
+ *     Resize a virtual terminal. This is called by the tty layer as we
+ *     register our own handler for resizing. The mutual helper does all
+ *     the actual work.
+ *
+ *     Takes the console sem and the called methods then take the tty
+ *     termios_mutex and the tty ctrl_lock in that order.
+ */
+static int vt_resize(struct tty_struct *tty, struct winsize *ws)
+{
+       struct vc_data *vc = tty->driver_data;
+       int ret;
+
+       acquire_console_sem();
+       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
+       release_console_sem();
+       return ret;
+}
+
+void vc_deallocate(unsigned int currcons)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc_cons_allocated(currcons)) {
+               struct vc_data *vc = vc_cons[currcons].d;
+               struct vt_notifier_param param = { .vc = vc };
+
+               atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
+               vcs_remove_sysfs(currcons);
+               vc->vc_sw->con_deinit(vc);
+               put_pid(vc->vt_pid);
+               module_put(vc->vc_sw->owner);
+               kfree(vc->vc_screenbuf);
+               if (currcons >= MIN_NR_CONSOLES)
+                       kfree(vc);
+               vc_cons[currcons].d = NULL;
+       }
+}
+
+/*
+ *     VT102 emulator
+ */
+
+#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define is_kbd(vc, x)  vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+
+#define decarm         VC_REPEAT
+#define decckm         VC_CKMODE
+#define kbdapplic      VC_APPLIC
+#define lnm            VC_CRLF
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+                                      8,12,10,14, 9,13,11,15 };
+
+/* the default colour table, for VGA+ colour systems */
+int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
+    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+
+module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+
+/*
+ * gotoxy() must verify all boundaries, because the arguments
+ * might also be negative. If the given position is out of
+ * bounds, the cursor is placed at the nearest margin.
+ */
+static void gotoxy(struct vc_data *vc, int new_x, int new_y)
+{
+       int min_y, max_y;
+
+       if (new_x < 0)
+               vc->vc_x = 0;
+       else {
+               if (new_x >= vc->vc_cols)
+                       vc->vc_x = vc->vc_cols - 1;
+               else
+                       vc->vc_x = new_x;
+       }
+
+       if (vc->vc_decom) {
+               min_y = vc->vc_top;
+               max_y = vc->vc_bottom;
+       } else {
+               min_y = 0;
+               max_y = vc->vc_rows;
+       }
+       if (new_y < min_y)
+               vc->vc_y = min_y;
+       else if (new_y >= max_y)
+               vc->vc_y = max_y - 1;
+       else
+               vc->vc_y = new_y;
+       vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
+       vc->vc_need_wrap = 0;
+}
+
+/* for absolute user moves, when decom is set */
+static void gotoxay(struct vc_data *vc, int new_x, int new_y)
+{
+       gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
+}
+
+void scrollback(struct vc_data *vc, int lines)
+{
+       if (!lines)
+               lines = vc->vc_rows / 2;
+       scrolldelta(-lines);
+}
+
+void scrollfront(struct vc_data *vc, int lines)
+{
+       if (!lines)
+               lines = vc->vc_rows / 2;
+       scrolldelta(lines);
+}
+
+static void lf(struct vc_data *vc)
+{
+       /* don't scroll if above bottom of scrolling region, or
+        * if below scrolling region
+        */
+       if (vc->vc_y + 1 == vc->vc_bottom)
+               scrup(vc, vc->vc_top, vc->vc_bottom, 1);
+       else if (vc->vc_y < vc->vc_rows - 1) {
+               vc->vc_y++;
+               vc->vc_pos += vc->vc_size_row;
+       }
+       vc->vc_need_wrap = 0;
+       notify_write(vc, '\n');
+}
+
+static void ri(struct vc_data *vc)
+{
+       /* don't scroll if below top of scrolling region, or
+        * if above scrolling region
+        */
+       if (vc->vc_y == vc->vc_top)
+               scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
+       else if (vc->vc_y > 0) {
+               vc->vc_y--;
+               vc->vc_pos -= vc->vc_size_row;
+       }
+       vc->vc_need_wrap = 0;
+}
+
+static inline void cr(struct vc_data *vc)
+{
+       vc->vc_pos -= vc->vc_x << 1;
+       vc->vc_need_wrap = vc->vc_x = 0;
+       notify_write(vc, '\r');
+}
+
+static inline void bs(struct vc_data *vc)
+{
+       if (vc->vc_x) {
+               vc->vc_pos -= 2;
+               vc->vc_x--;
+               vc->vc_need_wrap = 0;
+               notify_write(vc, '\b');
+       }
+}
+
+static inline void del(struct vc_data *vc)
+{
+       /* ignored */
+}
+
+static void csi_J(struct vc_data *vc, int vpar)
+{
+       unsigned int count;
+       unsigned short * start;
+
+       switch (vpar) {
+               case 0: /* erase from cursor to end of display */
+                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+                       start = (unsigned short *)vc->vc_pos;
+                       if (DO_UPDATE(vc)) {
+                               /* do in two stages */
+                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+                                             vc->vc_cols - vc->vc_x);
+                               vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
+                                             vc->vc_rows - vc->vc_y - 1,
+                                             vc->vc_cols);
+                       }
+                       break;
+               case 1: /* erase from start to cursor */
+                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+                       start = (unsigned short *)vc->vc_origin;
+                       if (DO_UPDATE(vc)) {
+                               /* do in two stages */
+                               vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
+                                             vc->vc_cols);
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                             vc->vc_x + 1);
+                       }
+                       break;
+               case 2: /* erase whole display */
+                       count = vc->vc_cols * vc->vc_rows;
+                       start = (unsigned short *)vc->vc_origin;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, 0, 0,
+                                             vc->vc_rows,
+                                             vc->vc_cols);
+                       break;
+               default:
+                       return;
+       }
+       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+       vc->vc_need_wrap = 0;
+}
+
+static void csi_K(struct vc_data *vc, int vpar)
+{
+       unsigned int count;
+       unsigned short * start;
+
+       switch (vpar) {
+               case 0: /* erase from cursor to end of line */
+                       count = vc->vc_cols - vc->vc_x;
+                       start = (unsigned short *)vc->vc_pos;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+                                                    vc->vc_cols - vc->vc_x);
+                       break;
+               case 1: /* erase from start of line to cursor */
+                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+                       count = vc->vc_x + 1;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                                    vc->vc_x + 1);
+                       break;
+               case 2: /* erase whole line */
+                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+                       count = vc->vc_cols;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                             vc->vc_cols);
+                       break;
+               default:
+                       return;
+       }
+       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+       vc->vc_need_wrap = 0;
+}
+
+static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
+{                                        /* not vt100? */
+       int count;
+
+       if (!vpar)
+               vpar++;
+       count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
+
+       scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
+       if (DO_UPDATE(vc))
+               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
+       vc->vc_need_wrap = 0;
+}
+
+static void default_attr(struct vc_data *vc)
+{
+       vc->vc_intensity = 1;
+       vc->vc_italic = 0;
+       vc->vc_underline = 0;
+       vc->vc_reverse = 0;
+       vc->vc_blink = 0;
+       vc->vc_color = vc->vc_def_color;
+}
+
+/* console_sem is held */
+static void csi_m(struct vc_data *vc)
+{
+       int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               switch (vc->vc_par[i]) {
+                       case 0: /* all attributes off */
+                               default_attr(vc);
+                               break;
+                       case 1:
+                               vc->vc_intensity = 2;
+                               break;
+                       case 2:
+                               vc->vc_intensity = 0;
+                               break;
+                       case 3:
+                               vc->vc_italic = 1;
+                               break;
+                       case 4:
+                               vc->vc_underline = 1;
+                               break;
+                       case 5:
+                               vc->vc_blink = 1;
+                               break;
+                       case 7:
+                               vc->vc_reverse = 1;
+                               break;
+                       case 10: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select primary font, don't display
+                                 * control chars if defined, don't set
+                                 * bit 8 on output.
+                                 */
+                               vc->vc_translate = set_translate(vc->vc_charset == 0
+                                               ? vc->vc_G0_charset
+                                               : vc->vc_G1_charset, vc);
+                               vc->vc_disp_ctrl = 0;
+                               vc->vc_toggle_meta = 0;
+                               break;
+                       case 11: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select first alternate font, lets
+                                 * chars < 32 be displayed as ROM chars.
+                                 */
+                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
+                               vc->vc_disp_ctrl = 1;
+                               vc->vc_toggle_meta = 0;
+                               break;
+                       case 12: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select second alternate font, toggle
+                                 * high bit before displaying as ROM char.
+                                 */
+                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
+                               vc->vc_disp_ctrl = 1;
+                               vc->vc_toggle_meta = 1;
+                               break;
+                       case 21:
+                       case 22:
+                               vc->vc_intensity = 1;
+                               break;
+                       case 23:
+                               vc->vc_italic = 0;
+                               break;
+                       case 24:
+                               vc->vc_underline = 0;
+                               break;
+                       case 25:
+                               vc->vc_blink = 0;
+                               break;
+                       case 27:
+                               vc->vc_reverse = 0;
+                               break;
+                       case 38: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Enables underscore, white foreground
+                                 * with white underscore (Linux - use
+                                 * default foreground).
+                                 */
+                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+                               vc->vc_underline = 1;
+                               break;
+                       case 39: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Disable underline option.
+                                 * Reset colour to default? It did this
+                                 * before...
+                                 */
+                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+                               vc->vc_underline = 0;
+                               break;
+                       case 49:
+                               vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
+                               break;
+                       default:
+                               if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
+                                       vc->vc_color = color_table[vc->vc_par[i] - 30]
+                                               | (vc->vc_color & 0xf0);
+                               else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
+                                       vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
+                                               | (vc->vc_color & 0x0f);
+                               break;
+               }
+       update_attr(vc);
+}
+
+static void respond_string(const char *p, struct tty_struct *tty)
+{
+       while (*p) {
+               tty_insert_flip_char(tty, *p, 0);
+               p++;
+       }
+       con_schedule_flip(tty);
+}
+
+static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
+{
+       char buf[40];
+
+       sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
+       respond_string(buf, tty);
+}
+
+static inline void status_report(struct tty_struct *tty)
+{
+       respond_string("\033[0n", tty); /* Terminal ok */
+}
+
+static inline void respond_ID(struct tty_struct * tty)
+{
+       respond_string(VT102ID, tty);
+}
+
+void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
+{
+       char buf[8];
+
+       sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+               (char)('!' + mry));
+       respond_string(buf, tty);
+}
+
+/* invoked via ioctl(TIOCLINUX) and through set_selection */
+int mouse_reporting(void)
+{
+       return vc_cons[fg_console].d->vc_report_mouse;
+}
+
+/* console_sem is held */
+static void set_mode(struct vc_data *vc, int on_off)
+{
+       int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               if (vc->vc_ques) {
+                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
+                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
+                               if (on_off)
+                                       set_kbd(vc, decckm);
+                               else
+                                       clr_kbd(vc, decckm);
+                               break;
+                       case 3: /* 80/132 mode switch unimplemented */
+                               vc->vc_deccolm = on_off;
+#if 0
+                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
+                               /* this alone does not suffice; some user mode
+                                  utility has to change the hardware regs */
+#endif
+                               break;
+                       case 5:                 /* Inverted screen on/off */
+                               if (vc->vc_decscnm != on_off) {
+                                       vc->vc_decscnm = on_off;
+                                       invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
+                                       update_attr(vc);
+                               }
+                               break;
+                       case 6:                 /* Origin relative/absolute */
+                               vc->vc_decom = on_off;
+                               gotoxay(vc, 0, 0);
+                               break;
+                       case 7:                 /* Autowrap on/off */
+                               vc->vc_decawm = on_off;
+                               break;
+                       case 8:                 /* Autorepeat on/off */
+                               if (on_off)
+                                       set_kbd(vc, decarm);
+                               else
+                                       clr_kbd(vc, decarm);
+                               break;
+                       case 9:
+                               vc->vc_report_mouse = on_off ? 1 : 0;
+                               break;
+                       case 25:                /* Cursor on/off */
+                               vc->vc_deccm = on_off;
+                               break;
+                       case 1000:
+                               vc->vc_report_mouse = on_off ? 2 : 0;
+                               break;
+                       }
+               } else {
+                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
+                       case 3:                 /* Monitor (display ctrls) */
+                               vc->vc_disp_ctrl = on_off;
+                               break;
+                       case 4:                 /* Insert Mode on/off */
+                               vc->vc_decim = on_off;
+                               break;
+                       case 20:                /* Lf, Enter == CrLf/Lf */
+                               if (on_off)
+                                       set_kbd(vc, lnm);
+                               else
+                                       clr_kbd(vc, lnm);
+                               break;
+                       }
+               }
+}
+
+/* console_sem is held */
+static void setterm_command(struct vc_data *vc)
+{
+       switch(vc->vc_par[0]) {
+               case 1: /* set color for underline mode */
+                       if (vc->vc_can_do_color &&
+                                       vc->vc_par[1] < 16) {
+                               vc->vc_ulcolor = color_table[vc->vc_par[1]];
+                               if (vc->vc_underline)
+                                       update_attr(vc);
+                       }
+                       break;
+               case 2: /* set color for half intensity mode */
+                       if (vc->vc_can_do_color &&
+                                       vc->vc_par[1] < 16) {
+                               vc->vc_halfcolor = color_table[vc->vc_par[1]];
+                               if (vc->vc_intensity == 0)
+                                       update_attr(vc);
+                       }
+                       break;
+               case 8: /* store colors as defaults */
+                       vc->vc_def_color = vc->vc_attr;
+                       if (vc->vc_hi_font_mask == 0x100)
+                               vc->vc_def_color >>= 1;
+                       default_attr(vc);
+                       update_attr(vc);
+                       break;
+               case 9: /* set blanking interval */
+                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
+                       poke_blanked_console();
+                       break;
+               case 10: /* set bell frequency in Hz */
+                       if (vc->vc_npar >= 1)
+                               vc->vc_bell_pitch = vc->vc_par[1];
+                       else
+                               vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+                       break;
+               case 11: /* set bell duration in msec */
+                       if (vc->vc_npar >= 1)
+                               vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
+                                       vc->vc_par[1] * HZ / 1000 : 0;
+                       else
+                               vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+                       break;
+               case 12: /* bring specified console to the front */
+                       if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
+                               set_console(vc->vc_par[1] - 1);
+                       break;
+               case 13: /* unblank the screen */
+                       poke_blanked_console();
+                       break;
+               case 14: /* set vesa powerdown interval */
+                       vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
+                       break;
+               case 15: /* activate the previous console */
+                       set_console(last_console);
+                       break;
+       }
+}
+
+/* console_sem is held */
+static void csi_at(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_cols - vc->vc_x)
+               nr = vc->vc_cols - vc->vc_x;
+       else if (!nr)
+               nr = 1;
+       insert_char(vc, nr);
+}
+
+/* console_sem is held */
+static void csi_L(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_rows - vc->vc_y)
+               nr = vc->vc_rows - vc->vc_y;
+       else if (!nr)
+               nr = 1;
+       scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
+       vc->vc_need_wrap = 0;
+}
+
+/* console_sem is held */
+static void csi_P(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_cols - vc->vc_x)
+               nr = vc->vc_cols - vc->vc_x;
+       else if (!nr)
+               nr = 1;
+       delete_char(vc, nr);
+}
+
+/* console_sem is held */
+static void csi_M(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_rows - vc->vc_y)
+               nr = vc->vc_rows - vc->vc_y;
+       else if (!nr)
+               nr=1;
+       scrup(vc, vc->vc_y, vc->vc_bottom, nr);
+       vc->vc_need_wrap = 0;
+}
+
+/* console_sem is held (except via vc_init->reset_terminal */
+static void save_cur(struct vc_data *vc)
+{
+       vc->vc_saved_x          = vc->vc_x;
+       vc->vc_saved_y          = vc->vc_y;
+       vc->vc_s_intensity      = vc->vc_intensity;
+       vc->vc_s_italic         = vc->vc_italic;
+       vc->vc_s_underline      = vc->vc_underline;
+       vc->vc_s_blink          = vc->vc_blink;
+       vc->vc_s_reverse        = vc->vc_reverse;
+       vc->vc_s_charset        = vc->vc_charset;
+       vc->vc_s_color          = vc->vc_color;
+       vc->vc_saved_G0         = vc->vc_G0_charset;
+       vc->vc_saved_G1         = vc->vc_G1_charset;
+}
+
+/* console_sem is held */
+static void restore_cur(struct vc_data *vc)
+{
+       gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
+       vc->vc_intensity        = vc->vc_s_intensity;
+       vc->vc_italic           = vc->vc_s_italic;
+       vc->vc_underline        = vc->vc_s_underline;
+       vc->vc_blink            = vc->vc_s_blink;
+       vc->vc_reverse          = vc->vc_s_reverse;
+       vc->vc_charset          = vc->vc_s_charset;
+       vc->vc_color            = vc->vc_s_color;
+       vc->vc_G0_charset       = vc->vc_saved_G0;
+       vc->vc_G1_charset       = vc->vc_saved_G1;
+       vc->vc_translate        = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
+       update_attr(vc);
+       vc->vc_need_wrap = 0;
+}
+
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+       EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+       ESpalette };
+
+/* console_sem is held (except via vc_init()) */
+static void reset_terminal(struct vc_data *vc, int do_clear)
+{
+       vc->vc_top              = 0;
+       vc->vc_bottom           = vc->vc_rows;
+       vc->vc_state            = ESnormal;
+       vc->vc_ques             = 0;
+       vc->vc_translate        = set_translate(LAT1_MAP, vc);
+       vc->vc_G0_charset       = LAT1_MAP;
+       vc->vc_G1_charset       = GRAF_MAP;
+       vc->vc_charset          = 0;
+       vc->vc_need_wrap        = 0;
+       vc->vc_report_mouse     = 0;
+       vc->vc_utf              = default_utf8;
+       vc->vc_utf_count        = 0;
+
+       vc->vc_disp_ctrl        = 0;
+       vc->vc_toggle_meta      = 0;
+
+       vc->vc_decscnm          = 0;
+       vc->vc_decom            = 0;
+       vc->vc_decawm           = 1;
+       vc->vc_deccm            = global_cursor_default;
+       vc->vc_decim            = 0;
+
+       set_kbd(vc, decarm);
+       clr_kbd(vc, decckm);
+       clr_kbd(vc, kbdapplic);
+       clr_kbd(vc, lnm);
+       kbd_table[vc->vc_num].lockstate = 0;
+       kbd_table[vc->vc_num].slockstate = 0;
+       kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
+       kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
+       /* do not do set_leds here because this causes an endless tasklet loop
+          when the keyboard hasn't been initialized yet */
+
+       vc->vc_cursor_type = cur_default;
+       vc->vc_complement_mask = vc->vc_s_complement_mask;
+
+       default_attr(vc);
+       update_attr(vc);
+
+       vc->vc_tab_stop[0]      = 0x01010100;
+       vc->vc_tab_stop[1]      =
+       vc->vc_tab_stop[2]      =
+       vc->vc_tab_stop[3]      =
+       vc->vc_tab_stop[4]      =
+       vc->vc_tab_stop[5]      =
+       vc->vc_tab_stop[6]      =
+       vc->vc_tab_stop[7]      = 0x01010101;
+
+       vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+       vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+
+       gotoxy(vc, 0, 0);
+       save_cur(vc);
+       if (do_clear)
+           csi_J(vc, 2);
+}
+
+/* console_sem is held */
+static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
+{
+       /*
+        *  Control characters can be used in the _middle_
+        *  of an escape sequence.
+        */
+       switch (c) {
+       case 0:
+               return;
+       case 7:
+               if (vc->vc_bell_duration)
+                       kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
+               return;
+       case 8:
+               bs(vc);
+               return;
+       case 9:
+               vc->vc_pos -= (vc->vc_x << 1);
+               while (vc->vc_x < vc->vc_cols - 1) {
+                       vc->vc_x++;
+                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
+                               break;
+               }
+               vc->vc_pos += (vc->vc_x << 1);
+               notify_write(vc, '\t');
+               return;
+       case 10: case 11: case 12:
+               lf(vc);
+               if (!is_kbd(vc, lnm))
+                       return;
+       case 13:
+               cr(vc);
+               return;
+       case 14:
+               vc->vc_charset = 1;
+               vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+               vc->vc_disp_ctrl = 1;
+               return;
+       case 15:
+               vc->vc_charset = 0;
+               vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+               vc->vc_disp_ctrl = 0;
+               return;
+       case 24: case 26:
+               vc->vc_state = ESnormal;
+               return;
+       case 27:
+               vc->vc_state = ESesc;
+               return;
+       case 127:
+               del(vc);
+               return;
+       case 128+27:
+               vc->vc_state = ESsquare;
+               return;
+       }
+       switch(vc->vc_state) {
+       case ESesc:
+               vc->vc_state = ESnormal;
+               switch (c) {
+               case '[':
+                       vc->vc_state = ESsquare;
+                       return;
+               case ']':
+                       vc->vc_state = ESnonstd;
+                       return;
+               case '%':
+                       vc->vc_state = ESpercent;
+                       return;
+               case 'E':
+                       cr(vc);
+                       lf(vc);
+                       return;
+               case 'M':
+                       ri(vc);
+                       return;
+               case 'D':
+                       lf(vc);
+                       return;
+               case 'H':
+                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
+                       return;
+               case 'Z':
+                       respond_ID(tty);
+                       return;
+               case '7':
+                       save_cur(vc);
+                       return;
+               case '8':
+                       restore_cur(vc);
+                       return;
+               case '(':
+                       vc->vc_state = ESsetG0;
+                       return;
+               case ')':
+                       vc->vc_state = ESsetG1;
+                       return;
+               case '#':
+                       vc->vc_state = EShash;
+                       return;
+               case 'c':
+                       reset_terminal(vc, 1);
+                       return;
+               case '>':  /* Numeric keypad */
+                       clr_kbd(vc, kbdapplic);
+                       return;
+               case '=':  /* Appl. keypad */
+                       set_kbd(vc, kbdapplic);
+                       return;
+               }
+               return;
+       case ESnonstd:
+               if (c=='P') {   /* palette escape sequence */
+                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+                               vc->vc_par[vc->vc_npar] = 0;
+                       vc->vc_npar = 0;
+                       vc->vc_state = ESpalette;
+                       return;
+               } else if (c=='R') {   /* reset palette */
+                       reset_palette(vc);
+                       vc->vc_state = ESnormal;
+               } else
+                       vc->vc_state = ESnormal;
+               return;
+       case ESpalette:
+               if (isxdigit(c)) {
+                       vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
+                       if (vc->vc_npar == 7) {
+                               int i = vc->vc_par[0] * 3, j = 1;
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i++] += vc->vc_par[j++];
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i++] += vc->vc_par[j++];
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i] += vc->vc_par[j];
+                               set_palette(vc);
+                               vc->vc_state = ESnormal;
+                       }
+               } else
+                       vc->vc_state = ESnormal;
+               return;
+       case ESsquare:
+               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+                       vc->vc_par[vc->vc_npar] = 0;
+               vc->vc_npar = 0;
+               vc->vc_state = ESgetpars;
+               if (c == '[') { /* Function key */
+                       vc->vc_state=ESfunckey;
+                       return;
+               }
+               vc->vc_ques = (c == '?');
+               if (vc->vc_ques)
+                       return;
+       case ESgetpars:
+               if (c == ';' && vc->vc_npar < NPAR - 1) {
+                       vc->vc_npar++;
+                       return;
+               } else if (c>='0' && c<='9') {
+                       vc->vc_par[vc->vc_npar] *= 10;
+                       vc->vc_par[vc->vc_npar] += c - '0';
+                       return;
+               } else
+                       vc->vc_state = ESgotpars;
+       case ESgotpars:
+               vc->vc_state = ESnormal;
+               switch(c) {
+               case 'h':
+                       set_mode(vc, 1);
+                       return;
+               case 'l':
+                       set_mode(vc, 0);
+                       return;
+               case 'c':
+                       if (vc->vc_ques) {
+                               if (vc->vc_par[0])
+                                       vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
+                               else
+                                       vc->vc_cursor_type = cur_default;
+                               return;
+                       }
+                       break;
+               case 'm':
+                       if (vc->vc_ques) {
+                               clear_selection();
+                               if (vc->vc_par[0])
+                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
+                               else
+                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
+                               return;
+                       }
+                       break;
+               case 'n':
+                       if (!vc->vc_ques) {
+                               if (vc->vc_par[0] == 5)
+                                       status_report(tty);
+                               else if (vc->vc_par[0] == 6)
+                                       cursor_report(vc, tty);
+                       }
+                       return;
+               }
+               if (vc->vc_ques) {
+                       vc->vc_ques = 0;
+                       return;
+               }
+               switch(c) {
+               case 'G': case '`':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       gotoxy(vc, vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'A':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
+                       return;
+               case 'B': case 'e':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
+                       return;
+               case 'C': case 'a':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'D':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'E':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
+                       return;
+               case 'F':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
+                       return;
+               case 'd':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
+                       return;
+               case 'H': case 'f':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       if (vc->vc_par[1])
+                               vc->vc_par[1]--;
+                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
+                       return;
+               case 'J':
+                       csi_J(vc, vc->vc_par[0]);
+                       return;
+               case 'K':
+                       csi_K(vc, vc->vc_par[0]);
+                       return;
+               case 'L':
+                       csi_L(vc, vc->vc_par[0]);
+                       return;
+               case 'M':
+                       csi_M(vc, vc->vc_par[0]);
+                       return;
+               case 'P':
+                       csi_P(vc, vc->vc_par[0]);
+                       return;
+               case 'c':
+                       if (!vc->vc_par[0])
+                               respond_ID(tty);
+                       return;
+               case 'g':
+                       if (!vc->vc_par[0])
+                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+                       else if (vc->vc_par[0] == 3) {
+                               vc->vc_tab_stop[0] =
+                                       vc->vc_tab_stop[1] =
+                                       vc->vc_tab_stop[2] =
+                                       vc->vc_tab_stop[3] =
+                                       vc->vc_tab_stop[4] =
+                                       vc->vc_tab_stop[5] =
+                                       vc->vc_tab_stop[6] =
+                                       vc->vc_tab_stop[7] = 0;
+                       }
+                       return;
+               case 'm':
+                       csi_m(vc);
+                       return;
+               case 'q': /* DECLL - but only 3 leds */
+                       /* map 0,1,2,3 to 0,1,2,4 */
+                       if (vc->vc_par[0] < 4)
+                               setledstate(kbd_table + vc->vc_num,
+                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
+                       return;
+               case 'r':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       if (!vc->vc_par[1])
+                               vc->vc_par[1] = vc->vc_rows;
+                       /* Minimum allowed region is 2 lines */
+                       if (vc->vc_par[0] < vc->vc_par[1] &&
+                           vc->vc_par[1] <= vc->vc_rows) {
+                               vc->vc_top = vc->vc_par[0] - 1;
+                               vc->vc_bottom = vc->vc_par[1];
+                               gotoxay(vc, 0, 0);
+                       }
+                       return;
+               case 's':
+                       save_cur(vc);
+                       return;
+               case 'u':
+                       restore_cur(vc);
+                       return;
+               case 'X':
+                       csi_X(vc, vc->vc_par[0]);
+                       return;
+               case '@':
+                       csi_at(vc, vc->vc_par[0]);
+                       return;
+               case ']': /* setterm functions */
+                       setterm_command(vc);
+                       return;
+               }
+               return;
+       case ESpercent:
+               vc->vc_state = ESnormal;
+               switch (c) {
+               case '@':  /* defined in ISO 2022 */
+                       vc->vc_utf = 0;
+                       return;
+               case 'G':  /* prelim official escape code */
+               case '8':  /* retained for compatibility */
+                       vc->vc_utf = 1;
+                       return;
+               }
+               return;
+       case ESfunckey:
+               vc->vc_state = ESnormal;
+               return;
+       case EShash:
+               vc->vc_state = ESnormal;
+               if (c == '8') {
+                       /* DEC screen alignment test. kludge :-) */
+                       vc->vc_video_erase_char =
+                               (vc->vc_video_erase_char & 0xff00) | 'E';
+                       csi_J(vc, 2);
+                       vc->vc_video_erase_char =
+                               (vc->vc_video_erase_char & 0xff00) | ' ';
+                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+               }
+               return;
+       case ESsetG0:
+               if (c == '0')
+                       vc->vc_G0_charset = GRAF_MAP;
+               else if (c == 'B')
+                       vc->vc_G0_charset = LAT1_MAP;
+               else if (c == 'U')
+                       vc->vc_G0_charset = IBMPC_MAP;
+               else if (c == 'K')
+                       vc->vc_G0_charset = USER_MAP;
+               if (vc->vc_charset == 0)
+                       vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+               vc->vc_state = ESnormal;
+               return;
+       case ESsetG1:
+               if (c == '0')
+                       vc->vc_G1_charset = GRAF_MAP;
+               else if (c == 'B')
+                       vc->vc_G1_charset = LAT1_MAP;
+               else if (c == 'U')
+                       vc->vc_G1_charset = IBMPC_MAP;
+               else if (c == 'K')
+                       vc->vc_G1_charset = USER_MAP;
+               if (vc->vc_charset == 1)
+                       vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+               vc->vc_state = ESnormal;
+               return;
+       default:
+               vc->vc_state = ESnormal;
+       }
+}
+
+/* This is a temporary buffer used to prepare a tty console write
+ * so that we can easily avoid touching user space while holding the
+ * console spinlock.  It is allocated in con_init and is shared by
+ * this code and the vc_screen read/write tty calls.
+ *
+ * We have to allocate this statically in the kernel data section
+ * since console_init (and thus con_init) are called before any
+ * kernel memory allocation is available.
+ */
+char con_buf[CON_BUF_SIZE];
+DEFINE_MUTEX(con_buf_mtx);
+
+/* is_double_width() is based on the wcwidth() implementation by
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+struct interval {
+       uint32_t first;
+       uint32_t last;
+};
+
+static int bisearch(uint32_t ucs, const struct interval *table, int max)
+{
+       int min = 0;
+       int mid;
+
+       if (ucs < table[0].first || ucs > table[max].last)
+               return 0;
+       while (max >= min) {
+               mid = (min + max) / 2;
+               if (ucs > table[mid].last)
+                       min = mid + 1;
+               else if (ucs < table[mid].first)
+                       max = mid - 1;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+static int is_double_width(uint32_t ucs)
+{
+       static const struct interval double_width[] = {
+               { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
+               { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
+               { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
+               { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
+       };
+       return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
+}
+
+/* acquires console_sem */
+static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
+#define FLUSH if (draw_x >= 0) { \
+       vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
+       draw_x = -1; \
+       }
+#endif
+
+       int c, tc, ok, n = 0, draw_x = -1;
+       unsigned int currcons;
+       unsigned long draw_from = 0, draw_to = 0;
+       struct vc_data *vc;
+       unsigned char vc_attr;
+       struct vt_notifier_param param;
+       uint8_t rescan;
+       uint8_t inverse;
+       uint8_t width;
+       u16 himask, charmask;
+
+       if (in_interrupt())
+               return count;
+
+       might_sleep();
+
+       acquire_console_sem();
+       vc = tty->driver_data;
+       if (vc == NULL) {
+               printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
+               release_console_sem();
+               return 0;
+       }
+
+       currcons = vc->vc_num;
+       if (!vc_cons_allocated(currcons)) {
+           /* could this happen? */
+               printk_once("con_write: tty %d not allocated\n", currcons+1);
+           release_console_sem();
+           return 0;
+       }
+
+       himask = vc->vc_hi_font_mask;
+       charmask = himask ? 0x1ff : 0xff;
+
+       /* undraw cursor first */
+       if (IS_FG(vc))
+               hide_cursor(vc);
+
+       param.vc = vc;
+
+       while (!tty->stopped && count) {
+               int orig = *buf;
+               c = orig;
+               buf++;
+               n++;
+               count--;
+               rescan = 0;
+               inverse = 0;
+               width = 1;
+
+               /* Do no translation at all in control states */
+               if (vc->vc_state != ESnormal) {
+                       tc = c;
+               } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
+                   /* Combine UTF-8 into Unicode in vc_utf_char.
+                    * vc_utf_count is the number of continuation bytes still
+                    * expected to arrive.
+                    * vc_npar is the number of continuation bytes arrived so
+                    * far
+                    */
+rescan_last_byte:
+                   if ((c & 0xc0) == 0x80) {
+                       /* Continuation byte received */
+                       static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
+                       if (vc->vc_utf_count) {
+                           vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+                           vc->vc_npar++;
+                           if (--vc->vc_utf_count) {
+                               /* Still need some bytes */
+                               continue;
+                           }
+                           /* Got a whole character */
+                           c = vc->vc_utf_char;
+                           /* Reject overlong sequences */
+                           if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+                                       c > utf8_length_changes[vc->vc_npar])
+                               c = 0xfffd;
+                       } else {
+                           /* Unexpected continuation byte */
+                           vc->vc_utf_count = 0;
+                           c = 0xfffd;
+                       }
+                   } else {
+                       /* Single ASCII byte or first byte of a sequence received */
+                       if (vc->vc_utf_count) {
+                           /* Continuation byte expected */
+                           rescan = 1;
+                           vc->vc_utf_count = 0;
+                           c = 0xfffd;
+                       } else if (c > 0x7f) {
+                           /* First byte of a multibyte sequence received */
+                           vc->vc_npar = 0;
+                           if ((c & 0xe0) == 0xc0) {
+                               vc->vc_utf_count = 1;
+                               vc->vc_utf_char = (c & 0x1f);
+                           } else if ((c & 0xf0) == 0xe0) {
+                               vc->vc_utf_count = 2;
+                               vc->vc_utf_char = (c & 0x0f);
+                           } else if ((c & 0xf8) == 0xf0) {
+                               vc->vc_utf_count = 3;
+                               vc->vc_utf_char = (c & 0x07);
+                           } else if ((c & 0xfc) == 0xf8) {
+                               vc->vc_utf_count = 4;
+                               vc->vc_utf_char = (c & 0x03);
+                           } else if ((c & 0xfe) == 0xfc) {
+                               vc->vc_utf_count = 5;
+                               vc->vc_utf_char = (c & 0x01);
+                           } else {
+                               /* 254 and 255 are invalid */
+                               c = 0xfffd;
+                           }
+                           if (vc->vc_utf_count) {
+                               /* Still need some bytes */
+                               continue;
+                           }
+                       }
+                       /* Nothing to do if an ASCII byte was received */
+                   }
+                   /* End of UTF-8 decoding. */
+                   /* c is the received character, or U+FFFD for invalid sequences. */
+                   /* Replace invalid Unicode code points with U+FFFD too */
+                   if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+                       c = 0xfffd;
+                   tc = c;
+               } else {        /* no utf or alternate charset mode */
+                   tc = vc_translate(vc, c);
+               }
+
+               param.c = tc;
+               if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
+                                       &param) == NOTIFY_STOP)
+                       continue;
+
+                /* If the original code was a control character we
+                 * only allow a glyph to be displayed if the code is
+                 * not normally used (such as for cursor movement) or
+                 * if the disp_ctrl mode has been explicitly enabled.
+                 * Certain characters (as given by the CTRL_ALWAYS
+                 * bitmap) are always displayed as control characters,
+                 * as the console would be pretty useless without
+                 * them; to display an arbitrary font position use the
+                 * direct-to-font zone in UTF-8 mode.
+                 */
+                ok = tc && (c >= 32 ||
+                           !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+                                 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
+                       && (c != 127 || vc->vc_disp_ctrl)
+                       && (c != 128+27);
+
+               if (vc->vc_state == ESnormal && ok) {
+                       if (vc->vc_utf && !vc->vc_disp_ctrl) {
+                               if (is_double_width(c))
+                                       width = 2;
+                       }
+                       /* Now try to find out how to display it */
+                       tc = conv_uni_to_pc(vc, tc);
+                       if (tc & ~charmask) {
+                               if (tc == -1 || tc == -2) {
+                                   continue; /* nothing to display */
+                               }
+                               /* Glyph not found */
+                               if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
+                                   /* In legacy mode use the glyph we get by a 1:1 mapping.
+                                      This would make absolutely no sense with Unicode in mind,
+                                      but do this for ASCII characters since a font may lack
+                                      Unicode mapping info and we don't want to end up with
+                                      having question marks only. */
+                                   tc = c;
+                               } else {
+                                   /* Display U+FFFD. If it's not found, display an inverse question mark. */
+                                   tc = conv_uni_to_pc(vc, 0xfffd);
+                                   if (tc < 0) {
+                                       inverse = 1;
+                                       tc = conv_uni_to_pc(vc, '?');
+                                       if (tc < 0) tc = '?';
+                                   }
+                               }
+                       }
+
+                       if (!inverse) {
+                               vc_attr = vc->vc_attr;
+                       } else {
+                               /* invert vc_attr */
+                               if (!vc->vc_can_do_color) {
+                                       vc_attr = (vc->vc_attr) ^ 0x08;
+                               } else if (vc->vc_hi_font_mask == 0x100) {
+                                       vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
+                               } else {
+                                       vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
+                               }
+                               FLUSH
+                       }
+
+                       while (1) {
+                               if (vc->vc_need_wrap || vc->vc_decim)
+                                       FLUSH
+                               if (vc->vc_need_wrap) {
+                                       cr(vc);
+                                       lf(vc);
+                               }
+                               if (vc->vc_decim)
+                                       insert_char(vc, 1);
+                               scr_writew(himask ?
+                                            ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+                                            (vc_attr << 8) + tc,
+                                          (u16 *) vc->vc_pos);
+                               if (DO_UPDATE(vc) && draw_x < 0) {
+                                       draw_x = vc->vc_x;
+                                       draw_from = vc->vc_pos;
+                               }
+                               if (vc->vc_x == vc->vc_cols - 1) {
+                                       vc->vc_need_wrap = vc->vc_decawm;
+                                       draw_to = vc->vc_pos + 2;
+                               } else {
+                                       vc->vc_x++;
+                                       draw_to = (vc->vc_pos += 2);
+                               }
+
+                               if (!--width) break;
+
+                               tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
+                               if (tc < 0) tc = ' ';
+                       }
+                       notify_write(vc, c);
+
+                       if (inverse) {
+                               FLUSH
+                       }
+
+                       if (rescan) {
+                               rescan = 0;
+                               inverse = 0;
+                               width = 1;
+                               c = orig;
+                               goto rescan_last_byte;
+                       }
+                       continue;
+               }
+               FLUSH
+               do_con_trol(tty, vc, orig);
+       }
+       FLUSH
+       console_conditional_schedule();
+       release_console_sem();
+       notify_update(vc);
+       return n;
+#undef FLUSH
+}
+
+/*
+ * This is the console switching callback.
+ *
+ * Doing console switching in a process context allows
+ * us to do the switches asynchronously (needed when we want
+ * to switch due to a keyboard interrupt).  Synchronization
+ * with other console code and prevention of re-entrancy is
+ * ensured with console_sem.
+ */
+static void console_callback(struct work_struct *ignored)
+{
+       acquire_console_sem();
+
+       if (want_console >= 0) {
+               if (want_console != fg_console &&
+                   vc_cons_allocated(want_console)) {
+                       hide_cursor(vc_cons[fg_console].d);
+                       change_console(vc_cons[want_console].d);
+                       /* we only changed when the console had already
+                          been allocated - a new console is not created
+                          in an interrupt routine */
+               }
+               want_console = -1;
+       }
+       if (do_poke_blanked_console) { /* do not unblank for a LED change */
+               do_poke_blanked_console = 0;
+               poke_blanked_console();
+       }
+       if (scrollback_delta) {
+               struct vc_data *vc = vc_cons[fg_console].d;
+               clear_selection();
+               if (vc->vc_mode == KD_TEXT)
+                       vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
+               scrollback_delta = 0;
+       }
+       if (blank_timer_expired) {
+               do_blank_screen(0);
+               blank_timer_expired = 0;
+       }
+       notify_update(vc_cons[fg_console].d);
+
+       release_console_sem();
+}
+
+int set_console(int nr)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+
+       if (!vc_cons_allocated(nr) || vt_dont_switch ||
+               (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
+
+               /*
+                * Console switch will fail in console_callback() or
+                * change_console() so there is no point scheduling
+                * the callback
+                *
+                * Existing set_console() users don't check the return
+                * value so this shouldn't break anything
+                */
+               return -EINVAL;
+       }
+
+       want_console = nr;
+       schedule_console_callback();
+
+       return 0;
+}
+
+struct tty_driver *console_driver;
+
+#ifdef CONFIG_VT_CONSOLE
+
+/**
+ * vt_kmsg_redirect() - Sets/gets the kernel message console
+ * @new:       The new virtual terminal number or -1 if the console should stay
+ *             unchanged
+ *
+ * By default, the kernel messages are always printed on the current virtual
+ * console. However, the user may modify that default with the
+ * TIOCL_SETKMSGREDIRECT ioctl call.
+ *
+ * This function sets the kernel message console to be @new. It returns the old
+ * virtual console number. The virtual terminal number 0 (both as parameter and
+ * return value) means no redirection (i.e. always printed on the currently
+ * active console).
+ *
+ * The parameter -1 means that only the current console is returned, but the
+ * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
+ * case to make the code more understandable.
+ *
+ * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
+ * the parameter and always returns 0.
+ */
+int vt_kmsg_redirect(int new)
+{
+       static int kmsg_con;
+
+       if (new != -1)
+               return xchg(&kmsg_con, new);
+       else
+               return kmsg_con;
+}
+
+/*
+ *     Console on virtual terminal
+ *
+ * The console must be locked when we get here.
+ */
+
+static void vt_console_print(struct console *co, const char *b, unsigned count)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       unsigned char c;
+       static DEFINE_SPINLOCK(printing_lock);
+       const ushort *start;
+       ushort cnt = 0;
+       ushort myx;
+       int kmsg_console;
+
+       /* console busy or not yet initialized */
+       if (!printable)
+               return;
+       if (!spin_trylock(&printing_lock))
+               return;
+
+       kmsg_console = vt_get_kmsg_redirect();
+       if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
+               vc = vc_cons[kmsg_console - 1].d;
+
+       /* read `x' only after setting currcons properly (otherwise
+          the `x' macro will read the x of the foreground console). */
+       myx = vc->vc_x;
+
+       if (!vc_cons_allocated(fg_console)) {
+               /* impossible */
+               /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
+               goto quit;
+       }
+
+       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+               goto quit;
+
+       /* undraw cursor first */
+       if (IS_FG(vc))
+               hide_cursor(vc);
+
+       start = (ushort *)vc->vc_pos;
+
+       /* Contrived structure to try to emulate original need_wrap behaviour
+        * Problems caused when we have need_wrap set on '\n' character */
+       while (count--) {
+               c = *b++;
+               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
+                       if (cnt > 0) {
+                               if (CON_IS_VISIBLE(vc))
+                                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+                               vc->vc_x += cnt;
+                               if (vc->vc_need_wrap)
+                                       vc->vc_x--;
+                               cnt = 0;
+                       }
+                       if (c == 8) {           /* backspace */
+                               bs(vc);
+                               start = (ushort *)vc->vc_pos;
+                               myx = vc->vc_x;
+                               continue;
+                       }
+                       if (c != 13)
+                               lf(vc);
+                       cr(vc);
+                       start = (ushort *)vc->vc_pos;
+                       myx = vc->vc_x;
+                       if (c == 10 || c == 13)
+                               continue;
+               }
+               scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
+               notify_write(vc, c);
+               cnt++;
+               if (myx == vc->vc_cols - 1) {
+                       vc->vc_need_wrap = 1;
+                       continue;
+               }
+               vc->vc_pos += 2;
+               myx++;
+       }
+       if (cnt > 0) {
+               if (CON_IS_VISIBLE(vc))
+                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+               vc->vc_x += cnt;
+               if (vc->vc_x == vc->vc_cols) {
+                       vc->vc_x--;
+                       vc->vc_need_wrap = 1;
+               }
+       }
+       set_cursor(vc);
+       notify_update(vc);
+
+quit:
+       spin_unlock(&printing_lock);
+}
+
+static struct tty_driver *vt_console_device(struct console *c, int *index)
+{
+       *index = c->index ? c->index-1 : fg_console;
+       return console_driver;
+}
+
+static struct console vt_console_driver = {
+       .name           = "tty",
+       .write          = vt_console_print,
+       .device         = vt_console_device,
+       .unblank        = unblank_screen,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+#endif
+
+/*
+ *     Handling of Linux-specific VC ioctls
+ */
+
+/*
+ * Generally a bit racy with respect to console_sem().
+ *
+ * There are some functions which don't need it.
+ *
+ * There are some functions which can sleep for arbitrary periods
+ * (paste_selection) but we don't need the lock there anyway.
+ *
+ * set_selection has locking, and definitely needs it
+ */
+
+int tioclinux(struct tty_struct *tty, unsigned long arg)
+{
+       char type, data;
+       char __user *p = (char __user *)arg;
+       int lines;
+       int ret;
+
+       if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(type, p))
+               return -EFAULT;
+       ret = 0;
+
+       switch (type)
+       {
+               case TIOCL_SETSEL:
+                       acquire_console_sem();
+                       ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
+                       release_console_sem();
+                       break;
+               case TIOCL_PASTESEL:
+                       ret = paste_selection(tty);
+                       break;
+               case TIOCL_UNBLANKSCREEN:
+                       acquire_console_sem();
+                       unblank_screen();
+                       release_console_sem();
+                       break;
+               case TIOCL_SELLOADLUT:
+                       ret = sel_loadlut(p);
+                       break;
+               case TIOCL_GETSHIFTSTATE:
+
+       /*
+        * Make it possible to react to Shift+Mousebutton.
+        * Note that 'shift_state' is an undocumented
+        * kernel-internal variable; programs not closely
+        * related to the kernel should not use this.
+        */
+                       data = shift_state;
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_GETMOUSEREPORTING:
+                       data = mouse_reporting();
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_SETVESABLANK:
+                       ret = set_vesa_blanking(p);
+                       break;
+               case TIOCL_GETKMSGREDIRECT:
+                       data = vt_get_kmsg_redirect();
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_SETKMSGREDIRECT:
+                       if (!capable(CAP_SYS_ADMIN)) {
+                               ret = -EPERM;
+                       } else {
+                               if (get_user(data, p+1))
+                                       ret = -EFAULT;
+                               else
+                                       vt_kmsg_redirect(data);
+                       }
+                       break;
+               case TIOCL_GETFGCONSOLE:
+                       ret = fg_console;
+                       break;
+               case TIOCL_SCROLLCONSOLE:
+                       if (get_user(lines, (s32 __user *)(p+4))) {
+                               ret = -EFAULT;
+                       } else {
+                               scrollfront(vc_cons[fg_console].d, lines);
+                               ret = 0;
+                       }
+                       break;
+               case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+                       acquire_console_sem();
+                       ignore_poke = 1;
+                       do_blank_screen(0);
+                       release_console_sem();
+                       break;
+               case TIOCL_BLANKEDSCREEN:
+                       ret = console_blanked;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+       }
+       return ret;
+}
+
+/*
+ * /dev/ttyN handling
+ */
+
+static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       int     retval;
+
+       retval = do_con_write(tty, buf, count);
+       con_flush_chars(tty);
+
+       return retval;
+}
+
+static int con_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       if (in_interrupt())
+               return 0;       /* n_r3964 calls put_char() from interrupt context */
+       return do_con_write(tty, &ch, 1);
+}
+
+static int con_write_room(struct tty_struct *tty)
+{
+       if (tty->stopped)
+               return 0;
+       return 32768;           /* No limit, really; we're not buffering */
+}
+
+static int con_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;               /* we're not buffering */
+}
+
+/*
+ * con_throttle and con_unthrottle are only used for
+ * paste_selection(), which has to stuff in a large number of
+ * characters...
+ */
+static void con_throttle(struct tty_struct *tty)
+{
+}
+
+static void con_unthrottle(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+
+       wake_up_interruptible(&vc->paste_wait);
+}
+
+/*
+ * Turn the Scroll-Lock LED on when the tty is stopped
+ */
+static void con_stop(struct tty_struct *tty)
+{
+       int console_num;
+       if (!tty)
+               return;
+       console_num = tty->index;
+       if (!vc_cons_allocated(console_num))
+               return;
+       set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+       set_leds();
+}
+
+/*
+ * Turn the Scroll-Lock LED off when the console is started
+ */
+static void con_start(struct tty_struct *tty)
+{
+       int console_num;
+       if (!tty)
+               return;
+       console_num = tty->index;
+       if (!vc_cons_allocated(console_num))
+               return;
+       clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+       set_leds();
+}
+
+static void con_flush_chars(struct tty_struct *tty)
+{
+       struct vc_data *vc;
+
+       if (in_interrupt())     /* from flush_to_ldisc */
+               return;
+
+       /* if we race with con_close(), vt may be null */
+       acquire_console_sem();
+       vc = tty->driver_data;
+       if (vc)
+               set_cursor(vc);
+       release_console_sem();
+}
+
+/*
+ * Allocate the console screen memory.
+ */
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+       unsigned int currcons = tty->index;
+       int ret = 0;
+
+       acquire_console_sem();
+       if (tty->driver_data == NULL) {
+               ret = vc_allocate(currcons);
+               if (ret == 0) {
+                       struct vc_data *vc = vc_cons[currcons].d;
+
+                       /* Still being freed */
+                       if (vc->port.tty) {
+                               release_console_sem();
+                               return -ERESTARTSYS;
+                       }
+                       tty->driver_data = vc;
+                       vc->port.tty = tty;
+
+                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+                       }
+                       if (vc->vc_utf)
+                               tty->termios->c_iflag |= IUTF8;
+                       else
+                               tty->termios->c_iflag &= ~IUTF8;
+                       release_console_sem();
+                       return ret;
+               }
+       }
+       release_console_sem();
+       return ret;
+}
+
+static void con_close(struct tty_struct *tty, struct file *filp)
+{
+       /* Nothing to do - we defer to shutdown */
+}
+
+static void con_shutdown(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       BUG_ON(vc == NULL);
+       acquire_console_sem();
+       vc->port.tty = NULL;
+       release_console_sem();
+       tty_shutdown(tty);
+}
+
+static int default_italic_color    = 2; // green (ASCII)
+static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
+module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
+
+static void vc_init(struct vc_data *vc, unsigned int rows,
+                   unsigned int cols, int do_clear)
+{
+       int j, k ;
+
+       vc->vc_cols = cols;
+       vc->vc_rows = rows;
+       vc->vc_size_row = cols << 1;
+       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+
+       set_origin(vc);
+       vc->vc_pos = vc->vc_origin;
+       reset_vc(vc);
+       for (j=k=0; j<16; j++) {
+               vc->vc_palette[k++] = default_red[j] ;
+               vc->vc_palette[k++] = default_grn[j] ;
+               vc->vc_palette[k++] = default_blu[j] ;
+       }
+       vc->vc_def_color       = 0x07;   /* white */
+       vc->vc_ulcolor         = default_underline_color;
+       vc->vc_itcolor         = default_italic_color;
+       vc->vc_halfcolor       = 0x08;   /* grey */
+       init_waitqueue_head(&vc->paste_wait);
+       reset_terminal(vc, do_clear);
+}
+
+/*
+ * This routine initializes console interrupts, and does nothing
+ * else. If you want the screen to clear, call tty_write with
+ * the appropriate escape-sequence.
+ */
+
+static int __init con_init(void)
+{
+       const char *display_desc = NULL;
+       struct vc_data *vc;
+       unsigned int currcons = 0, i;
+
+       acquire_console_sem();
+
+       if (conswitchp)
+               display_desc = conswitchp->con_startup();
+       if (!display_desc) {
+               fg_console = 0;
+               release_console_sem();
+               return 0;
+       }
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == NULL) {
+                       con_driver->con = conswitchp;
+                       con_driver->desc = display_desc;
+                       con_driver->flag = CON_DRIVER_FLAG_INIT;
+                       con_driver->first = 0;
+                       con_driver->last = MAX_NR_CONSOLES - 1;
+                       break;
+               }
+       }
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               con_driver_map[i] = conswitchp;
+
+       if (blankinterval) {
+               blank_state = blank_normal_wait;
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+       }
+
+       for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
+               vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
+               INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+               tty_port_init(&vc->port);
+               visual_init(vc, currcons, 1);
+               vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
+               vc_init(vc, vc->vc_rows, vc->vc_cols,
+                       currcons || !vc->vc_sw->con_save_screen);
+       }
+       currcons = fg_console = 0;
+       master_display_fg = vc = vc_cons[currcons].d;
+       set_origin(vc);
+       save_screen(vc);
+       gotoxy(vc, vc->vc_x, vc->vc_y);
+       csi_J(vc, 0);
+       update_screen(vc);
+       printk("Console: %s %s %dx%d",
+               vc->vc_can_do_color ? "colour" : "mono",
+               display_desc, vc->vc_cols, vc->vc_rows);
+       printable = 1;
+       printk("\n");
+
+       release_console_sem();
+
+#ifdef CONFIG_VT_CONSOLE
+       register_console(&vt_console_driver);
+#endif
+       return 0;
+}
+console_initcall(con_init);
+
+static const struct tty_operations con_ops = {
+       .open = con_open,
+       .close = con_close,
+       .write = con_write,
+       .write_room = con_write_room,
+       .put_char = con_put_char,
+       .flush_chars = con_flush_chars,
+       .chars_in_buffer = con_chars_in_buffer,
+       .ioctl = vt_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = vt_compat_ioctl,
+#endif
+       .stop = con_stop,
+       .start = con_start,
+       .throttle = con_throttle,
+       .unthrottle = con_unthrottle,
+       .resize = vt_resize,
+       .shutdown = con_shutdown
+};
+
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
+{
+       cdev_init(&vc0_cdev, console_fops);
+       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+               panic("Couldn't register /dev/tty0 driver\n");
+       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
+       vcs_init();
+
+       console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
+       if (!console_driver)
+               panic("Couldn't allocate console driver\n");
+       console_driver->owner = THIS_MODULE;
+       console_driver->name = "tty";
+       console_driver->name_base = 1;
+       console_driver->major = TTY_MAJOR;
+       console_driver->minor_start = 1;
+       console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+       console_driver->init_termios = tty_std_termios;
+       if (default_utf8)
+               console_driver->init_termios.c_iflag |= IUTF8;
+       console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+       tty_set_operations(console_driver, &con_ops);
+       if (tty_register_driver(console_driver))
+               panic("Couldn't register console driver\n");
+       kbd_init();
+       console_map_init();
+#ifdef CONFIG_MDA_CONSOLE
+       mda_console_init();
+#endif
+       return 0;
+}
+
+#ifndef VT_SINGLE_DRIVER
+
+static struct class *vtconsole_class;
+
+static int bind_con_driver(const struct consw *csw, int first, int last,
+                          int deflt)
+{
+       struct module *owner = csw->owner;
+       const char *desc = NULL;
+       struct con_driver *con_driver;
+       int i, j = -1, k = -1, retval = -ENODEV;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       /* check if driver is registered */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw) {
+                       desc = con_driver->desc;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval)
+               goto err;
+
+       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
+               csw->con_startup();
+               con_driver->flag |= CON_DRIVER_FLAG_INIT;
+       }
+
+       if (deflt) {
+               if (conswitchp)
+                       module_put(conswitchp->owner);
+
+               __module_get(owner);
+               conswitchp = csw;
+       }
+
+       first = max(first, con_driver->first);
+       last = min(last, con_driver->last);
+
+       for (i = first; i <= last; i++) {
+               int old_was_color;
+               struct vc_data *vc = vc_cons[i].d;
+
+               if (con_driver_map[i])
+                       module_put(con_driver_map[i]->owner);
+               __module_get(owner);
+               con_driver_map[i] = csw;
+
+               if (!vc || !vc->vc_sw)
+                       continue;
+
+               j = i;
+
+               if (CON_IS_VISIBLE(vc)) {
+                       k = i;
+                       save_screen(vc);
+               }
+
+               old_was_color = vc->vc_can_do_color;
+               vc->vc_sw->con_deinit(vc);
+               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+               visual_init(vc, i, 0);
+               set_origin(vc);
+               update_attr(vc);
+
+               /* If the console changed between mono <-> color, then
+                * the attributes in the screenbuf will be wrong.  The
+                * following resets all attributes to something sane.
+                */
+               if (old_was_color != vc->vc_can_do_color)
+                       clear_buffer_attributes(vc);
+       }
+
+       printk("Console: switching ");
+       if (!deflt)
+               printk("consoles %d-%d ", first+1, last+1);
+       if (j >= 0) {
+               struct vc_data *vc = vc_cons[j].d;
+
+               printk("to %s %s %dx%d\n",
+                      vc->vc_can_do_color ? "colour" : "mono",
+                      desc, vc->vc_cols, vc->vc_rows);
+
+               if (k >= 0) {
+                       vc = vc_cons[k].d;
+                       update_screen(vc);
+               }
+       } else
+               printk("to %s\n", desc);
+
+       retval = 0;
+err:
+       release_console_sem();
+       module_put(owner);
+       return retval;
+};
+
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int con_is_graphics(const struct consw *csw, int first, int last)
+{
+       int i, retval = 0;
+
+       for (i = first; i <= last; i++) {
+               struct vc_data *vc = vc_cons[i].d;
+
+               if (vc && vc->vc_mode == KD_GRAPHICS) {
+                       retval = 1;
+                       break;
+               }
+       }
+
+       return retval;
+}
+
+/**
+ * unbind_con_driver - unbind a console driver
+ * @csw: pointer to console driver to unregister
+ * @first: first in range of consoles that @csw should be unbound from
+ * @last: last in range of consoles that @csw should be unbound from
+ * @deflt: should next bound console driver be default after @csw is unbound?
+ *
+ * To unbind a driver from all possible consoles, pass 0 as @first and
+ * %MAX_NR_CONSOLES as @last.
+ *
+ * @deflt controls whether the console that ends up replacing @csw should be
+ * the default console.
+ *
+ * RETURNS:
+ * -ENODEV if @csw isn't a registered console driver or can't be unregistered
+ * or 0 on success.
+ */
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
+{
+       struct module *owner = csw->owner;
+       const struct consw *defcsw = NULL;
+       struct con_driver *con_driver = NULL, *con_back = NULL;
+       int i, retval = -ENODEV;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       /* check if driver is registered and if it is unbindable */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw &&
+                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval) {
+               release_console_sem();
+               goto err;
+       }
+
+       retval = -ENODEV;
+
+       /* check if backup driver exists */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_back = &registered_con_driver[i];
+
+               if (con_back->con &&
+                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+                       defcsw = con_back->con;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval) {
+               release_console_sem();
+               goto err;
+       }
+
+       if (!con_is_bound(csw)) {
+               release_console_sem();
+               goto err;
+       }
+
+       first = max(first, con_driver->first);
+       last = min(last, con_driver->last);
+
+       for (i = first; i <= last; i++) {
+               if (con_driver_map[i] == csw) {
+                       module_put(csw->owner);
+                       con_driver_map[i] = NULL;
+               }
+       }
+
+       if (!con_is_bound(defcsw)) {
+               const struct consw *defconsw = conswitchp;
+
+               defcsw->con_startup();
+               con_back->flag |= CON_DRIVER_FLAG_INIT;
+               /*
+                * vgacon may change the default driver to point
+                * to dummycon, we restore it here...
+                */
+               conswitchp = defconsw;
+       }
+
+       if (!con_is_bound(csw))
+               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
+
+       release_console_sem();
+       /* ignore return value, binding should not fail */
+       bind_con_driver(defcsw, first, last, deflt);
+err:
+       module_put(owner);
+       return retval;
+
+}
+EXPORT_SYMBOL(unbind_con_driver);
+
+static int vt_bind(struct con_driver *con)
+{
+       const struct consw *defcsw = NULL, *csw = NULL;
+       int i, more = 1, first = -1, last = -1, deflt = 0;
+
+       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+           con_is_graphics(con->con, con->first, con->last))
+               goto err;
+
+       csw = con->con;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con = &registered_con_driver[i];
+
+               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
+                       defcsw = con->con;
+                       break;
+               }
+       }
+
+       if (!defcsw)
+               goto err;
+
+       while (more) {
+               more = 0;
+
+               for (i = con->first; i <= con->last; i++) {
+                       if (con_driver_map[i] == defcsw) {
+                               if (first == -1)
+                                       first = i;
+                               last = i;
+                               more = 1;
+                       } else if (first != -1)
+                               break;
+               }
+
+               if (first == 0 && last == MAX_NR_CONSOLES -1)
+                       deflt = 1;
+
+               if (first != -1)
+                       bind_con_driver(csw, first, last, deflt);
+
+               first = -1;
+               last = -1;
+               deflt = 0;
+       }
+
+err:
+       return 0;
+}
+
+static int vt_unbind(struct con_driver *con)
+{
+       const struct consw *csw = NULL;
+       int i, more = 1, first = -1, last = -1, deflt = 0;
+
+       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+           con_is_graphics(con->con, con->first, con->last))
+               goto err;
+
+       csw = con->con;
+
+       while (more) {
+               more = 0;
+
+               for (i = con->first; i <= con->last; i++) {
+                       if (con_driver_map[i] == csw) {
+                               if (first == -1)
+                                       first = i;
+                               last = i;
+                               more = 1;
+                       } else if (first != -1)
+                               break;
+               }
+
+               if (first == 0 && last == MAX_NR_CONSOLES -1)
+                       deflt = 1;
+
+               if (first != -1)
+                       unbind_con_driver(csw, first, last, deflt);
+
+               first = -1;
+               last = -1;
+               deflt = 0;
+       }
+
+err:
+       return 0;
+}
+#else
+static inline int vt_bind(struct con_driver *con)
+{
+       return 0;
+}
+static inline int vt_unbind(struct con_driver *con)
+{
+       return 0;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+       int bind = simple_strtoul(buf, NULL, 0);
+
+       if (bind)
+               vt_bind(con);
+       else
+               vt_unbind(con);
+
+       return count;
+}
+
+static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+       int bind = con_is_bound(con->con);
+
+       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%s %s\n",
+                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
+                        con->desc);
+
+}
+
+static struct device_attribute device_attrs[] = {
+       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
+       __ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static int vtconsole_init_device(struct con_driver *con)
+{
+       int i;
+       int error = 0;
+
+       con->flag |= CON_DRIVER_FLAG_ATTR;
+       dev_set_drvdata(con->dev, con);
+       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+               error = device_create_file(con->dev, &device_attrs[i]);
+               if (error)
+                       break;
+       }
+
+       if (error) {
+               while (--i >= 0)
+                       device_remove_file(con->dev, &device_attrs[i]);
+               con->flag &= ~CON_DRIVER_FLAG_ATTR;
+       }
+
+       return error;
+}
+
+static void vtconsole_deinit_device(struct con_driver *con)
+{
+       int i;
+
+       if (con->flag & CON_DRIVER_FLAG_ATTR) {
+               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+                       device_remove_file(con->dev, &device_attrs[i]);
+               con->flag &= ~CON_DRIVER_FLAG_ATTR;
+       }
+}
+
+/**
+ * con_is_bound - checks if driver is bound to the console
+ * @csw: console driver
+ *
+ * RETURNS: zero if unbound, nonzero if bound
+ *
+ * Drivers can call this and if zero, they should release
+ * all resources allocated on con_startup()
+ */
+int con_is_bound(const struct consw *csw)
+{
+       int i, bound = 0;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (con_driver_map[i] == csw) {
+                       bound = 1;
+                       break;
+               }
+       }
+
+       return bound;
+}
+EXPORT_SYMBOL(con_is_bound);
+
+/**
+ * con_debug_enter - prepare the console for the kernel debugger
+ * @sw: console driver
+ *
+ * Called when the console is taken over by the kernel debugger, this
+ * function needs to save the current console state, then put the console
+ * into a state suitable for the kernel debugger.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to prepare
+ * the console for the debugger.
+ */
+int con_debug_enter(struct vc_data *vc)
+{
+       int ret = 0;
+
+       saved_fg_console = fg_console;
+       saved_last_console = last_console;
+       saved_want_console = want_console;
+       saved_vc_mode = vc->vc_mode;
+       saved_console_blanked = console_blanked;
+       vc->vc_mode = KD_TEXT;
+       console_blanked = 0;
+       if (vc->vc_sw->con_debug_enter)
+               ret = vc->vc_sw->con_debug_enter(vc);
+#ifdef CONFIG_KGDB_KDB
+       /* Set the initial LINES variable if it is not already set */
+       if (vc->vc_rows < 999) {
+               int linecount;
+               char lns[4];
+               const char *setargs[3] = {
+                       "set",
+                       "LINES",
+                       lns,
+               };
+               if (kdbgetintenv(setargs[0], &linecount)) {
+                       snprintf(lns, 4, "%i", vc->vc_rows);
+                       kdb_set(2, setargs);
+               }
+       }
+#endif /* CONFIG_KGDB_KDB */
+       return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_enter);
+
+/**
+ * con_debug_leave - restore console state
+ * @sw: console driver
+ *
+ * Restore the console state to what it was before the kernel debugger
+ * was invoked.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to restore
+ * the console.
+ */
+int con_debug_leave(void)
+{
+       struct vc_data *vc;
+       int ret = 0;
+
+       fg_console = saved_fg_console;
+       last_console = saved_last_console;
+       want_console = saved_want_console;
+       console_blanked = saved_console_blanked;
+       vc_cons[fg_console].d->vc_mode = saved_vc_mode;
+
+       vc = vc_cons[fg_console].d;
+       if (vc->vc_sw->con_debug_leave)
+               ret = vc->vc_sw->con_debug_leave(vc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_leave);
+
+/**
+ * register_con_driver - register console driver to console layer
+ * @csw: console driver
+ * @first: the first console to take over, minimum value is 0
+ * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
+ *
+ * DESCRIPTION: This function registers a console driver which can later
+ * bind to a range of consoles specified by @first and @last. It will
+ * also initialize the console driver by calling con_startup().
+ */
+int register_con_driver(const struct consw *csw, int first, int last)
+{
+       struct module *owner = csw->owner;
+       struct con_driver *con_driver;
+       const char *desc;
+       int i, retval = 0;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               /* already registered */
+               if (con_driver->con == csw)
+                       retval = -EINVAL;
+       }
+
+       if (retval)
+               goto err;
+
+       desc = csw->con_startup();
+
+       if (!desc)
+               goto err;
+
+       retval = -EINVAL;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == NULL) {
+                       con_driver->con = csw;
+                       con_driver->desc = desc;
+                       con_driver->node = i;
+                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
+                                          CON_DRIVER_FLAG_INIT;
+                       con_driver->first = first;
+                       con_driver->last = last;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval)
+               goto err;
+
+       con_driver->dev = device_create(vtconsole_class, NULL,
+                                               MKDEV(0, con_driver->node),
+                                               NULL, "vtcon%i",
+                                               con_driver->node);
+
+       if (IS_ERR(con_driver->dev)) {
+               printk(KERN_WARNING "Unable to create device for %s; "
+                      "errno = %ld\n", con_driver->desc,
+                      PTR_ERR(con_driver->dev));
+               con_driver->dev = NULL;
+       } else {
+               vtconsole_init_device(con_driver);
+       }
+
+err:
+       release_console_sem();
+       module_put(owner);
+       return retval;
+}
+EXPORT_SYMBOL(register_con_driver);
+
+/**
+ * unregister_con_driver - unregister console driver from console layer
+ * @csw: console driver
+ *
+ * DESCRIPTION: All drivers that registers to the console layer must
+ * call this function upon exit, or if the console driver is in a state
+ * where it won't be able to handle console services, such as the
+ * framebuffer console without loaded framebuffer drivers.
+ *
+ * The driver must unbind first prior to unregistration.
+ */
+int unregister_con_driver(const struct consw *csw)
+{
+       int i, retval = -ENODEV;
+
+       acquire_console_sem();
+
+       /* cannot unregister a bound driver */
+       if (con_is_bound(csw))
+               goto err;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw &&
+                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+                       vtconsole_deinit_device(con_driver);
+                       device_destroy(vtconsole_class,
+                                      MKDEV(0, con_driver->node));
+                       con_driver->con = NULL;
+                       con_driver->desc = NULL;
+                       con_driver->dev = NULL;
+                       con_driver->node = 0;
+                       con_driver->flag = 0;
+                       con_driver->first = 0;
+                       con_driver->last = 0;
+                       retval = 0;
+                       break;
+               }
+       }
+err:
+       release_console_sem();
+       return retval;
+}
+EXPORT_SYMBOL(unregister_con_driver);
+
+/*
+ *     If we support more console drivers, this function is used
+ *     when a driver wants to take over some existing consoles
+ *     and become default driver for newly opened ones.
+ *
+ *      take_over_console is basically a register followed by unbind
+ */
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
+{
+       int err;
+
+       err = register_con_driver(csw, first, last);
+
+       if (!err)
+               bind_con_driver(csw, first, last, deflt);
+
+       return err;
+}
+
+/*
+ * give_up_console is a wrapper to unregister_con_driver. It will only
+ * work if driver is fully unbound.
+ */
+void give_up_console(const struct consw *csw)
+{
+       unregister_con_driver(csw);
+}
+
+static int __init vtconsole_class_init(void)
+{
+       int i;
+
+       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
+       if (IS_ERR(vtconsole_class)) {
+               printk(KERN_WARNING "Unable to create vt console class; "
+                      "errno = %ld\n", PTR_ERR(vtconsole_class));
+               vtconsole_class = NULL;
+       }
+
+       /* Add system drivers to sysfs */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con = &registered_con_driver[i];
+
+               if (con->con && !con->dev) {
+                       con->dev = device_create(vtconsole_class, NULL,
+                                                        MKDEV(0, con->node),
+                                                        NULL, "vtcon%i",
+                                                        con->node);
+
+                       if (IS_ERR(con->dev)) {
+                               printk(KERN_WARNING "Unable to create "
+                                      "device for %s; errno = %ld\n",
+                                      con->desc, PTR_ERR(con->dev));
+                               con->dev = NULL;
+                       } else {
+                               vtconsole_init_device(con);
+                       }
+               }
+       }
+
+       return 0;
+}
+postcore_initcall(vtconsole_class_init);
+
+#endif
+
+/*
+ *     Screen blanking
+ */
+
+static int set_vesa_blanking(char __user *p)
+{
+       unsigned int mode;
+
+       if (get_user(mode, p + 1))
+               return -EFAULT;
+
+       vesa_blank_mode = (mode < 4) ? mode : 0;
+       return 0;
+}
+
+void do_blank_screen(int entering_gfx)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       int i;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (console_blanked) {
+               if (blank_state == blank_vesa_wait) {
+                       blank_state = blank_off;
+                       vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
+               }
+               return;
+       }
+
+       /* entering graphics mode? */
+       if (entering_gfx) {
+               hide_cursor(vc);
+               save_screen(vc);
+               vc->vc_sw->con_blank(vc, -1, 1);
+               console_blanked = fg_console + 1;
+               blank_state = blank_off;
+               set_origin(vc);
+               return;
+       }
+
+       if (blank_state != blank_normal_wait)
+               return;
+       blank_state = blank_off;
+
+       /* don't blank graphics */
+       if (vc->vc_mode != KD_TEXT) {
+               console_blanked = fg_console + 1;
+               return;
+       }
+
+       hide_cursor(vc);
+       del_timer_sync(&console_timer);
+       blank_timer_expired = 0;
+
+       save_screen(vc);
+       /* In case we need to reset origin, blanking hook returns 1 */
+       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
+       console_blanked = fg_console + 1;
+       if (i)
+               set_origin(vc);
+
+       if (console_blank_hook && console_blank_hook(1))
+               return;
+
+       if (vesa_off_interval && vesa_blank_mode) {
+               blank_state = blank_vesa_wait;
+               mod_timer(&console_timer, jiffies + vesa_off_interval);
+       }
+       vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
+}
+EXPORT_SYMBOL(do_blank_screen);
+
+/*
+ * Called by timer as well as from vt_console_driver
+ */
+void do_unblank_screen(int leaving_gfx)
+{
+       struct vc_data *vc;
+
+       /* This should now always be called from a "sane" (read: can schedule)
+        * context for the sake of the low level drivers, except in the special
+        * case of oops_in_progress
+        */
+       if (!oops_in_progress)
+               might_sleep();
+
+       WARN_CONSOLE_UNLOCKED();
+
+       ignore_poke = 0;
+       if (!console_blanked)
+               return;
+       if (!vc_cons_allocated(fg_console)) {
+               /* impossible */
+               printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
+               return;
+       }
+       vc = vc_cons[fg_console].d;
+       /* Try to unblank in oops case too */
+       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+               return; /* but leave console_blanked != 0 */
+
+       if (blankinterval) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               blank_state = blank_normal_wait;
+       }
+
+       console_blanked = 0;
+       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
+               /* Low-level driver cannot restore -> do it ourselves */
+               update_screen(vc);
+       if (console_blank_hook)
+               console_blank_hook(0);
+       set_palette(vc);
+       set_cursor(vc);
+       vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
+}
+EXPORT_SYMBOL(do_unblank_screen);
+
+/*
+ * This is called by the outside world to cause a forced unblank, mostly for
+ * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
+ * call it with 1 as an argument and so force a mode restore... that may kill
+ * X or at least garbage the screen but would also make the Oops visible...
+ */
+void unblank_screen(void)
+{
+       do_unblank_screen(0);
+}
+
+/*
+ * We defer the timer blanking to work queue so it can take the console mutex
+ * (console operations can still happen at irq time, but only from printk which
+ * has the console mutex. Not perfect yet, but better than no locking
+ */
+static void blank_screen_t(unsigned long dummy)
+{
+       if (unlikely(!keventd_up())) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               return;
+       }
+       blank_timer_expired = 1;
+       schedule_work(&console_work);
+}
+
+void poke_blanked_console(void)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       /* Add this so we quickly catch whoever might call us in a non
+        * safe context. Nowadays, unblank_screen() isn't to be called in
+        * atomic contexts and is allowed to schedule (with the special case
+        * of oops_in_progress, but that isn't of any concern for this
+        * function. --BenH.
+        */
+       might_sleep();
+
+       /* This isn't perfectly race free, but a race here would be mostly harmless,
+        * at worse, we'll do a spurrious blank and it's unlikely
+        */
+       del_timer(&console_timer);
+       blank_timer_expired = 0;
+
+       if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
+               return;
+       if (console_blanked)
+               unblank_screen();
+       else if (blankinterval) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               blank_state = blank_normal_wait;
+       }
+}
+
+/*
+ *     Palettes
+ */
+
+static void set_palette(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc->vc_mode != KD_GRAPHICS)
+               vc->vc_sw->con_set_palette(vc, color_table);
+}
+
+static int set_get_cmap(unsigned char __user *arg, int set)
+{
+    int i, j, k;
+
+    WARN_CONSOLE_UNLOCKED();
+
+    for (i = 0; i < 16; i++)
+       if (set) {
+           get_user(default_red[i], arg++);
+           get_user(default_grn[i], arg++);
+           get_user(default_blu[i], arg++);
+       } else {
+           put_user(default_red[i], arg++);
+           put_user(default_grn[i], arg++);
+           put_user(default_blu[i], arg++);
+       }
+    if (set) {
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+           if (vc_cons_allocated(i)) {
+               for (j = k = 0; j < 16; j++) {
+                   vc_cons[i].d->vc_palette[k++] = default_red[j];
+                   vc_cons[i].d->vc_palette[k++] = default_grn[j];
+                   vc_cons[i].d->vc_palette[k++] = default_blu[j];
+               }
+               set_palette(vc_cons[i].d);
+           }
+    }
+    return 0;
+}
+
+/*
+ * Load palette into the DAC registers. arg points to a colour
+ * map, 3 bytes per colour, 16 colours, range from 0 to 255.
+ */
+
+int con_set_cmap(unsigned char __user *arg)
+{
+       int rc;
+
+       acquire_console_sem();
+       rc = set_get_cmap (arg,1);
+       release_console_sem();
+
+       return rc;
+}
+
+int con_get_cmap(unsigned char __user *arg)
+{
+       int rc;
+
+       acquire_console_sem();
+       rc = set_get_cmap (arg,0);
+       release_console_sem();
+
+       return rc;
+}
+
+void reset_palette(struct vc_data *vc)
+{
+       int j, k;
+       for (j=k=0; j<16; j++) {
+               vc->vc_palette[k++] = default_red[j];
+               vc->vc_palette[k++] = default_grn[j];
+               vc->vc_palette[k++] = default_blu[j];
+       }
+       set_palette(vc);
+}
+
+/*
+ *  Font switching
+ *
+ *  Currently we only support fonts up to 32 pixels wide, at a maximum height
+ *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
+ *  depending on width) reserved for each character which is kinda wasty, but 
+ *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
+ *  is upto the actual low-level console-driver convert data into its favorite
+ *  format (maybe we should add a `fontoffset' field to the `display'
+ *  structure so we won't have to convert the fontdata all the time.
+ *  /Jes
+ */
+
+#define max_font_size 65536
+
+static int con_font_get(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font;
+       int rc = -EINVAL;
+       int c;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       if (op->data) {
+               font.data = kmalloc(max_font_size, GFP_KERNEL);
+               if (!font.data)
+                       return -ENOMEM;
+       } else
+               font.data = NULL;
+
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_get)
+               rc = vc->vc_sw->con_font_get(vc, &font);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+
+       if (rc)
+               goto out;
+
+       c = (font.width+7)/8 * 32 * font.charcount;
+
+       if (op->data && font.charcount > op->charcount)
+               rc = -ENOSPC;
+       if (!(op->flags & KD_FONT_FLAG_OLD)) {
+               if (font.width > op->width || font.height > op->height) 
+                       rc = -ENOSPC;
+       } else {
+               if (font.width != 8)
+                       rc = -EIO;
+               else if ((op->height && font.height > op->height) ||
+                        font.height > 32)
+                       rc = -ENOSPC;
+       }
+       if (rc)
+               goto out;
+
+       op->height = font.height;
+       op->width = font.width;
+       op->charcount = font.charcount;
+
+       if (op->data && copy_to_user(op->data, font.data, c))
+               rc = -EFAULT;
+
+out:
+       kfree(font.data);
+       return rc;
+}
+
+static int con_font_set(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font;
+       int rc = -EINVAL;
+       int size;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+       if (!op->data)
+               return -EINVAL;
+       if (op->charcount > 512)
+               return -EINVAL;
+       if (!op->height) {              /* Need to guess font height [compat] */
+               int h, i;
+               u8 __user *charmap = op->data;
+               u8 tmp;
+               
+               /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+                  so that we can get rid of this soon */
+               if (!(op->flags & KD_FONT_FLAG_OLD))
+                       return -EINVAL;
+               for (h = 32; h > 0; h--)
+                       for (i = 0; i < op->charcount; i++) {
+                               if (get_user(tmp, &charmap[32*i+h-1]))
+                                       return -EFAULT;
+                               if (tmp)
+                                       goto nonzero;
+                       }
+               return -EINVAL;
+       nonzero:
+               op->height = h;
+       }
+       if (op->width <= 0 || op->width > 32 || op->height > 32)
+               return -EINVAL;
+       size = (op->width+7)/8 * 32 * op->charcount;
+       if (size > max_font_size)
+               return -ENOSPC;
+       font.charcount = op->charcount;
+       font.height = op->height;
+       font.width = op->width;
+       font.data = memdup_user(op->data, size);
+       if (IS_ERR(font.data))
+               return PTR_ERR(font.data);
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_set)
+               rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+       kfree(font.data);
+       return rc;
+}
+
+static int con_font_default(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font = {.width = op->width, .height = op->height};
+       char name[MAX_FONT_NAME];
+       char *s = name;
+       int rc;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       if (!op->data)
+               s = NULL;
+       else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
+               return -EFAULT;
+       else
+               name[MAX_FONT_NAME - 1] = 0;
+
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_default)
+               rc = vc->vc_sw->con_font_default(vc, &font, s);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+       if (!rc) {
+               op->width = font.width;
+               op->height = font.height;
+       }
+       return rc;
+}
+
+static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
+{
+       int con = op->height;
+       int rc;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       acquire_console_sem();
+       if (!vc->vc_sw->con_font_copy)
+               rc = -ENOSYS;
+       else if (con < 0 || !vc_cons_allocated(con))
+               rc = -ENOTTY;
+       else if (con == vc->vc_num)     /* nothing to do */
+               rc = 0;
+       else
+               rc = vc->vc_sw->con_font_copy(vc, con);
+       release_console_sem();
+       return rc;
+}
+
+int con_font_op(struct vc_data *vc, struct console_font_op *op)
+{
+       switch (op->op) {
+       case KD_FONT_OP_SET:
+               return con_font_set(vc, op);
+       case KD_FONT_OP_GET:
+               return con_font_get(vc, op);
+       case KD_FONT_OP_SET_DEFAULT:
+               return con_font_default(vc, op);
+       case KD_FONT_OP_COPY:
+               return con_font_copy(vc, op);
+       }
+       return -ENOSYS;
+}
+
+/*
+ *     Interface exported to selection and vcs.
+ */
+
+/* used by selection */
+u16 screen_glyph(struct vc_data *vc, int offset)
+{
+       u16 w = scr_readw(screenpos(vc, offset, 1));
+       u16 c = w & 0xff;
+
+       if (w & vc->vc_hi_font_mask)
+               c |= 0x100;
+       return c;
+}
+EXPORT_SYMBOL_GPL(screen_glyph);
+
+/* used by vcs - note the word offset */
+unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
+{
+       return screenpos(vc, 2 * w_offset, viewed);
+}
+
+void getconsxy(struct vc_data *vc, unsigned char *p)
+{
+       p[0] = vc->vc_x;
+       p[1] = vc->vc_y;
+}
+
+void putconsxy(struct vc_data *vc, unsigned char *p)
+{
+       hide_cursor(vc);
+       gotoxy(vc, p[0], p[1]);
+       set_cursor(vc);
+}
+
+u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
+{
+       if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
+               return softcursor_original;
+       return scr_readw(org);
+}
+
+void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
+{
+       scr_writew(val, org);
+       if ((unsigned long)org == vc->vc_pos) {
+               softcursor_original = -1;
+               add_softcursor(vc);
+       }
+}
+
+void vcs_scr_updated(struct vc_data *vc)
+{
+       notify_update(vc);
+}
+
+/*
+ *     Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(color_table);
+EXPORT_SYMBOL(default_red);
+EXPORT_SYMBOL(default_grn);
+EXPORT_SYMBOL(default_blu);
+EXPORT_SYMBOL(update_region);
+EXPORT_SYMBOL(redraw_screen);
+EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(fg_console);
+EXPORT_SYMBOL(console_blank_hook);
+EXPORT_SYMBOL(console_blanked);
+EXPORT_SYMBOL(vc_cons);
+EXPORT_SYMBOL(global_cursor_default);
+#ifndef VT_SINGLE_DRIVER
+EXPORT_SYMBOL(take_over_console);
+EXPORT_SYMBOL(give_up_console);
+#endif
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
new file mode 100644 (file)
index 0000000..6b68a0f
--- /dev/null
@@ -0,0 +1,1788 @@
+/*
+ *  linux/drivers/char/vt_ioctl.c
+ *
+ *  Copyright (C) 1992 obz under the linux copyright
+ *
+ *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
+ *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
+ *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
+ *  Some code moved for less code duplication - Andi Kleen - Mar 1997
+ *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/compat.h>
+#include <linux/module.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/console.h>
+#include <linux/consolemap.h>
+#include <linux/signal.h>
+#include <linux/smp_lock.h>
+#include <linux/timex.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/selection.h>
+
+char vt_dont_switch;
+extern struct tty_driver *console_driver;
+
+#define VT_IS_IN_USE(i)        (console_driver->ttys[i] && console_driver->ttys[i]->count)
+#define VT_BUSY(i)     (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
+
+/*
+ * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
+ * experimentation and study of X386 SYSV handling.
+ *
+ * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
+ * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
+ * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
+ * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
+ * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
+ * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
+ * to the current console is done by the main ioctl code.
+ */
+
+#ifdef CONFIG_X86
+#include <linux/syscalls.h>
+#endif
+
+static void complete_change_console(struct vc_data *vc);
+
+/*
+ *     User space VT_EVENT handlers
+ */
+
+struct vt_event_wait {
+       struct list_head list;
+       struct vt_event event;
+       int done;
+};
+
+static LIST_HEAD(vt_events);
+static DEFINE_SPINLOCK(vt_event_lock);
+static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
+
+/**
+ *     vt_event_post
+ *     @event: the event that occurred
+ *     @old: old console
+ *     @new: new console
+ *
+ *     Post an VT event to interested VT handlers
+ */
+
+void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
+{
+       struct list_head *pos, *head;
+       unsigned long flags;
+       int wake = 0;
+
+       spin_lock_irqsave(&vt_event_lock, flags);
+       head = &vt_events;
+
+       list_for_each(pos, head) {
+               struct vt_event_wait *ve = list_entry(pos,
+                                               struct vt_event_wait, list);
+               if (!(ve->event.event & event))
+                       continue;
+               ve->event.event = event;
+               /* kernel view is consoles 0..n-1, user space view is
+                  console 1..n with 0 meaning current, so we must bias */
+               ve->event.oldev = old + 1;
+               ve->event.newev = new + 1;
+               wake = 1;
+               ve->done = 1;
+       }
+       spin_unlock_irqrestore(&vt_event_lock, flags);
+       if (wake)
+               wake_up_interruptible(&vt_event_waitqueue);
+}
+
+/**
+ *     vt_event_wait           -       wait for an event
+ *     @vw: our event
+ *
+ *     Waits for an event to occur which completes our vt_event_wait
+ *     structure. On return the structure has wv->done set to 1 for success
+ *     or 0 if some event such as a signal ended the wait.
+ */
+
+static void vt_event_wait(struct vt_event_wait *vw)
+{
+       unsigned long flags;
+       /* Prepare the event */
+       INIT_LIST_HEAD(&vw->list);
+       vw->done = 0;
+       /* Queue our event */
+       spin_lock_irqsave(&vt_event_lock, flags);
+       list_add(&vw->list, &vt_events);
+       spin_unlock_irqrestore(&vt_event_lock, flags);
+       /* Wait for it to pass */
+       wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
+       /* Dequeue it */
+       spin_lock_irqsave(&vt_event_lock, flags);
+       list_del(&vw->list);
+       spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+/**
+ *     vt_event_wait_ioctl     -       event ioctl handler
+ *     @arg: argument to ioctl
+ *
+ *     Implement the VT_WAITEVENT ioctl using the VT event interface
+ */
+
+static int vt_event_wait_ioctl(struct vt_event __user *event)
+{
+       struct vt_event_wait vw;
+
+       if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
+               return -EFAULT;
+       /* Highest supported event for now */
+       if (vw.event.event & ~VT_MAX_EVENT)
+               return -EINVAL;
+
+       vt_event_wait(&vw);
+       /* If it occurred report it */
+       if (vw.done) {
+               if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
+                       return -EFAULT;
+               return 0;
+       }
+       return -EINTR;
+}
+
+/**
+ *     vt_waitactive   -       active console wait
+ *     @event: event code
+ *     @n: new console
+ *
+ *     Helper for event waits. Used to implement the legacy
+ *     event waiting ioctls in terms of events
+ */
+
+int vt_waitactive(int n)
+{
+       struct vt_event_wait vw;
+       do {
+               if (n == fg_console + 1)
+                       break;
+               vw.event.event = VT_EVENT_SWITCH;
+               vt_event_wait(&vw);
+               if (vw.done == 0)
+                       return -EINTR;
+       } while (vw.event.newev != n);
+       return 0;
+}
+
+/*
+ * these are the valid i/o ports we're allowed to change. they map all the
+ * video ports
+ */
+#define GPFIRST 0x3b4
+#define GPLAST 0x3df
+#define GPNUM (GPLAST - GPFIRST + 1)
+
+#define i (tmp.kb_index)
+#define s (tmp.kb_table)
+#define v (tmp.kb_value)
+static inline int
+do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
+{
+       struct kbentry tmp;
+       ushort *key_map, val, ov;
+
+       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+               return -EFAULT;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       switch (cmd) {
+       case KDGKBENT:
+               key_map = key_maps[s];
+               if (key_map) {
+                   val = U(key_map[i]);
+                   if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+                       val = K_HOLE;
+               } else
+                   val = (i ? K_HOLE : K_NOSUCHMAP);
+               return put_user(val, &user_kbe->kb_value);
+       case KDSKBENT:
+               if (!perm)
+                       return -EPERM;
+               if (!i && v == K_NOSUCHMAP) {
+                       /* deallocate map */
+                       key_map = key_maps[s];
+                       if (s && key_map) {
+                           key_maps[s] = NULL;
+                           if (key_map[0] == U(K_ALLOCATED)) {
+                                       kfree(key_map);
+                                       keymap_count--;
+                           }
+                       }
+                       break;
+               }
+
+               if (KTYP(v) < NR_TYPES) {
+                   if (KVAL(v) > max_vals[KTYP(v)])
+                               return -EINVAL;
+               } else
+                   if (kbd->kbdmode != VC_UNICODE)
+                               return -EINVAL;
+
+               /* ++Geert: non-PC keyboards may generate keycode zero */
+#if !defined(__mc68000__) && !defined(__powerpc__)
+               /* assignment to entry 0 only tests validity of args */
+               if (!i)
+                       break;
+#endif
+
+               if (!(key_map = key_maps[s])) {
+                       int j;
+
+                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+                           !capable(CAP_SYS_RESOURCE))
+                               return -EPERM;
+
+                       key_map = kmalloc(sizeof(plain_map),
+                                                    GFP_KERNEL);
+                       if (!key_map)
+                               return -ENOMEM;
+                       key_maps[s] = key_map;
+                       key_map[0] = U(K_ALLOCATED);
+                       for (j = 1; j < NR_KEYS; j++)
+                               key_map[j] = U(K_HOLE);
+                       keymap_count++;
+               }
+               ov = U(key_map[i]);
+               if (v == ov)
+                       break;  /* nothing to do */
+               /*
+                * Attention Key.
+                */
+               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               key_map[i] = U(v);
+               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
+                       compute_shiftstate();
+               break;
+       }
+       return 0;
+}
+#undef i
+#undef s
+#undef v
+
+static inline int 
+do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
+{
+       struct kbkeycode tmp;
+       int kc = 0;
+
+       if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
+               return -EFAULT;
+       switch (cmd) {
+       case KDGETKEYCODE:
+               kc = getkeycode(tmp.scancode);
+               if (kc >= 0)
+                       kc = put_user(kc, &user_kbkc->keycode);
+               break;
+       case KDSETKEYCODE:
+               if (!perm)
+                       return -EPERM;
+               kc = setkeycode(tmp.scancode, tmp.keycode);
+               break;
+       }
+       return kc;
+}
+
+static inline int
+do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+{
+       struct kbsentry *kbs;
+       char *p;
+       u_char *q;
+       u_char __user *up;
+       int sz;
+       int delta;
+       char *first_free, *fj, *fnw;
+       int i, j, k;
+       int ret;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
+       if (!kbs) {
+               ret = -ENOMEM;
+               goto reterr;
+       }
+
+       /* we mostly copy too much here (512bytes), but who cares ;) */
+       if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
+               ret = -EFAULT;
+               goto reterr;
+       }
+       kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
+       i = kbs->kb_func;
+
+       switch (cmd) {
+       case KDGKBSENT:
+               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
+                                                 a struct member */
+               up = user_kdgkb->kb_string;
+               p = func_table[i];
+               if(p)
+                       for ( ; *p && sz; p++, sz--)
+                               if (put_user(*p, up++)) {
+                                       ret = -EFAULT;
+                                       goto reterr;
+                               }
+               if (put_user('\0', up)) {
+                       ret = -EFAULT;
+                       goto reterr;
+               }
+               kfree(kbs);
+               return ((p && *p) ? -EOVERFLOW : 0);
+       case KDSKBSENT:
+               if (!perm) {
+                       ret = -EPERM;
+                       goto reterr;
+               }
+
+               q = func_table[i];
+               first_free = funcbufptr + (funcbufsize - funcbufleft);
+               for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
+                       ;
+               if (j < MAX_NR_FUNC)
+                       fj = func_table[j];
+               else
+                       fj = first_free;
+
+               delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+               if (delta <= funcbufleft) {     /* it fits in current buf */
+                   if (j < MAX_NR_FUNC) {
+                       memmove(fj + delta, fj, first_free - fj);
+                       for (k = j; k < MAX_NR_FUNC; k++)
+                           if (func_table[k])
+                               func_table[k] += delta;
+                   }
+                   if (!q)
+                     func_table[i] = fj;
+                   funcbufleft -= delta;
+               } else {                        /* allocate a larger buffer */
+                   sz = 256;
+                   while (sz < funcbufsize - funcbufleft + delta)
+                     sz <<= 1;
+                   fnw = kmalloc(sz, GFP_KERNEL);
+                   if(!fnw) {
+                     ret = -ENOMEM;
+                     goto reterr;
+                   }
+
+                   if (!q)
+                     func_table[i] = fj;
+                   if (fj > funcbufptr)
+                       memmove(fnw, funcbufptr, fj - funcbufptr);
+                   for (k = 0; k < j; k++)
+                     if (func_table[k])
+                       func_table[k] = fnw + (func_table[k] - funcbufptr);
+
+                   if (first_free > fj) {
+                       memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
+                       for (k = j; k < MAX_NR_FUNC; k++)
+                         if (func_table[k])
+                           func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
+                   }
+                   if (funcbufptr != func_buf)
+                     kfree(funcbufptr);
+                   funcbufptr = fnw;
+                   funcbufleft = funcbufleft - delta + sz - funcbufsize;
+                   funcbufsize = sz;
+               }
+               strcpy(func_table[i], kbs->kb_string);
+               break;
+       }
+       ret = 0;
+reterr:
+       kfree(kbs);
+       return ret;
+}
+
+static inline int 
+do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
+{
+       struct consolefontdesc cfdarg;
+       int i;
+
+       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
+               return -EFAULT;
+       
+       switch (cmd) {
+       case PIO_FONTX:
+               if (!perm)
+                       return -EPERM;
+               op->op = KD_FONT_OP_SET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = cfdarg.chardata;
+               return con_font_op(vc_cons[fg_console].d, op);
+       case GIO_FONTX: {
+               op->op = KD_FONT_OP_GET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = cfdarg.chardata;
+               i = con_font_op(vc_cons[fg_console].d, op);
+               if (i)
+                       return i;
+               cfdarg.charheight = op->height;
+               cfdarg.charcount = op->charcount;
+               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
+                       return -EFAULT;
+               return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static inline int 
+do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
+{
+       struct unimapdesc tmp;
+
+       if (copy_from_user(&tmp, user_ud, sizeof tmp))
+               return -EFAULT;
+       if (tmp.entries)
+               if (!access_ok(VERIFY_WRITE, tmp.entries,
+                               tmp.entry_ct*sizeof(struct unipair)))
+                       return -EFAULT;
+       switch (cmd) {
+       case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
+               return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
+       case GIO_UNIMAP:
+               if (!perm && fg_console != vc->vc_num)
+                       return -EPERM;
+               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+       }
+       return 0;
+}
+
+
+
+/*
+ * We handle the console-specific ioctl's here.  We allow the
+ * capability to modify any console, not just the fg_console. 
+ */
+int vt_ioctl(struct tty_struct *tty, struct file * file,
+            unsigned int cmd, unsigned long arg)
+{
+       struct vc_data *vc = tty->driver_data;
+       struct console_font_op op;      /* used in multiple places here */
+       struct kbd_struct * kbd;
+       unsigned int console;
+       unsigned char ucval;
+       unsigned int uival;
+       void __user *up = (void __user *)arg;
+       int i, perm;
+       int ret = 0;
+
+       console = vc->vc_num;
+
+       tty_lock();
+
+       if (!vc_cons_allocated(console)) {      /* impossible? */
+               ret = -ENOIOCTLCMD;
+               goto out;
+       }
+
+
+       /*
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+       kbd = kbd_table + console;
+       switch (cmd) {
+       case TIOCLINUX:
+               ret = tioclinux(tty, arg);
+               break;
+       case KIOCSOUND:
+               if (!perm)
+                       goto eperm;
+               /*
+                * The use of PIT_TICK_RATE is historic, it used to be
+                * the platform-dependent CLOCK_TICK_RATE between 2.6.12
+                * and 2.6.36, which was a minor but unfortunate ABI
+                * change.
+                */
+               if (arg)
+                       arg = PIT_TICK_RATE / arg;
+               kd_mksound(arg, 0);
+               break;
+
+       case KDMKTONE:
+               if (!perm)
+                       goto eperm;
+       {
+               unsigned int ticks, count;
+               
+               /*
+                * Generate the tone for the appropriate number of ticks.
+                * If the time is zero, turn off sound ourselves.
+                */
+               ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+               count = ticks ? (arg & 0xffff) : 0;
+               if (count)
+                       count = PIT_TICK_RATE / count;
+               kd_mksound(count, ticks);
+               break;
+       }
+
+       case KDGKBTYPE:
+               /*
+                * this is naive.
+                */
+               ucval = KB_101;
+               goto setchar;
+
+               /*
+                * These cannot be implemented on any machine that implements
+                * ioperm() in user level (such as Alpha PCs) or not at all.
+                *
+                * XXX: you should never use these, just call ioperm directly..
+                */
+#ifdef CONFIG_X86
+       case KDADDIO:
+       case KDDELIO:
+               /*
+                * KDADDIO and KDDELIO may be able to add ports beyond what
+                * we reject here, but to be safe...
+                */
+               if (arg < GPFIRST || arg > GPLAST) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+               break;
+
+       case KDENABIO:
+       case KDDISABIO:
+               ret = sys_ioperm(GPFIRST, GPNUM,
+                                 (cmd == KDENABIO)) ? -ENXIO : 0;
+               break;
+#endif
+
+       /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
+               
+       case KDKBDREP:
+       {
+               struct kbd_repeat kbrep;
+               
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+
+               if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
+                       ret =  -EFAULT;
+                       break;
+               }
+               ret = kbd_rate(&kbrep);
+               if (ret)
+                       break;
+               if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case KDSETMODE:
+               /*
+                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
+                * doesn't do a whole lot. i'm not sure if it should do any
+                * restoration of modes or what...
+                *
+                * XXX It should at least call into the driver, fbdev's definitely
+                * need to restore their engine state. --BenH
+                */
+               if (!perm)
+                       goto eperm;
+               switch (arg) {
+               case KD_GRAPHICS:
+                       break;
+               case KD_TEXT0:
+               case KD_TEXT1:
+                       arg = KD_TEXT;
+               case KD_TEXT:
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (vc->vc_mode == (unsigned char) arg)
+                       break;
+               vc->vc_mode = (unsigned char) arg;
+               if (console != fg_console)
+                       break;
+               /*
+                * explicitly blank/unblank the screen if switching modes
+                */
+               acquire_console_sem();
+               if (arg == KD_TEXT)
+                       do_unblank_screen(1);
+               else
+                       do_blank_screen(1);
+               release_console_sem();
+               break;
+
+       case KDGETMODE:
+               uival = vc->vc_mode;
+               goto setint;
+
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+               /*
+                * these work like a combination of mmap and KDENABIO.
+                * this could be easily finished.
+                */
+               ret = -EINVAL;
+               break;
+
+       case KDSKBMODE:
+               if (!perm)
+                       goto eperm;
+               switch(arg) {
+                 case K_RAW:
+                       kbd->kbdmode = VC_RAW;
+                       break;
+                 case K_MEDIUMRAW:
+                       kbd->kbdmode = VC_MEDIUMRAW;
+                       break;
+                 case K_XLATE:
+                       kbd->kbdmode = VC_XLATE;
+                       compute_shiftstate();
+                       break;
+                 case K_UNICODE:
+                       kbd->kbdmode = VC_UNICODE;
+                       compute_shiftstate();
+                       break;
+                 default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               tty_ldisc_flush(tty);
+               break;
+
+       case KDGKBMODE:
+               uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
+                                (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
+                                (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
+                                K_XLATE);
+               goto setint;
+
+       /* this could be folded into KDSKBMODE, but for compatibility
+          reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
+       case KDSKBMETA:
+               switch(arg) {
+                 case K_METABIT:
+                       clr_vc_kbd_mode(kbd, VC_META);
+                       break;
+                 case K_ESCPREFIX:
+                       set_vc_kbd_mode(kbd, VC_META);
+                       break;
+                 default:
+                       ret = -EINVAL;
+               }
+               break;
+
+       case KDGKBMETA:
+               uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
+       setint:
+               ret = put_user(uival, (int __user *)arg);
+               break;
+
+       case KDGETKEYCODE:
+       case KDSETKEYCODE:
+               if(!capable(CAP_SYS_TTY_CONFIG))
+                       perm = 0;
+               ret = do_kbkeycode_ioctl(cmd, up, perm);
+               break;
+
+       case KDGKBENT:
+       case KDSKBENT:
+               ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+               break;
+
+       case KDGKBSENT:
+       case KDSKBSENT:
+               ret = do_kdgkb_ioctl(cmd, up, perm);
+               break;
+
+       case KDGKBDIACR:
+       {
+               struct kbdiacrs __user *a = up;
+               struct kbdiacr diacr;
+               int i;
+
+               if (put_user(accent_table_size, &a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               for (i = 0; i < accent_table_size; i++) {
+                       diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
+                       diacr.base = conv_uni_to_8bit(accent_table[i].base);
+                       diacr.result = conv_uni_to_8bit(accent_table[i].result);
+                       if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+               }
+               break;
+       }
+       case KDGKBDIACRUC:
+       {
+               struct kbdiacrsuc __user *a = up;
+
+               if (put_user(accent_table_size, &a->kb_cnt))
+                       ret = -EFAULT;
+               else if (copy_to_user(a->kbdiacruc, accent_table,
+                               accent_table_size*sizeof(struct kbdiacruc)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case KDSKBDIACR:
+       {
+               struct kbdiacrs __user *a = up;
+               struct kbdiacr diacr;
+               unsigned int ct;
+               int i;
+
+               if (!perm)
+                       goto eperm;
+               if (get_user(ct,&a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (ct >= MAX_DIACR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               accent_table_size = ct;
+               for (i = 0; i < ct; i++) {
+                       if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
+                       accent_table[i].base = conv_8bit_to_uni(diacr.base);
+                       accent_table[i].result = conv_8bit_to_uni(diacr.result);
+               }
+               break;
+       }
+
+       case KDSKBDIACRUC:
+       {
+               struct kbdiacrsuc __user *a = up;
+               unsigned int ct;
+
+               if (!perm)
+                       goto eperm;
+               if (get_user(ct,&a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (ct >= MAX_DIACR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               accent_table_size = ct;
+               if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       /* the ioctls below read/set the flags usually shown in the leds */
+       /* don't use them - they will go away without warning */
+       case KDGKBLED:
+               ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
+               goto setchar;
+
+       case KDSKBLED:
+               if (!perm)
+                       goto eperm;
+               if (arg & ~0x77) {
+                       ret = -EINVAL;
+                       break;
+               }
+               kbd->ledflagstate = (arg & 7);
+               kbd->default_ledflagstate = ((arg >> 4) & 7);
+               set_leds();
+               break;
+
+       /* the ioctls below only set the lights, not the functions */
+       /* for those, see KDGKBLED and KDSKBLED above */
+       case KDGETLED:
+               ucval = getledstate();
+       setchar:
+               ret = put_user(ucval, (char __user *)arg);
+               break;
+
+       case KDSETLED:
+               if (!perm)
+                       goto eperm;
+               setledstate(kbd, arg);
+               break;
+
+       /*
+        * A process can indicate its willingness to accept signals
+        * generated by pressing an appropriate key combination.
+        * Thus, one can have a daemon that e.g. spawns a new console
+        * upon a keypress and then changes to it.
+        * See also the kbrequest field of inittab(5).
+        */
+       case KDSIGACCEPT:
+       {
+               if (!perm || !capable(CAP_KILL))
+                       goto eperm;
+               if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
+                       ret = -EINVAL;
+               else {
+                       spin_lock_irq(&vt_spawn_con.lock);
+                       put_pid(vt_spawn_con.pid);
+                       vt_spawn_con.pid = get_pid(task_pid(current));
+                       vt_spawn_con.sig = arg;
+                       spin_unlock_irq(&vt_spawn_con.lock);
+               }
+               break;
+       }
+
+       case VT_SETMODE:
+       {
+               struct vt_mode tmp;
+
+               if (!perm)
+                       goto eperm;
+               if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               acquire_console_sem();
+               vc->vt_mode = tmp;
+               /* the frsig is ignored, so we set it to 0 */
+               vc->vt_mode.frsig = 0;
+               put_pid(vc->vt_pid);
+               vc->vt_pid = get_pid(task_pid(current));
+               /* no switch is required -- saw@shade.msu.ru */
+               vc->vt_newvt = -1;
+               release_console_sem();
+               break;
+       }
+
+       case VT_GETMODE:
+       {
+               struct vt_mode tmp;
+               int rc;
+
+               acquire_console_sem();
+               memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
+               release_console_sem();
+
+               rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
+               if (rc)
+                       ret = -EFAULT;
+               break;
+       }
+
+       /*
+        * Returns global vt state. Note that VT 0 is always open, since
+        * it's an alias for the current VT, and people can't use it here.
+        * We cannot return state for more than 16 VTs, since v_state is short.
+        */
+       case VT_GETSTATE:
+       {
+               struct vt_stat __user *vtstat = up;
+               unsigned short state, mask;
+
+               if (put_user(fg_console + 1, &vtstat->v_active))
+                       ret = -EFAULT;
+               else {
+                       state = 1;      /* /dev/tty0 is always open */
+                       for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+                                                       ++i, mask <<= 1)
+                               if (VT_IS_IN_USE(i))
+                                       state |= mask;
+                       ret = put_user(state, &vtstat->v_state);
+               }
+               break;
+       }
+
+       /*
+        * Returns the first available (non-opened) console.
+        */
+       case VT_OPENQRY:
+               for (i = 0; i < MAX_NR_CONSOLES; ++i)
+                       if (! VT_IS_IN_USE(i))
+                               break;
+               uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
+               goto setint;             
+
+       /*
+        * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
+        * with num >= 1 (switches to vt 0, our console, are not allowed, just
+        * to preserve sanity).
+        */
+       case VT_ACTIVATE:
+               if (!perm)
+                       goto eperm;
+               if (arg == 0 || arg > MAX_NR_CONSOLES)
+                       ret =  -ENXIO;
+               else {
+                       arg--;
+                       acquire_console_sem();
+                       ret = vc_allocate(arg);
+                       release_console_sem();
+                       if (ret)
+                               break;
+                       set_console(arg);
+               }
+               break;
+
+       case VT_SETACTIVATE:
+       {
+               struct vt_setactivate vsa;
+
+               if (!perm)
+                       goto eperm;
+
+               if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
+                                       sizeof(struct vt_setactivate))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
+                       ret = -ENXIO;
+               else {
+                       vsa.console--;
+                       acquire_console_sem();
+                       ret = vc_allocate(vsa.console);
+                       if (ret == 0) {
+                               struct vc_data *nvc;
+                               /* This is safe providing we don't drop the
+                                  console sem between vc_allocate and
+                                  finishing referencing nvc */
+                               nvc = vc_cons[vsa.console].d;
+                               nvc->vt_mode = vsa.mode;
+                               nvc->vt_mode.frsig = 0;
+                               put_pid(nvc->vt_pid);
+                               nvc->vt_pid = get_pid(task_pid(current));
+                       }
+                       release_console_sem();
+                       if (ret)
+                               break;
+                       /* Commence switch and lock */
+                       set_console(arg);
+               }
+       }
+
+       /*
+        * wait until the specified VT has been activated
+        */
+       case VT_WAITACTIVE:
+               if (!perm)
+                       goto eperm;
+               if (arg == 0 || arg > MAX_NR_CONSOLES)
+                       ret = -ENXIO;
+               else
+                       ret = vt_waitactive(arg);
+               break;
+
+       /*
+        * If a vt is under process control, the kernel will not switch to it
+        * immediately, but postpone the operation until the process calls this
+        * ioctl, allowing the switch to complete.
+        *
+        * According to the X sources this is the behavior:
+        *      0:      pending switch-from not OK
+        *      1:      pending switch-from OK
+        *      2:      completed switch-to OK
+        */
+       case VT_RELDISP:
+               if (!perm)
+                       goto eperm;
+
+               if (vc->vt_mode.mode != VT_PROCESS) {
+                       ret = -EINVAL;
+                       break;
+               }
+               /*
+                * Switching-from response
+                */
+               acquire_console_sem();
+               if (vc->vt_newvt >= 0) {
+                       if (arg == 0)
+                               /*
+                                * Switch disallowed, so forget we were trying
+                                * to do it.
+                                */
+                               vc->vt_newvt = -1;
+
+                       else {
+                               /*
+                                * The current vt has been released, so
+                                * complete the switch.
+                                */
+                               int newvt;
+                               newvt = vc->vt_newvt;
+                               vc->vt_newvt = -1;
+                               ret = vc_allocate(newvt);
+                               if (ret) {
+                                       release_console_sem();
+                                       break;
+                               }
+                               /*
+                                * When we actually do the console switch,
+                                * make sure we are atomic with respect to
+                                * other console switches..
+                                */
+                               complete_change_console(vc_cons[newvt].d);
+                       }
+               } else {
+                       /*
+                        * Switched-to response
+                        */
+                       /*
+                        * If it's just an ACK, ignore it
+                        */
+                       if (arg != VT_ACKACQ)
+                               ret = -EINVAL;
+               }
+               release_console_sem();
+               break;
+
+        /*
+         * Disallocate memory associated to VT (but leave VT1)
+         */
+        case VT_DISALLOCATE:
+               if (arg > MAX_NR_CONSOLES) {
+                       ret = -ENXIO;
+                       break;
+               }
+               if (arg == 0) {
+                   /* deallocate all unused consoles, but leave 0 */
+                       acquire_console_sem();
+                       for (i=1; i<MAX_NR_CONSOLES; i++)
+                               if (! VT_BUSY(i))
+                                       vc_deallocate(i);
+                       release_console_sem();
+               } else {
+                       /* deallocate a single console, if possible */
+                       arg--;
+                       if (VT_BUSY(arg))
+                               ret = -EBUSY;
+                       else if (arg) {                       /* leave 0 */
+                               acquire_console_sem();
+                               vc_deallocate(arg);
+                               release_console_sem();
+                       }
+               }
+               break;
+
+       case VT_RESIZE:
+       {
+               struct vt_sizes __user *vtsizes = up;
+               struct vc_data *vc;
+
+               ushort ll,cc;
+               if (!perm)
+                       goto eperm;
+               if (get_user(ll, &vtsizes->v_rows) ||
+                   get_user(cc, &vtsizes->v_cols))
+                       ret = -EFAULT;
+               else {
+                       acquire_console_sem();
+                       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                               vc = vc_cons[i].d;
+
+                               if (vc) {
+                                       vc->vc_resize_user = 1;
+                                       vc_resize(vc_cons[i].d, cc, ll);
+                               }
+                       }
+                       release_console_sem();
+               }
+               break;
+       }
+
+       case VT_RESIZEX:
+       {
+               struct vt_consize __user *vtconsize = up;
+               ushort ll,cc,vlin,clin,vcol,ccol;
+               if (!perm)
+                       goto eperm;
+               if (!access_ok(VERIFY_READ, vtconsize,
+                               sizeof(struct vt_consize))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               /* FIXME: Should check the copies properly */
+               __get_user(ll, &vtconsize->v_rows);
+               __get_user(cc, &vtconsize->v_cols);
+               __get_user(vlin, &vtconsize->v_vlin);
+               __get_user(clin, &vtconsize->v_clin);
+               __get_user(vcol, &vtconsize->v_vcol);
+               __get_user(ccol, &vtconsize->v_ccol);
+               vlin = vlin ? vlin : vc->vc_scan_lines;
+               if (clin) {
+                       if (ll) {
+                               if (ll != vlin/clin) {
+                                       /* Parameters don't add up */
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       } else 
+                               ll = vlin/clin;
+               }
+               if (vcol && ccol) {
+                       if (cc) {
+                               if (cc != vcol/ccol) {
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       } else
+                               cc = vcol/ccol;
+               }
+
+               if (clin > 32) {
+                       ret =  -EINVAL;
+                       break;
+               }
+                   
+               for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                       if (!vc_cons[i].d)
+                               continue;
+                       acquire_console_sem();
+                       if (vlin)
+                               vc_cons[i].d->vc_scan_lines = vlin;
+                       if (clin)
+                               vc_cons[i].d->vc_font.height = clin;
+                       vc_cons[i].d->vc_resize_user = 1;
+                       vc_resize(vc_cons[i].d, cc, ll);
+                       release_console_sem();
+               }
+               break;
+       }
+
+       case PIO_FONT: {
+               if (!perm)
+                       goto eperm;
+               op.op = KD_FONT_OP_SET;
+               op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
+               op.width = 8;
+               op.height = 0;
+               op.charcount = 256;
+               op.data = up;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               break;
+       }
+
+       case GIO_FONT: {
+               op.op = KD_FONT_OP_GET;
+               op.flags = KD_FONT_FLAG_OLD;
+               op.width = 8;
+               op.height = 32;
+               op.charcount = 256;
+               op.data = up;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               break;
+       }
+
+       case PIO_CMAP:
+                if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_cmap(up);
+               break;
+
+       case GIO_CMAP:
+                ret = con_get_cmap(up);
+               break;
+
+       case PIO_FONTX:
+       case GIO_FONTX:
+               ret = do_fontx_ioctl(cmd, up, perm, &op);
+               break;
+
+       case PIO_FONTRESET:
+       {
+               if (!perm)
+                       goto eperm;
+
+#ifdef BROKEN_GRAPHICS_PROGRAMS
+               /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
+                  font is not saved. */
+               ret = -ENOSYS;
+               break;
+#else
+               {
+               op.op = KD_FONT_OP_SET_DEFAULT;
+               op.data = NULL;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               if (ret)
+                       break;
+               con_set_default_unimap(vc_cons[fg_console].d);
+               break;
+               }
+#endif
+       }
+
+       case KDFONTOP: {
+               if (copy_from_user(&op, up, sizeof(op))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (!perm && op.op != KD_FONT_OP_GET)
+                       goto eperm;
+               ret = con_font_op(vc, &op);
+               if (ret)
+                       break;
+               if (copy_to_user(up, &op, sizeof(op)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case PIO_SCRNMAP:
+               if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_trans_old(up);
+               break;
+
+       case GIO_SCRNMAP:
+               ret = con_get_trans_old(up);
+               break;
+
+       case PIO_UNISCRNMAP:
+               if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_trans_new(up);
+               break;
+
+       case GIO_UNISCRNMAP:
+               ret = con_get_trans_new(up);
+               break;
+
+       case PIO_UNIMAPCLR:
+             { struct unimapinit ui;
+               if (!perm)
+                       goto eperm;
+               ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
+               if (ret)
+                       ret = -EFAULT;
+               else
+                       con_clear_unimap(vc, &ui);
+               break;
+             }
+
+       case PIO_UNIMAP:
+       case GIO_UNIMAP:
+               ret = do_unimap_ioctl(cmd, up, perm, vc);
+               break;
+
+       case VT_LOCKSWITCH:
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+               vt_dont_switch = 1;
+               break;
+       case VT_UNLOCKSWITCH:
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+               vt_dont_switch = 0;
+               break;
+       case VT_GETHIFONTMASK:
+               ret = put_user(vc->vc_hi_font_mask,
+                                       (unsigned short __user *)arg);
+               break;
+       case VT_WAITEVENT:
+               ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+       }
+out:
+       tty_unlock();
+       return ret;
+eperm:
+       ret = -EPERM;
+       goto out;
+}
+
+void reset_vc(struct vc_data *vc)
+{
+       vc->vc_mode = KD_TEXT;
+       kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+       vc->vt_mode.mode = VT_AUTO;
+       vc->vt_mode.waitv = 0;
+       vc->vt_mode.relsig = 0;
+       vc->vt_mode.acqsig = 0;
+       vc->vt_mode.frsig = 0;
+       put_pid(vc->vt_pid);
+       vc->vt_pid = NULL;
+       vc->vt_newvt = -1;
+       if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
+               reset_palette(vc);
+}
+
+void vc_SAK(struct work_struct *work)
+{
+       struct vc *vc_con =
+               container_of(work, struct vc, SAK_work);
+       struct vc_data *vc;
+       struct tty_struct *tty;
+
+       acquire_console_sem();
+       vc = vc_con->d;
+       if (vc) {
+               tty = vc->port.tty;
+               /*
+                * SAK should also work in all raw modes and reset
+                * them properly.
+                */
+               if (tty)
+                       __do_SAK(tty);
+               reset_vc(vc);
+       }
+       release_console_sem();
+}
+
+#ifdef CONFIG_COMPAT
+
+struct compat_consolefontdesc {
+       unsigned short charcount;       /* characters in font (256 or 512) */
+       unsigned short charheight;      /* scan lines per character (1-32) */
+       compat_caddr_t chardata;        /* font data in expanded form */
+};
+
+static inline int
+compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
+                        int perm, struct console_font_op *op)
+{
+       struct compat_consolefontdesc cfdarg;
+       int i;
+
+       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case PIO_FONTX:
+               if (!perm)
+                       return -EPERM;
+               op->op = KD_FONT_OP_SET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = compat_ptr(cfdarg.chardata);
+               return con_font_op(vc_cons[fg_console].d, op);
+       case GIO_FONTX:
+               op->op = KD_FONT_OP_GET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = compat_ptr(cfdarg.chardata);
+               i = con_font_op(vc_cons[fg_console].d, op);
+               if (i)
+                       return i;
+               cfdarg.charheight = op->height;
+               cfdarg.charcount = op->charcount;
+               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
+                       return -EFAULT;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+struct compat_console_font_op {
+       compat_uint_t op;        /* operation code KD_FONT_OP_* */
+       compat_uint_t flags;     /* KD_FONT_FLAG_* */
+       compat_uint_t width, height;     /* font size */
+       compat_uint_t charcount;
+       compat_caddr_t data;    /* font data with height fixed to 32 */
+};
+
+static inline int
+compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
+                        int perm, struct console_font_op *op, struct vc_data *vc)
+{
+       int i;
+
+       if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
+               return -EFAULT;
+       if (!perm && op->op != KD_FONT_OP_GET)
+               return -EPERM;
+       op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
+       op->flags |= KD_FONT_FLAG_OLD;
+       i = con_font_op(vc, op);
+       if (i)
+               return i;
+       ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
+       if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
+               return -EFAULT;
+       return 0;
+}
+
+struct compat_unimapdesc {
+       unsigned short entry_ct;
+       compat_caddr_t entries;
+};
+
+static inline int
+compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
+                        int perm, struct vc_data *vc)
+{
+       struct compat_unimapdesc tmp;
+       struct unipair __user *tmp_entries;
+
+       if (copy_from_user(&tmp, user_ud, sizeof tmp))
+               return -EFAULT;
+       tmp_entries = compat_ptr(tmp.entries);
+       if (tmp_entries)
+               if (!access_ok(VERIFY_WRITE, tmp_entries,
+                               tmp.entry_ct*sizeof(struct unipair)))
+                       return -EFAULT;
+       switch (cmd) {
+       case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
+               return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
+       case GIO_UNIMAP:
+               if (!perm && fg_console != vc->vc_num)
+                       return -EPERM;
+               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
+       }
+       return 0;
+}
+
+long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+            unsigned int cmd, unsigned long arg)
+{
+       struct vc_data *vc = tty->driver_data;
+       struct console_font_op op;      /* used in multiple places here */
+       struct kbd_struct *kbd;
+       unsigned int console;
+       void __user *up = (void __user *)arg;
+       int perm;
+       int ret = 0;
+
+       console = vc->vc_num;
+
+       tty_lock();
+
+       if (!vc_cons_allocated(console)) {      /* impossible? */
+               ret = -ENOIOCTLCMD;
+               goto out;
+       }
+
+       /*
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+
+       kbd = kbd_table + console;
+       switch (cmd) {
+       /*
+        * these need special handlers for incompatible data structures
+        */
+       case PIO_FONTX:
+       case GIO_FONTX:
+               ret = compat_fontx_ioctl(cmd, up, perm, &op);
+               break;
+
+       case KDFONTOP:
+               ret = compat_kdfontop_ioctl(up, perm, &op, vc);
+               break;
+
+       case PIO_UNIMAP:
+       case GIO_UNIMAP:
+               ret = compat_unimap_ioctl(cmd, up, perm, vc);
+               break;
+
+       /*
+        * all these treat 'arg' as an integer
+        */
+       case KIOCSOUND:
+       case KDMKTONE:
+#ifdef CONFIG_X86
+       case KDADDIO:
+       case KDDELIO:
+#endif
+       case KDSETMODE:
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+       case KDSKBMODE:
+       case KDSKBMETA:
+       case KDSKBLED:
+       case KDSETLED:
+       case KDSIGACCEPT:
+       case VT_ACTIVATE:
+       case VT_WAITACTIVE:
+       case VT_RELDISP:
+       case VT_DISALLOCATE:
+       case VT_RESIZE:
+       case VT_RESIZEX:
+               goto fallback;
+
+       /*
+        * the rest has a compatible data structure behind arg,
+        * but we have to convert it to a proper 64 bit pointer.
+        */
+       default:
+               arg = (unsigned long)compat_ptr(arg);
+               goto fallback;
+       }
+out:
+       tty_unlock();
+       return ret;
+
+fallback:
+       tty_unlock();
+       return vt_ioctl(tty, file, cmd, arg);
+}
+
+
+#endif /* CONFIG_COMPAT */
+
+
+/*
+ * Performs the back end of a vt switch. Called under the console
+ * semaphore.
+ */
+static void complete_change_console(struct vc_data *vc)
+{
+       unsigned char old_vc_mode;
+       int old = fg_console;
+
+       last_console = fg_console;
+
+       /*
+        * If we're switching, we could be going from KD_GRAPHICS to
+        * KD_TEXT mode or vice versa, which means we need to blank or
+        * unblank the screen later.
+        */
+       old_vc_mode = vc_cons[fg_console].d->vc_mode;
+       switch_screen(vc);
+
+       /*
+        * This can't appear below a successful kill_pid().  If it did,
+        * then the *blank_screen operation could occur while X, having
+        * received acqsig, is waking up on another processor.  This
+        * condition can lead to overlapping accesses to the VGA range
+        * and the framebuffer (causing system lockups).
+        *
+        * To account for this we duplicate this code below only if the
+        * controlling process is gone and we've called reset_vc.
+        */
+       if (old_vc_mode != vc->vc_mode) {
+               if (vc->vc_mode == KD_TEXT)
+                       do_unblank_screen(1);
+               else
+                       do_blank_screen(1);
+       }
+
+       /*
+        * If this new console is under process control, send it a signal
+        * telling it that it has acquired. Also check if it has died and
+        * clean up (similar to logic employed in change_console())
+        */
+       if (vc->vt_mode.mode == VT_PROCESS) {
+               /*
+                * Send the signal as privileged - kill_pid() will
+                * tell us if the process has gone or something else
+                * is awry
+                */
+               if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
+               /*
+                * The controlling process has died, so we revert back to
+                * normal operation. In this case, we'll also change back
+                * to KD_TEXT mode. I'm not sure if this is strictly correct
+                * but it saves the agony when the X server dies and the screen
+                * remains blanked due to KD_GRAPHICS! It would be nice to do
+                * this outside of VT_PROCESS but there is no single process
+                * to account for and tracking tty count may be undesirable.
+                */
+                       reset_vc(vc);
+
+                       if (old_vc_mode != vc->vc_mode) {
+                               if (vc->vc_mode == KD_TEXT)
+                                       do_unblank_screen(1);
+                               else
+                                       do_blank_screen(1);
+                       }
+               }
+       }
+
+       /*
+        * Wake anyone waiting for their VT to activate
+        */
+       vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
+       return;
+}
+
+/*
+ * Performs the front-end of a vt switch
+ */
+void change_console(struct vc_data *new_vc)
+{
+       struct vc_data *vc;
+
+       if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
+               return;
+
+       /*
+        * If this vt is in process mode, then we need to handshake with
+        * that process before switching. Essentially, we store where that
+        * vt wants to switch to and wait for it to tell us when it's done
+        * (via VT_RELDISP ioctl).
+        *
+        * We also check to see if the controlling process still exists.
+        * If it doesn't, we reset this vt to auto mode and continue.
+        * This is a cheap way to track process control. The worst thing
+        * that can happen is: we send a signal to a process, it dies, and
+        * the switch gets "lost" waiting for a response; hopefully, the
+        * user will try again, we'll detect the process is gone (unless
+        * the user waits just the right amount of time :-) and revert the
+        * vt to auto control.
+        */
+       vc = vc_cons[fg_console].d;
+       if (vc->vt_mode.mode == VT_PROCESS) {
+               /*
+                * Send the signal as privileged - kill_pid() will
+                * tell us if the process has gone or something else
+                * is awry.
+                *
+                * We need to set vt_newvt *before* sending the signal or we
+                * have a race.
+                */
+               vc->vt_newvt = new_vc->vc_num;
+               if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
+                       /*
+                        * It worked. Mark the vt to switch to and
+                        * return. The process needs to send us a
+                        * VT_RELDISP ioctl to complete the switch.
+                        */
+                       return;
+               }
+
+               /*
+                * The controlling process has died, so we revert back to
+                * normal operation. In this case, we'll also change back
+                * to KD_TEXT mode. I'm not sure if this is strictly correct
+                * but it saves the agony when the X server dies and the screen
+                * remains blanked due to KD_GRAPHICS! It would be nice to do
+                * this outside of VT_PROCESS but there is no single process
+                * to account for and tracking tty count may be undesirable.
+                */
+               reset_vc(vc);
+
+               /*
+                * Fall through to normal (VT_AUTO) handling of the switch...
+                */
+       }
+
+       /*
+        * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
+        */
+       if (vc->vc_mode == KD_GRAPHICS)
+               return;
+
+       complete_change_console(new_vc);
+}
+
+/* Perform a kernel triggered VT switch for suspend/resume */
+
+static int disable_vt_switch;
+
+int vt_move_to_console(unsigned int vt, int alloc)
+{
+       int prev;
+
+       acquire_console_sem();
+       /* Graphics mode - up to X */
+       if (disable_vt_switch) {
+               release_console_sem();
+               return 0;
+       }
+       prev = fg_console;
+
+       if (alloc && vc_allocate(vt)) {
+               /* we can't have a free VC for now. Too bad,
+                * we don't want to mess the screen for now. */
+               release_console_sem();
+               return -ENOSPC;
+       }
+
+       if (set_console(vt)) {
+               /*
+                * We're unable to switch to the SUSPEND_CONSOLE.
+                * Let the calling function know so it can decide
+                * what to do.
+                */
+               release_console_sem();
+               return -EIO;
+       }
+       release_console_sem();
+       tty_lock();
+       if (vt_waitactive(vt + 1)) {
+               pr_debug("Suspend: Can't switch VCs.");
+               tty_unlock();
+               return -EINTR;
+       }
+       tty_unlock();
+       return prev;
+}
+
+/*
+ * Normally during a suspend, we allocate a new console and switch to it.
+ * When we resume, we switch back to the original console.  This switch
+ * can be slow, so on systems where the framebuffer can handle restoration
+ * of video registers anyways, there's little point in doing the console
+ * switch.  This function allows you to disable it by passing it '0'.
+ */
+void pm_set_vt_switch(int do_switch)
+{
+       acquire_console_sem();
+       disable_vt_switch = !do_switch;
+       release_console_sem();
+}
+EXPORT_SYMBOL(pm_set_vt_switch);
index ea071a5b6eee6aa929827851966dec80dfe070a0..44447f54942f6d6e1c7c7e2a777b4c882f6b546d 100644 (file)
@@ -2301,7 +2301,7 @@ out:
        return ret;
 }
 
-static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);
+static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot);
 
 static ssize_t read_human_status(struct device *dev,
                        struct device_attribute *attr, char *buf)
@@ -2364,8 +2364,7 @@ out:
        return ret;
 }
 
-static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO,
-                               read_human_status, NULL);
+static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL);
 
 static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
                char *buf)
@@ -2397,7 +2396,7 @@ out:
        return ret;
 }
 
-static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);
+static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL);
 
 #define UEA_ATTR(name, reset)                                  \
                                                                \
index ddb4dc980923e443e9cc2f3e0da30855ca59ff5b..a3d2e2399655b84a348561e8aa27521212f21831 100644 (file)
@@ -54,7 +54,6 @@
 #include <linux/gfp.h>
 #include <linux/poll.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usb/hcd.h>
 #include <linux/mutex.h>
index f1aaff6202a58bb386a2947d0df2047322c8c43f..a7131ad630f9ad54535205017352ee10175df384 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/module.h>
@@ -965,10 +964,11 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
 
 static int proc_connectinfo(struct dev_state *ps, void __user *arg)
 {
-       struct usbdevfs_connectinfo ci;
+       struct usbdevfs_connectinfo ci = {
+               .devnum = ps->dev->devnum,
+               .slow = ps->dev->speed == USB_SPEED_LOW
+       };
 
-       ci.devnum = ps->dev->devnum;
-       ci.slow = ps->dev->speed == USB_SPEED_LOW;
        if (copy_to_user(arg, &ci, sizeof(ci)))
                return -EFAULT;
        return 0;
index 9fe34fb78ef11c4d0dd88065502c6e92cd4398f3..cf6a5423de0997b424fe06c051acd1e7d305519f 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/errno.h>
 #include <linux/rwsem.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 
 #include "usb.h"
index 9819a4cc3b264d48111a08a8d51e242b0b1329d8..b690aa35df9a35117394c4177213e3f5ad286162 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/parser.h>
 #include <linux/notifier.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/usb/hcd.h>
 #include <asm/byteorder.h>
 #include "usb.h"
index b739ca8146511dc96f38d067f139ad79b23e2348..607d0db4a988aa590833209faa37db881cadc728 100644 (file)
@@ -158,7 +158,7 @@ config USB_GADGET_FSL_USB2
        boolean "Freescale Highspeed USB DR Peripheral Controller"
        depends on FSL_SOC || ARCH_MXC
        select USB_GADGET_DUALSPEED
-       select USB_FSL_MPH_DR_OF
+       select USB_FSL_MPH_DR_OF if OF
        help
           Some of Freescale PowerPC processors have a High Speed
           Dual-Role(DR) USB controller, which supports device mode.
index b5e20e873cbad09bbebb7134929cf97880532bea..717ff653fa2330a9e5b78774b1a084f80186faf0 100644 (file)
@@ -2017,7 +2017,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
                        }
                } else {
                        /* gpio_request fail so use -EINVAL for gpio_is_valid */
-                       ubc->vbus_pin = -EINVAL;
+                       udc->vbus_pin = -EINVAL;
                }
        }
 
index 4a830df4fc31a1a58692f6b1b5adc29a7a9895c4..484c5ba5450ebfc254613ca04cd9c8ac9227aaf6 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/blkdev.h>
 #include <linux/pagemap.h>
 #include <asm/unaligned.h>
-#include <linux/smp_lock.h>
 
 #include <linux/usb/composite.h>
 #include <linux/usb/functionfs.h>
index 4f891eddd06041886b664d54f7488d9b00fcf781..598e7e2ab80c666f1395f1db6c30aaa44f34d646 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/cdev.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
 #include <linux/usb/g_hid.h>
index 566cb23190565288ec500fc3c525944801982910..e7e0c69d3b1f4671f1c7b81ca500080bf50672d8 100644 (file)
@@ -251,7 +251,8 @@ struct goku_udc {
                                        got_region:1,
                                        req_config:1,
                                        configured:1,
-                                       enabled:1;
+                                       enabled:1,
+                                       registered:1;
 
        /* pci state used to access those endpoints */
        struct pci_dev                  *pdev;
index cb23355f52d3d8b5335dbdf1e5b07a32c77b281a..fbe86ca95802b93d68ace2718280a4aeb8b533c2 100644 (file)
@@ -811,7 +811,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               netif_stop_queue(net);
                the_dev = dev;
        }
 
index 01e5354a4c20ffd5b072fdff6a828d08e9049317..40f7716b31fcc78244c6db8f36569ddd0cd824cc 100644 (file)
@@ -105,11 +105,15 @@ struct gs_port {
        wait_queue_head_t       close_wait;     /* wait for last close */
 
        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 */
 
@@ -363,6 +367,9 @@ __acquires(&port->port_lock)
                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) {
@@ -397,6 +404,8 @@ __acquires(&port->port_lock)
                        break;
                }
 
+               port->write_started++;
+
                /* abort immediately after disconnect */
                if (!port->port_usb)
                        break;
@@ -418,7 +427,6 @@ __acquires(&port->port_lock)
 {
        struct list_head        *pool = &port->read_pool;
        struct usb_ep           *out = port->port_usb->out;
-       unsigned                started = 0;
 
        while (!list_empty(pool)) {
                struct usb_request      *req;
@@ -430,6 +438,9 @@ __acquires(&port->port_lock)
                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;
@@ -447,13 +458,13 @@ __acquires(&port->port_lock)
                        list_add(&req->list, pool);
                        break;
                }
-               started++;
+               port->read_started++;
 
                /* abort immediately after disconnect */
                if (!port->port_usb)
                        break;
        }
-       return started;
+       return port->read_started;
 }
 
 /*
@@ -535,6 +546,7 @@ static void gs_rx_push(unsigned long _port)
                }
 recycle:
                list_move(&req->list, &port->read_pool);
+               port->read_started--;
        }
 
        /* Push from tty to ldisc; without low_latency set this is handled by
@@ -587,6 +599,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
 
        spin_lock(&port->port_lock);
        list_add(&req->list, &port->write_pool);
+       port->write_started--;
 
        switch (req->status) {
        default:
@@ -608,7 +621,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
        spin_unlock(&port->port_lock);
 }
 
-static void gs_free_requests(struct usb_ep *ep, struct list_head *head)
+static void gs_free_requests(struct usb_ep *ep, struct list_head *head,
+                                                        int *allocated)
 {
        struct usb_request      *req;
 
@@ -616,25 +630,31 @@ static void gs_free_requests(struct usb_ep *ep, struct list_head *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 *))
+               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 < QUEUE_SIZE; i++) {
+       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;
 }
@@ -661,14 +681,15 @@ static int gs_start_io(struct gs_port *port)
         * 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);
+       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);
+                       gs_write_complete, &port->write_allocated);
        if (status) {
-               gs_free_requests(ep, head);
+               gs_free_requests(ep, head, &port->read_allocated);
                return status;
        }
 
@@ -680,8 +701,9 @@ static int gs_start_io(struct gs_port *port)
        if (started) {
                tty_wakeup(port->port_tty);
        } else {
-               gs_free_requests(ep, head);
-               gs_free_requests(port->port_usb->in, &port->write_pool);
+               gs_free_requests(ep, head, &port->read_allocated);
+               gs_free_requests(port->port_usb->in, &port->write_pool,
+                       &port->write_allocated);
                status = -EIO;
        }
 
@@ -1315,8 +1337,12 @@ void gserial_disconnect(struct gserial *gser)
        spin_lock_irqsave(&port->port_lock, flags);
        if (port->open_count == 0 && !port->openclose)
                gs_buf_free(&port->port_write_buf);
-       gs_free_requests(gser->out, &port->read_pool);
-       gs_free_requests(gser->out, &port->read_queue);
-       gs_free_requests(gser->in, &port->write_pool);
+       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);
 }
index 2391c396ca32911611f22627b513ab2116ce06fe..6f4f8e6a40c7e2d1fe034ce3ddb056696fc0be00 100644 (file)
@@ -122,7 +122,7 @@ config USB_EHCI_FSL
        bool "Support for Freescale on-chip EHCI USB controller"
        depends on USB_EHCI_HCD && FSL_SOC
        select USB_EHCI_ROOT_HUB_TT
-       select USB_FSL_MPH_DR_OF
+       select USB_FSL_MPH_DR_OF if OF
        ---help---
          Variation of ARC USB block used in some Freescale chips.
 
index 86afdc73322f21787bf0d1e003acbe563f8f316e..6e2599661b5bdcad9323185bd992dbdb7df45b21 100644 (file)
@@ -1067,7 +1067,7 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
                                                    &debug_registers_fops))
                goto file_error;
 
-       if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
+       if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
                                                    &debug_lpm_fops))
                goto file_error;
 
index 502a7e6fef42a5a5c9ddbfa0ca26b4b971b043e1..e9062806d4a24898286240f139a2f28dadd8522c 100644 (file)
@@ -1063,10 +1063,11 @@ rescan:
                                tmp && tmp != qh;
                                tmp = tmp->qh_next.qh)
                        continue;
-               /* periodic qh self-unlinks on empty */
-               if (!tmp)
-                       goto nogood;
-               unlink_async (ehci, qh);
+               /* periodic qh self-unlinks on empty, and a COMPLETING qh
+                * may already be unlinked.
+                */
+               if (tmp)
+                       unlink_async(ehci, qh);
                /* FALL THROUGH */
        case QH_STATE_UNLINK:           /* wait for hw to finish? */
        case QH_STATE_UNLINK_WAIT:
@@ -1083,7 +1084,6 @@ idle_timeout:
                }
                /* else FALL THROUGH */
        default:
-nogood:
                /* caller was supposed to have unlinked any requests;
                 * that's not our job.  just leak this memory.
                 */
index d36e4e75e08d4e476249a71259d8d760d5158a7b..12f70c302b0b73089451e8e93dbeb66f3c068723 100644 (file)
@@ -141,6 +141,10 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
                qh_put (ehci->async);
        ehci->async = NULL;
 
+       if (ehci->dummy)
+               qh_put(ehci->dummy);
+       ehci->dummy = NULL;
+
        /* DMA consistent memory and pools */
        if (ehci->qtd_pool)
                dma_pool_destroy (ehci->qtd_pool);
@@ -227,8 +231,26 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
        if (ehci->periodic == NULL) {
                goto fail;
        }
-       for (i = 0; i < ehci->periodic_size; i++)
-               ehci->periodic [i] = EHCI_LIST_END(ehci);
+
+       if (ehci->use_dummy_qh) {
+               struct ehci_qh_hw       *hw;
+               ehci->dummy = ehci_qh_alloc(ehci, flags);
+               if (!ehci->dummy)
+                       goto fail;
+
+               hw = ehci->dummy->hw;
+               hw->hw_next = EHCI_LIST_END(ehci);
+               hw->hw_qtd_next = EHCI_LIST_END(ehci);
+               hw->hw_alt_next = EHCI_LIST_END(ehci);
+               hw->hw_token &= ~QTD_STS_ACTIVE;
+               ehci->dummy->hw = hw;
+
+               for (i = 0; i < ehci->periodic_size; i++)
+                       ehci->periodic[i] = ehci->dummy->qh_dma;
+       } else {
+               for (i = 0; i < ehci->periodic_size; i++)
+                       ehci->periodic[i] = EHCI_LIST_END(ehci);
+       }
 
        /* software shadow of hardware table */
        ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
index ac9c4d7c44af227ff974b6f5af7636013583bcbc..bce85055019a190d3d835fd0386d8a8cd7f4e746 100644 (file)
@@ -36,6 +36,8 @@ struct ehci_mxc_priv {
 static int ehci_mxc_setup(struct usb_hcd *hcd)
 {
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct device *dev = hcd->self.controller;
+       struct mxc_usbh_platform_data *pdata = dev_get_platdata(dev);
        int retval;
 
        /* EHCI registers start at offset 0x100 */
@@ -63,6 +65,12 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
 
        ehci_reset(ehci);
 
+       /* set up the PORTSCx register */
+       ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
+
+       /* is this really needed? */
+       msleep(10);
+
        ehci_port_power(ehci, 0);
        return 0;
 }
@@ -114,7 +122,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
        struct usb_hcd *hcd;
        struct resource *res;
-       int irq, ret, temp;
+       int irq, ret;
        struct ehci_mxc_priv *priv;
        struct device *dev = &pdev->dev;
 
@@ -188,10 +196,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                clk_enable(priv->ahbclk);
        }
 
-       /* set up the PORTSCx register */
-       ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
-       mdelay(10);
-
        /* setup specific usb hw */
        ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
        if (ret < 0)
index a1e8d273103f77b2d237a5f68438b289b51bb92a..01bb72b7183230182fac79fd307b17323e79cfb3 100644 (file)
@@ -103,6 +103,19 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        if (retval)
                return retval;
 
+       if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
+           (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
+               /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
+                * read/write memory space which does not belong to it when
+                * there is NULL pointer with T-bit set to 1 in the frame list
+                * table. To avoid the issue, the frame list link pointer
+                * should always contain a valid pointer to a inactive qh.
+                */
+               ehci->use_dummy_qh = 1;
+               ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
+                               "dummy qh workaround\n");
+       }
+
        /* data structure init */
        retval = ehci_init(hcd);
        if (retval)
index a92526d6e5aeb4a306442df77d27b702e00c0d0c..d9f78eb265721bb065f23482e482b50d2bc8430a 100644 (file)
@@ -98,7 +98,14 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
         */
        *prev_p = *periodic_next_shadow(ehci, &here,
                        Q_NEXT_TYPE(ehci, *hw_p));
-       *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
+
+       if (!ehci->use_dummy_qh ||
+           *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p))
+                       != EHCI_LIST_END(ehci))
+               *hw_p = *shadow_next_periodic(ehci, &here,
+                               Q_NEXT_TYPE(ehci, *hw_p));
+       else
+               *hw_p = ehci->dummy->qh_dma;
 }
 
 /* how many of the uframe's 125 usecs are allocated? */
@@ -2335,7 +2342,11 @@ restart:
                                 * pointer for much longer, if at all.
                                 */
                                *q_p = q.itd->itd_next;
-                               *hw_p = q.itd->hw_next;
+                               if (!ehci->use_dummy_qh ||
+                                   q.itd->hw_next != EHCI_LIST_END(ehci))
+                                       *hw_p = q.itd->hw_next;
+                               else
+                                       *hw_p = ehci->dummy->qh_dma;
                                type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
                                wmb();
                                modified = itd_complete (ehci, q.itd);
@@ -2368,7 +2379,11 @@ restart:
                                 * URB completion.
                                 */
                                *q_p = q.sitd->sitd_next;
-                               *hw_p = q.sitd->hw_next;
+                               if (!ehci->use_dummy_qh ||
+                                   q.sitd->hw_next != EHCI_LIST_END(ehci))
+                                       *hw_p = q.sitd->hw_next;
+                               else
+                                       *hw_p = ehci->dummy->qh_dma;
                                type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
                                wmb();
                                modified = sitd_complete (ehci, q.sitd);
index bde823f704e9a6d496cf735f08658fa7f2f6397b..ba8eab366b823fd7153879a801ce7a60c915af08 100644 (file)
@@ -73,6 +73,7 @@ struct ehci_hcd {                     /* one per controller */
 
        /* async schedule support */
        struct ehci_qh          *async;
+       struct ehci_qh          *dummy;         /* For AMD quirk use */
        struct ehci_qh          *reclaim;
        unsigned                scanning : 1;
 
@@ -131,6 +132,7 @@ struct ehci_hcd {                   /* one per controller */
        unsigned                need_io_watchdog:1;
        unsigned                broken_periodic:1;
        unsigned                fs_i_thresh:1;  /* Intel iso scheduling */
+       unsigned                use_dummy_qh:1; /* AMD Frame List table quirk*/
 
        /* required for usb32 quirk */
        #define OHCI_CTRL_HCFS          (3 << 6)
index 8196fa11fec43678cb96b4c3241fd63b7fc1b35f..43a39eb56cc6ea77af2cc7ae930392f1cd70325a 100644 (file)
@@ -70,7 +70,6 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -2684,7 +2683,7 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __init isp1362_probe(struct platform_device *pdev)
+static int __devinit isp1362_probe(struct platform_device *pdev)
 {
        struct usb_hcd *hcd;
        struct isp1362_hcd *isp1362_hcd;
index 10e1872f3ab9deb2eb06a150f884a19919d26365..931d588c3fb57ccea160bfde8ef51468cfd46467 100644 (file)
@@ -273,4 +273,4 @@ static struct platform_driver ohci_hcd_jz4740_driver = {
        },
 };
 
-MODULE_ALIAS("platfrom:jz4740-ohci");
+MODULE_ALIAS("platform:jz4740-ohci");
index 6e7fb5f38db6379f0318f223f31054798e4640f0..ee60cd3ea64201dc4e86d534651c0699d7e8f1ef 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/debugfs.h>
-#include <linux/smp_lock.h>
 #include <asm/io.h>
 
 #include "uhci-hcd.h"
index 202770676da30c409652dc1aca0b4d33a857d366..d178761c39817ec71c0b9461e69a01eb6856e473 100644 (file)
@@ -1045,7 +1045,7 @@ static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
        if (udev->speed == USB_SPEED_SUPER)
                return ep->ss_ep_comp.wBytesPerInterval;
 
-       max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+       max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
        max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
        /* A 0 in max burst means 1 transfer per ESIT */
        return max_packet * (max_burst + 1);
@@ -1135,7 +1135,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
                /* Fall through */
        case USB_SPEED_FULL:
        case USB_SPEED_LOW:
-               max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+               max_packet = GET_MAX_PACKET(ep->desc.wMaxPacketSize);
                ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
                break;
        default:
index 9f3115e729b173605cb36c278509b7befb68f825..df558f6f84e30eff6d6df0fc61c3bd67fb183387 100644 (file)
@@ -2104,7 +2104,6 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
 
        if (!(status & STS_EINT)) {
                spin_unlock(&xhci->lock);
-               xhci_warn(xhci, "Spurious interrupt.\n");
                return IRQ_NONE;
        }
        xhci_dbg(xhci, "op reg status = %08x\n", status);
index 5d7d4e951ea4bc951c4783729472467a383ec1c2..06fca0835b52cc606d57a467332dec1fee916366 100644 (file)
@@ -577,6 +577,65 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
        xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
 }
 
+static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+{
+       u64     val_64;
+
+       /* step 2: initialize command ring buffer */
+       val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+       val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
+               (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
+                                     xhci->cmd_ring->dequeue) &
+                (u64) ~CMD_RING_RSVD_BITS) |
+               xhci->cmd_ring->cycle_state;
+       xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+                       (long unsigned long) val_64);
+       xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+}
+
+/*
+ * The whole command ring must be cleared to zero when we suspend the host.
+ *
+ * The host doesn't save the command ring pointer in the suspend well, so we
+ * need to re-program it on resume.  Unfortunately, the pointer must be 64-byte
+ * aligned, because of the reserved bits in the command ring dequeue pointer
+ * register.  Therefore, we can't just set the dequeue pointer back in the
+ * middle of the ring (TRBs are 16-byte aligned).
+ */
+static void xhci_clear_command_ring(struct xhci_hcd *xhci)
+{
+       struct xhci_ring *ring;
+       struct xhci_segment *seg;
+
+       ring = xhci->cmd_ring;
+       seg = ring->deq_seg;
+       do {
+               memset(seg->trbs, 0, SEGMENT_SIZE);
+               seg = seg->next;
+       } while (seg != ring->deq_seg);
+
+       /* Reset the software enqueue and dequeue pointers */
+       ring->deq_seg = ring->first_seg;
+       ring->dequeue = ring->first_seg->trbs;
+       ring->enq_seg = ring->deq_seg;
+       ring->enqueue = ring->dequeue;
+
+       /*
+        * Ring is now zeroed, so the HW should look for change of ownership
+        * when the cycle bit is set to 1.
+        */
+       ring->cycle_state = 1;
+
+       /*
+        * Reset the hardware dequeue pointer.
+        * Yes, this will need to be re-written after resume, but we're paranoid
+        * and want to make sure the hardware doesn't access bogus memory
+        * because, say, the BIOS or an SMI started the host without changing
+        * the command ring pointers.
+        */
+       xhci_set_cmd_ring_deq(xhci);
+}
+
 /*
  * Stop HC (not bus-specific)
  *
@@ -604,6 +663,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
                spin_unlock_irq(&xhci->lock);
                return -ETIMEDOUT;
        }
+       xhci_clear_command_ring(xhci);
 
        /* step 3: save registers */
        xhci_save_registers(xhci);
@@ -635,7 +695,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        u32                     command, temp = 0;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
-       u64     val_64;
        int     old_state, retval;
 
        old_state = hcd->state;
@@ -648,15 +707,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                /* step 1: restore register */
                xhci_restore_registers(xhci);
                /* step 2: initialize command ring buffer */
-               val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
-               val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
-                        (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
-                                              xhci->cmd_ring->dequeue) &
-                        (u64) ~CMD_RING_RSVD_BITS) |
-                        xhci->cmd_ring->cycle_state;
-               xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
-                               (long unsigned long) val_64);
-               xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+               xhci_set_cmd_ring_deq(xhci);
                /* step 3: restore state and start state*/
                /* step 3: set CRS flag */
                command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -714,6 +765,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                return retval;
        }
 
+       spin_unlock_irq(&xhci->lock);
        /* Re-setup MSI-X */
        if (hcd->irq)
                free_irq(hcd->irq, hcd);
@@ -736,6 +788,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                hcd->irq = pdev->irq;
        }
 
+       spin_lock_irq(&xhci->lock);
        /* step 4: set Run/Stop bit */
        command = xhci_readl(xhci, &xhci->op_regs->command);
        command |= CMD_RUN;
index 93d3bf4d213c76dbacc8d964f72bda2a4c2c32c5..85e65647d44518cf3c3bbf0873816b344b90cf53 100644 (file)
@@ -621,6 +621,11 @@ struct xhci_ep_ctx {
 #define MAX_PACKET_MASK                (0xffff << 16)
 #define MAX_PACKET_DECODED(p)  (((p) >> 16) & 0xffff)
 
+/* Get max packet size from ep desc. Bit 10..0 specify the max packet size.
+ * USB2.0 spec 9.6.6.
+ */
+#define GET_MAX_PACKET(p)      ((p) & 0x7ff)
+
 /* tx_info bitmasks */
 #define AVG_TRB_LENGTH_FOR_EP(p)       ((p) & 0xffff)
 #define MAX_ESIT_PAYLOAD_FOR_EP(p)     (((p) & 0xffff) << 16)
index 5a47805d9580740c7ef33f75bb0fafd0a2c73dad..c90c89dc00035c1e3c2da06fb177f11c82ed28dd 100644 (file)
@@ -364,7 +364,7 @@ static int mts_scsi_host_reset(struct scsi_cmnd *srb)
 }
 
 static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
+mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb);
 
 static void mts_transfer_cleanup( struct urb *transfer );
 static void mts_do_sg(struct urb * transfer);
@@ -573,7 +573,7 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
 
 
 static int
-mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
+mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
 {
        struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
        int err = 0;
@@ -626,6 +626,8 @@ out:
        return err;
 }
 
+static DEF_SCSI_QCMD(mts_scsi_queuecommand)
+
 static struct scsi_host_template mts_scsi_host_template = {
        .module                 = THIS_MODULE,
        .name                   = "microtekX6",
index 2f43c57743c9c905b26e8e06dc517df6b5bb7c26..9251773ecef4ffae6102a29f356bad68cf7dd574 100644 (file)
@@ -196,11 +196,9 @@ static ssize_t get_port1_handler(struct device *dev,
        return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
 }
 
-static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO,
-                  get_port0_handler, set_port0_handler);
+static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler);
 
-static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO,
-                  get_port1_handler, set_port1_handler);
+static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler);
 
 
 static int cypress_probe(struct usb_interface *interface,
index 3756641987762f3ff196bcb16601610a164a883a..c9078e4e1f4d5a5cd384a181d024fbccb83fc1e7 100644 (file)
@@ -553,6 +553,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
                        /* needed for power consumption */
                        struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc;
 
+                       memset(&info, 0, sizeof(info));
                        /* directly from the descriptor */
                        info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
                        info.product = dev->product_id;
index 70d00e99a4b40f4c4fde10c0472c087a897e3ed6..dd573abd2d1edf9b32b0a97aa9def3d1abd9d967 100644 (file)
@@ -3008,6 +3008,7 @@ sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 #else
                        x.sisusb_conactive  = 0;
 #endif
+                       memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
 
                        if (copy_to_user((void __user *)arg, &x, sizeof(x)))
                                retval = -EFAULT;
index d77aba46ae85675e58afb532078458b74b7b29a7..f63776a48e2a8717f37d5ebf68cb6b408a5d895a 100644 (file)
@@ -86,7 +86,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
        return count;
 }
 
-static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed);
 
 static int tv_probe(struct usb_interface *interface,
                    const struct usb_device_id *id)
index 63da2c3c838fd0b6495d0429a870e3b1e035e9dd..c96f51de1696581faba425fb29db3a18f9ef1458 100644 (file)
@@ -94,7 +94,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
        change_color(led);                                              \
        return count;                                                   \
 }                                                                      \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
 show_set(blue);
 show_set(red);
 show_set(green);
index de8ef945b536d07a277c56bff506798bd90620e3..417b8f207e8b126ac5b2ee33bab0dc5fdaa232b0 100644 (file)
@@ -192,7 +192,7 @@ static ssize_t set_attr_##name(struct device *dev,          \
                                                                \
        return count;                                           \
 }                                                              \
-static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name);
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name);
 
 static ssize_t show_attr_text(struct device *dev,
        struct device_attribute *attr, char *buf)
@@ -223,7 +223,7 @@ static ssize_t set_attr_text(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text);
+static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text);
 
 static ssize_t show_attr_decimals(struct device *dev,
        struct device_attribute *attr, char *buf)
@@ -272,8 +272,7 @@ static ssize_t set_attr_decimals(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO,
-       show_attr_decimals, set_attr_decimals);
+static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals);
 
 static ssize_t show_attr_textmode(struct device *dev,
        struct device_attribute *attr, char *buf)
@@ -319,8 +318,7 @@ static ssize_t set_attr_textmode(struct device *dev,
        return -EINVAL;
 }
 
-static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO,
-       show_attr_textmode, set_attr_textmode);
+static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode);
 
 
 MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered);
index 44cb37b5a4dc1f9b27075e3db5346b9ebe307b22..c436e1e2c3b6274f0fdcdb699ec1fd10a9b2273f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/poll.h>
 #include <linux/compat.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 
index 8ec94f15a73820ce5a1b26b8ed5d86fa04b6bba4..e5ce42bd316e5c68d29a72ffdc2d805b6a575f37 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
index 611a9d274363ee90132e705ea61d8af1aa36657a..fcb5206a65bdfd84eca43a39ce974f20489e2c80 100644 (file)
@@ -171,8 +171,9 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
        }
 
        /* Start sampling ID pin, when plug is removed from MUSB */
-       if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
-               || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+       if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
+               || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) ||
+               (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
                mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
                musb->a_wait_bcon = TIMER_DELAY;
        }
@@ -323,30 +324,8 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
        return -EIO;
 }
 
-int __init musb_platform_init(struct musb *musb, void *board_data)
+static void musb_platform_reg_init(struct musb *musb)
 {
-
-       /*
-        * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
-        * and OTG HOST modes, while rev 1.1 and greater require PE7 to
-        * be low for DEVICE mode and high for HOST mode. We set it high
-        * here because we are in host mode
-        */
-
-       if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
-               printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
-                       musb->config->gpio_vrsel);
-               return -ENODEV;
-       }
-       gpio_direction_output(musb->config->gpio_vrsel, 0);
-
-       usb_nop_xceiv_register();
-       musb->xceiv = otg_get_transceiver();
-       if (!musb->xceiv) {
-               gpio_free(musb->config->gpio_vrsel);
-               return -ENODEV;
-       }
-
        if (ANOMALY_05000346) {
                bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
                SSYNC();
@@ -358,7 +337,8 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
        }
 
        /* Configure PLL oscillator register */
-       bfin_write_USB_PLLOSC_CTRL(0x30a8);
+       bfin_write_USB_PLLOSC_CTRL(0x3080 |
+                       ((480/musb->config->clkin) << 1));
        SSYNC();
 
        bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
@@ -380,6 +360,33 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
                                EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
                                EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
        SSYNC();
+}
+
+int __init musb_platform_init(struct musb *musb, void *board_data)
+{
+
+       /*
+        * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
+        * and OTG HOST modes, while rev 1.1 and greater require PE7 to
+        * be low for DEVICE mode and high for HOST mode. We set it high
+        * here because we are in host mode
+        */
+
+       if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
+               printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
+                       musb->config->gpio_vrsel);
+               return -ENODEV;
+       }
+       gpio_direction_output(musb->config->gpio_vrsel, 0);
+
+       usb_nop_xceiv_register();
+       musb->xceiv = otg_get_transceiver();
+       if (!musb->xceiv) {
+               gpio_free(musb->config->gpio_vrsel);
+               return -ENODEV;
+       }
+
+       musb_platform_reg_init(musb);
 
        if (is_host_enabled(musb)) {
                musb->board_set_vbus = bfin_set_vbus;
@@ -394,6 +401,27 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
        return 0;
 }
 
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb *musb,
+                       struct musb_context_registers *musb_context)
+{
+       if (is_host_active(musb))
+               /*
+                * During hibernate gpio_vrsel will change from high to low
+                * low which will generate wakeup event resume the system
+                * immediately.  Set it to 0 before hibernate to avoid this
+                * wakeup event.
+                */
+               gpio_set_value(musb->config->gpio_vrsel, 0);
+}
+
+void musb_platform_restore_context(struct musb *musb,
+                       struct musb_context_registers *musb_context)
+{
+       musb_platform_reg_init(musb);
+}
+#endif
+
 int musb_platform_exit(struct musb *musb)
 {
        gpio_free(musb->config->gpio_vrsel);
index c9f9024c551525d8704a0d888bb8b1913859d326..e6669fc3b8048c3dfdbbbf5ee1e1a2048561cfaf 100644 (file)
@@ -552,7 +552,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
        if (int_usb & MUSB_INTR_SESSREQ) {
                void __iomem *mbase = musb->mregs;
 
-               if (devctl & MUSB_DEVCTL_BDEVICE) {
+               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
+                               && (devctl & MUSB_DEVCTL_BDEVICE)) {
                        DBG(3, "SessReq while on B state\n");
                        return IRQ_HANDLED;
                }
@@ -1052,6 +1053,11 @@ static void musb_shutdown(struct platform_device *pdev)
                clk_put(musb->clock);
        spin_unlock_irqrestore(&musb->lock, flags);
 
+       if (!is_otg_enabled(musb) && is_host_enabled(musb))
+               usb_remove_hcd(musb_to_hcd(musb));
+       musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+       musb_platform_exit(musb);
+
        /* FIXME power down */
 }
 
@@ -2244,13 +2250,6 @@ static int __exit musb_remove(struct platform_device *pdev)
         */
        musb_exit_debugfs(musb);
        musb_shutdown(pdev);
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
-       if (musb->board_mode == MUSB_HOST)
-               usb_remove_hcd(musb_to_hcd(musb));
-#endif
-       musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
-       musb_platform_exit(musb);
-       musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
 
        musb_free(musb);
        iounmap(ctrl_base);
@@ -2411,9 +2410,6 @@ static int musb_suspend(struct device *dev)
        unsigned long   flags;
        struct musb     *musb = dev_to_musb(&pdev->dev);
 
-       if (!musb->clock)
-               return 0;
-
        spin_lock_irqsave(&musb->lock, flags);
 
        if (is_peripheral_active(musb)) {
@@ -2428,10 +2424,12 @@ static int musb_suspend(struct device *dev)
 
        musb_save_context(musb);
 
-       if (musb->set_clock)
-               musb->set_clock(musb->clock, 0);
-       else
-               clk_disable(musb->clock);
+       if (musb->clock) {
+               if (musb->set_clock)
+                       musb->set_clock(musb->clock, 0);
+               else
+                       clk_disable(musb->clock);
+       }
        spin_unlock_irqrestore(&musb->lock, flags);
        return 0;
 }
@@ -2441,13 +2439,12 @@ static int musb_resume_noirq(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct musb     *musb = dev_to_musb(&pdev->dev);
 
-       if (!musb->clock)
-               return 0;
-
-       if (musb->set_clock)
-               musb->set_clock(musb->clock, 1);
-       else
-               clk_enable(musb->clock);
+       if (musb->clock) {
+               if (musb->set_clock)
+                       musb->set_clock(musb->clock, 1);
+               else
+                       clk_enable(musb->clock);
+       }
 
        musb_restore_context(musb);
 
index 69797e5b46a7fbfbea3ff5bffe9769b902149249..febaabcc2b3568d3538e26ff9912383e60ea1600 100644 (file)
@@ -487,7 +487,7 @@ struct musb_context_registers {
 };
 
 #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
-    defined(CONFIG_ARCH_OMAP4)
+    defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_BLACKFIN)
 extern void musb_platform_save_context(struct musb *musb,
                struct musb_context_registers *musb_context);
 extern void musb_platform_restore_context(struct musb *musb,
index 5d815049cbaac4796617ed9e1ae4e0aa6e29a668..36cfd060dbe55bffb7707293f3c1182ed7cbff6e 100644 (file)
@@ -644,10 +644,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
         */
 
                                csr |= MUSB_RXCSR_DMAENAB;
-                               if (!musb_ep->hb_mult &&
-                                       musb_ep->hw_ep->rx_double_buffered)
-                                       csr |= MUSB_RXCSR_AUTOCLEAR;
 #ifdef USE_MODE1
+                               csr |= MUSB_RXCSR_AUTOCLEAR;
                                /* csr |= MUSB_RXCSR_DMAMODE; */
 
                                /* this special sequence (enabling and then
@@ -656,6 +654,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                 */
                                musb_writew(epio, MUSB_RXCSR,
                                        csr | MUSB_RXCSR_DMAMODE);
+#else
+                               if (!musb_ep->hb_mult &&
+                                       musb_ep->hw_ep->rx_double_buffered)
+                                       csr |= MUSB_RXCSR_AUTOCLEAR;
 #endif
                                musb_writew(epio, MUSB_RXCSR, csr);
 
@@ -807,7 +809,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
 
 #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA)
                /* Autoclear doesn't clear RxPktRdy for short packets */
-               if ((dma->desired_mode == 0)
+               if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
                                || (dma->actual_len
                                        & (musb_ep->packet_sz - 1))) {
                        /* ack the read! */
@@ -818,8 +820,16 @@ void musb_g_rx(struct musb *musb, u8 epnum)
                /* incomplete, and not short? wait for next IN packet */
                if ((request->actual < request->length)
                                && (musb_ep->dma->actual_len
-                                       == musb_ep->packet_sz))
+                                       == musb_ep->packet_sz)) {
+                       /* In double buffer case, continue to unload fifo if
+                        * there is Rx packet in FIFO.
+                        **/
+                       csr = musb_readw(epio, MUSB_RXCSR);
+                       if ((csr & MUSB_RXCSR_RXPKTRDY) &&
+                               hw_ep->rx_double_buffered)
+                               goto exit;
                        return;
+               }
 #endif
                musb_g_giveback(musb_ep, request, 0);
 
@@ -827,7 +837,7 @@ void musb_g_rx(struct musb *musb, u8 epnum)
                if (!request)
                        return;
        }
-
+exit:
        /* Analyze request */
        rxstate(musb, to_musb_request(request));
 }
@@ -916,13 +926,9 @@ static int musb_gadget_enable(struct usb_ep *ep,
                 * likewise high bandwidth periodic tx
                 */
                /* Set TXMAXP with the FIFO size of the endpoint
-                * to disable double buffering mode. Currently, It seems that double
-                * buffering has problem if musb RTL revision number < 2.0.
+                * to disable double buffering mode.
                 */
-               if (musb->hwvers < MUSB_HWVERS_2000)
-                       musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
-               else
-                       musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
 
                csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
                if (musb_readw(regs, MUSB_TXCSR)
@@ -958,10 +964,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* Set RXMAXP with the FIFO size of the endpoint
                 * to disable double buffering mode.
                 */
-               if (musb->hwvers < MUSB_HWVERS_2000)
-                       musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
-               else
-                       musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
 
                /* force shared fifo to OUT-only mode */
                if (hw_ep->is_shared_fifo) {
@@ -1166,8 +1169,6 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
                                                : DMA_FROM_DEVICE);
                        request->mapped = 0;
                }
-       } else if (!req->buf) {
-               return -ENODATA;
        } else
                request->mapped = 0;
 
@@ -1695,8 +1696,10 @@ int __init musb_gadget_setup(struct musb *musb)
        musb_platform_try_idle(musb, 0);
 
        status = device_register(&musb->g.dev);
-       if (status != 0)
+       if (status != 0) {
+               put_device(&musb->g.dev);
                the_gadget = NULL;
+       }
        return status;
 }
 
index 244267527a60b1421ea7c70a814388dde6951f7f..5a727c5b86763fdb1f65347c9f02a44d49d70568 100644 (file)
@@ -633,8 +633,9 @@ static inline u8  musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
        return 0;
 }
 
-static inline void  musb_read_txhubport(void __iomem *mbase, u8 epnum)
+static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
 {
+       return 0;
 }
 
 #endif /* CONFIG_BLACKFIN */
index 6f771af5cbdb6b61b160c4a73d5ad863b62c051c..563114d613d603a9c4f9b13a194bf4d0f17943be 100644 (file)
@@ -158,6 +158,8 @@ static int dma_channel_program(struct dma_channel *channel,
                                dma_addr_t dma_addr, u32 len)
 {
        struct musb_dma_channel *musb_channel = channel->private_data;
+       struct musb_dma_controller *controller = musb_channel->controller;
+       struct musb *musb = controller->private_data;
 
        DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
                musb_channel->epnum,
@@ -167,6 +169,18 @@ static int dma_channel_program(struct dma_channel *channel,
        BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
                channel->status == MUSB_DMA_STATUS_BUSY);
 
+       /*
+        * The DMA engine in RTL1.8 and above cannot handle
+        * DMA addresses that are not aligned to a 4 byte boundary.
+        * It ends up masking the last two bits of the address
+        * programmed in DMA_ADDR.
+        *
+        * Fail such DMA transfers, so that the backup PIO mode
+        * can carry out the transfer
+        */
+       if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4))
+               return false;
+
        channel->actual_len = 0;
        musb_channel->start_addr = dma_addr;
        musb_channel->len = len;
index bdc3ea66be692dd1155828d97971cb11970a77f5..9fea48264fa2049fe7eefd18cada2013a180a5e0 100644 (file)
@@ -1896,7 +1896,7 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
        }
        return count;
 }
-static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req);
 
 static ssize_t
 get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1942,8 +1942,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
        }
        return count;
 }
-static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
-       get_a_bus_drop, set_a_bus_drop);
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, set_a_bus_drop);
 
 static ssize_t
 get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1988,7 +1987,7 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
        }
        return count;
 }
-static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
+static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req);
 
 static ssize_t
 set_a_clr_err(struct device *dev, struct device_attribute *attr,
@@ -2012,7 +2011,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
        }
        return count;
 }
-static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
 
 static struct attribute *inputs_attrs[] = {
        &dev_attr_a_bus_req.attr,
index 89a9a584780391d7ad6544440aecac540a3fc4f0..76f8b3556672307452c991d6144d6395c7395c65 100644 (file)
@@ -794,6 +794,8 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
+       { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
index 7dfe02f1fb6a09b2763befdced18226e1b9c5365..263f625511972137585c8cdcee3f1fe7a0a74ab9 100644 (file)
 #define FTDI_SCIENCESCOPE_LOGBOOKML_PID                0xFF18
 #define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID       0xFF1C
 #define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID       0xFF1D
+
+/*
+ * Milkymist One JTAG/Serial
+ */
+#define QIHARDWARE_VID                 0x20B7
+#define MILKYMISTONE_JTAGSERIAL_PID    0x0713
+
index 2297fb1bcf6547494c0e733c423be95de1999ed2..ef2977d3a613a441a7300ab37348fb99fa8f636c 100644 (file)
@@ -518,7 +518,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
-       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
index e64da74bdcc5d112ff20cf46e0c074115ca3ee67..861223f2af6eddc0a3fb3c4a449b71af9221eed4 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
index a688b1e686eae326d26da45bf37fa378524e6624..689ee1fb702a4351a7fdb2a0e0a400a682eabd4f 100644 (file)
@@ -285,7 +285,7 @@ static int slave_configure(struct scsi_device *sdev)
 
 /* queue a command */
 /* This is always called with scsi_lock(host) held */
-static int queuecommand(struct scsi_cmnd *srb,
+static int queuecommand_lck(struct scsi_cmnd *srb,
                        void (*done)(struct scsi_cmnd *))
 {
        struct us_data *us = host_to_us(srb->device->host);
@@ -315,6 +315,8 @@ static int queuecommand(struct scsi_cmnd *srb,
        return 0;
 }
 
+static DEF_SCSI_QCMD(queuecommand)
+
 /***********************************************************************
  * Error handling functions
  ***********************************************************************/
index 57fc2f532cabe985b9b10fdd57c7042b6d0fd4be..ceba512f84d0eeeb2f3170a14df915528304dbe2 100644 (file)
@@ -121,7 +121,7 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
        }
        return result;
 }
-static DEVICE_ATTR(truinst, S_IWUGO | S_IRUGO, show_truinst, NULL);
+static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL);
 
 int sierra_ms_init(struct us_data *us)
 {
index 2054b1e25a6554e3e62e8c96c9ccb8b4dc7fa893..339fac3949df870bd838c08fe652386ddfdde172 100644 (file)
@@ -331,10 +331,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
 
        iu->iu_id = IU_ID_COMMAND;
        iu->tag = cpu_to_be16(stream_id);
-       if (sdev->ordered_tags && (cmnd->request->cmd_flags & REQ_HARDBARRIER))
-               iu->prio_attr = UAS_ORDERED_TAG;
-       else
-               iu->prio_attr = UAS_SIMPLE_TAG;
+       iu->prio_attr = UAS_SIMPLE_TAG;
        iu->len = len;
        int_to_scsilun(sdev->lun, &iu->lun);
        memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
@@ -433,7 +430,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
        return 0;
 }
 
-static int uas_queuecommand(struct scsi_cmnd *cmnd,
+static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
                                        void (*done)(struct scsi_cmnd *))
 {
        struct scsi_device *sdev = cmnd->device;
@@ -491,6 +488,8 @@ static int uas_queuecommand(struct scsi_cmnd *cmnd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(uas_queuecommand)
+
 static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 {
        struct scsi_device *sdev = cmnd->device;
index 436e4f7110cbddc41cda3d4677fdb2eca6c0ab17..e45e673b8770e78a44b9ba0c0ace5f70122606e8 100644 (file)
@@ -326,7 +326,8 @@ int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *availab
        int bit_index;
 
        ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL);
-       
+       if (!ai)
+               return UWB_RSV_ALLOC_NOT_FOUND;
        ai->min_mas = rsv->min_mas;
        ai->max_mas = rsv->max_mas;
        ai->max_interval = rsv->max_interval;
index 3ec24609151e8ec322c48afcebae8dc9ce578b5d..734c650a47c433be7524e27b35b5e3c5b5eea0ad 100644 (file)
@@ -502,8 +502,10 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        struct adp8860_bl *data = dev_get_drvdata(dev);
+       int ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+       if (ret)
+               return ret;
 
-       strict_strtoul(buf, 10, &data->cached_daylight_max);
        return adp8860_store(dev, buf, count, ADP8860_BLMX1);
 }
 static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
@@ -614,7 +616,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
        if (val == 0) {
                /* Enable automatic ambient light sensing */
                adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
-       } else if ((val > 0) && (val < 6)) {
+       } else if ((val > 0) && (val <= 3)) {
                /* Disable automatic ambient light sensing */
                adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
 
@@ -622,7 +624,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
                mutex_lock(&data->lock);
                adp8860_read(data->client, ADP8860_CFGR, &reg_val);
                reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
-               reg_val |= val << CFGR_BLV_SHIFT;
+               reg_val |= (val - 1) << CFGR_BLV_SHIFT;
                adp8860_write(data->client, ADP8860_CFGR, reg_val);
                mutex_unlock(&data->lock);
        }
index 9093ef0fa8696f2da8b086984042001aa94d8eec..c67801e57aafb24f546250bcbdb45d59bcb5b9d4 100644 (file)
@@ -78,7 +78,7 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
        const u16 slpin = 0x10;
        const u16 disoff = 0x28;
 
-       if (power) {
+       if (power <= FB_BLANK_NORMAL) {
                if (priv->lcd_on)
                        return 0;
 
index abc43a0eb97dd054f7c526b47fa014e61e458dc0..5d3cf33953ac299cd759fb19bfd5a1d53205cc0b 100644 (file)
@@ -129,7 +129,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power)
        struct spi_device *spi = st->spi;
        struct lms283gf05_pdata *pdata = spi->dev.platform_data;
 
-       if (power) {
+       if (power <= FB_BLANK_NORMAL) {
                if (pdata)
                        lms283gf05_reset(pdata->reset_gpio,
                                        pdata->reset_inverted);
index 9fb533f6373e6ab958646ccfdcba047c43b99d9d..1485f7345f49ee32586d5d665d1bd624cfcd3e1a 100644 (file)
@@ -335,6 +335,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
                },
                .driver_data    = (void *)&nvidia_chipset_data,
        },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookAir 3,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookAir 3,2",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
        { }
 };
 
index 550443518891d41345234f4aa72929798b1f68a8..21866ec69656d6be90e69af18a56316895f9d69f 100644 (file)
@@ -25,6 +25,7 @@ struct pwm_bl_data {
        struct pwm_device       *pwm;
        struct device           *dev;
        unsigned int            period;
+       unsigned int            lth_brightness;
        int                     (*notify)(struct device *,
                                          int brightness);
 };
@@ -48,7 +49,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
                pwm_config(pb->pwm, 0, pb->period);
                pwm_disable(pb->pwm);
        } else {
-               pwm_config(pb->pwm, brightness * pb->period / max, pb->period);
+               brightness = pb->lth_brightness +
+                       (brightness * (pb->period - pb->lth_brightness) / max);
+               pwm_config(pb->pwm, brightness, pb->period);
                pwm_enable(pb->pwm);
        }
        return 0;
@@ -92,6 +95,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
        pb->period = data->pwm_period_ns;
        pb->notify = data->notify;
+       pb->lth_brightness = data->lth_brightness *
+               (data->pwm_period_ns / data->max_brightness);
        pb->dev = &pdev->dev;
 
        pb->pwm = pwm_request(data->pwm_id, "backlight");
index a3128c9cb7ad6b64999eb6e7bffe6a2898c996e0..5927db0da9998f87f273d9430d782c26723fb16e 100644 (file)
@@ -729,10 +729,10 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
 
        return strlen(buf);
 }
-static DEVICE_ATTR(gamma_table, 0644,
+static DEVICE_ATTR(gamma_table, 0444,
                s6e63m0_sysfs_show_gamma_table, NULL);
 
-static int __init s6e63m0_probe(struct spi_device *spi)
+static int __devinit s6e63m0_probe(struct spi_device *spi)
 {
        int ret = 0;
        struct s6e63m0 *lcd = NULL;
@@ -829,6 +829,9 @@ static int __devexit s6e63m0_remove(struct spi_device *spi)
        struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
 
        s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+       device_remove_file(&spi->dev, &dev_attr_gamma_table);
+       device_remove_file(&spi->dev, &dev_attr_gamma_mode);
+       backlight_device_unregister(lcd->bd);
        lcd_device_unregister(lcd->ld);
        kfree(lcd);
 
index 54e32c513610f8164839c2c167e3eccc09bbdb8b..915448ec75bf2fd33617eb73517876da74c68137 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/screen_info.h>
-#include <linux/smp_lock.h>
 #include <video/vga.h>
 #include <asm/io.h>
 
index fed2a72bc6b60a1986172298fbb67bc0eca2b3bc..2fd7e5271be91ea1c9cd5b202ef40f985266dd46 100644 (file)
@@ -554,9 +554,15 @@ void __init omap_vram_reserve_sdram_memblock(void)
        size = PAGE_ALIGN(size);
 
        if (paddr) {
-               if ((paddr & ~PAGE_MASK) ||
-                   !memblock_is_region_memory(paddr, size)) {
-                       pr_err("Illegal SDRAM region for VRAM\n");
+               if (paddr & ~PAGE_MASK) {
+                       pr_err("VRAM start address 0x%08x not page aligned\n",
+                                       paddr);
+                       return;
+               }
+
+               if (!memblock_is_region_memory(paddr, size)) {
+                       pr_err("Illegal SDRAM region 0x%08x..0x%08x for VRAM\n",
+                                       paddr, paddr + size - 1);
                        return;
                }
 
@@ -570,9 +576,12 @@ void __init omap_vram_reserve_sdram_memblock(void)
                        return;
                }
        } else {
-               paddr = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_REAL_LIMIT);
+               paddr = memblock_alloc(size, PAGE_SIZE);
        }
 
+       memblock_free(paddr, size);
+       memblock_remove(paddr, size);
+
        omap_vram_add_region(paddr, size);
 
        pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
index a0e22ac483a3d65161f7e54bdfad322c8918d93c..167400e2a18204f359edc38b6cfe2499e7992aa5 100644 (file)
@@ -94,7 +94,6 @@ static int __devinit riva_setup_i2c_bus(struct riva_i2c_chan *chan,
 
        strcpy(chan->adapter.name, name);
        chan->adapter.owner             = THIS_MODULE;
-       chan->adapter.id                = I2C_HW_B_RIVA;
        chan->adapter.class             = i2c_class;
        chan->adapter.algo_data         = &chan->algo;
        chan->adapter.dev.parent        = &chan->par->pdev->dev;
index 55b3077ff6fff567e2fc3c1831b1255498cb1c07..d7df10315d8d6f51aba676328985a52128e81876 100644 (file)
@@ -1071,6 +1071,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                if (!hdmi->info)
                        goto out;
 
+               hdmi->monspec.modedb_len = 0;
+               fb_destroy_modedb(hdmi->monspec.modedb);
+               hdmi->monspec.modedb = NULL;
+
                acquire_console_sem();
 
                /* HDMI disconnect */
@@ -1078,7 +1082,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 
                release_console_sem();
                pm_runtime_put(hdmi->dev);
-               fb_destroy_modedb(hdmi->monspec.modedb);
        }
 
 out:
index 50963739a40977832e03285b1049be65f4cde1dd..9b1364723c65e2fcff4dcec661d59ab50b960ee1 100644 (file)
@@ -115,15 +115,16 @@ static const struct fb_videomode default_720p = {
        .xres = 1280,
        .yres = 720,
 
-       .left_margin = 200,
-       .right_margin = 88,
-       .hsync_len = 48,
+       .left_margin = 220,
+       .right_margin = 110,
+       .hsync_len = 40,
 
        .upper_margin = 20,
        .lower_margin = 5,
        .vsync_len = 5,
 
        .pixclock = 13468,
+       .refresh = 60,
        .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
 };
 
@@ -1197,6 +1198,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                const struct fb_videomode *mode = cfg->lcd_cfg;
                unsigned long max_size = 0;
                int k;
+               int num_cfg;
 
                ch->info = framebuffer_alloc(0, &pdev->dev);
                if (!ch->info) {
@@ -1232,8 +1234,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                info->fix = sh_mobile_lcdc_fix;
                info->fix.smem_len = max_size * (cfg->bpp / 8) * 2;
 
-               if (!mode)
+               if (!mode) {
                        mode = &default_720p;
+                       num_cfg = 1;
+               } else {
+                       num_cfg = ch->cfg.num_cfg;
+               }
+
+               fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
 
                fb_videomode_to_var(var, mode);
                /* Default Y virtual resolution is 2x panel size */
@@ -1281,10 +1289,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 
        for (i = 0; i < j; i++) {
                struct sh_mobile_lcdc_chan *ch = priv->ch + i;
-               const struct fb_videomode *mode = ch->cfg.lcd_cfg;
-
-               if (!mode)
-                       mode = &default_720p;
 
                info = ch->info;
 
@@ -1297,7 +1301,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                        }
                }
 
-               fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist);
                error = register_framebuffer(info);
                if (error < 0)
                        goto err1;
index b52f8e4ef1fdbe3cd19c70d4fb282d15f5b99f85..3dde12b0ab06420c58b0e6a41fc5f23350b28a75 100644 (file)
@@ -4181,6 +4181,9 @@ static void __devinit
 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
                        unsigned int min)
 {
+       if (*mapsize < (min << 20))
+               return;
+
        ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
 
        if(!ivideo->video_vbase) {
@@ -4514,7 +4517,7 @@ sisfb_post_sis300(struct pci_dev *pdev)
        } else {
 #endif
                /* Need to map max FB size for finding out about RAM size */
-               mapsize = 64 << 20;
+               mapsize = ivideo->video_size;
                sisfb_post_map_vram(ivideo, &mapsize, 4);
 
                if(ivideo->video_vbase) {
@@ -4680,7 +4683,7 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
        orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
 
        /* Need to map max FB size for finding out about RAM size */
-       mapsize = 256 << 20;
+       mapsize = ivideo->video_size;
        sisfb_post_map_vram(ivideo, &mapsize, 32);
 
        if(!ivideo->video_vbase) {
@@ -5936,6 +5939,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        ivideo->video_base = pci_resource_start(pdev, 0);
+       ivideo->video_size = pci_resource_len(pdev, 0);
        ivideo->mmio_base  = pci_resource_start(pdev, 1);
        ivideo->mmio_size  = pci_resource_len(pdev, 1);
        ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
index eb8a78d77d9d2a7fb70f81ac54ae902e6b29204d..533a199e7a3f94911ef9665ab5e1789c63bef6d2 100644 (file)
@@ -8,9 +8,12 @@ obj-$(CONFIG_BLOCK)            += biomerge.o
 obj-$(CONFIG_HOTPLUG_CPU)      += cpu_hotplug.o
 obj-$(CONFIG_XEN_XENCOMM)      += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)      += balloon.o
-obj-$(CONFIG_XEN_DEV_EVTCHN)   += evtchn.o
+obj-$(CONFIG_XEN_DEV_EVTCHN)   += xen-evtchn.o
 obj-$(CONFIG_XENFS)            += xenfs/
 obj-$(CONFIG_XEN_SYS_HYPERVISOR)       += sys-hypervisor.o
 obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
 obj-$(CONFIG_SWIOTLB_XEN)      += swiotlb-xen.o
 obj-$(CONFIG_XEN_DOM0)         += pci.o
+
+xen-evtchn-y                   := evtchn.o
+
index 500290b150bb526cf27b9f5e82d9a08b160a2d91..2b17ad5b4b32d27277a115de4cd2fd7834f7769d 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
+#include <asm/e820.h>
 
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
@@ -119,7 +120,7 @@ static void scrub_page(struct page *page)
 }
 
 /* balloon_append: add the given page to the balloon. */
-static void balloon_append(struct page *page)
+static void __balloon_append(struct page *page)
 {
        /* Lowmem is re-populated first, so highmem pages go at list tail. */
        if (PageHighMem(page)) {
@@ -130,7 +131,11 @@ static void balloon_append(struct page *page)
                list_add(&page->lru, &ballooned_pages);
                balloon_stats.balloon_low++;
        }
+}
 
+static void balloon_append(struct page *page)
+{
+       __balloon_append(page);
        totalram_pages--;
 }
 
@@ -191,7 +196,7 @@ static unsigned long current_target(void)
 
 static int increase_reservation(unsigned long nr_pages)
 {
-       unsigned long  pfn, i, flags;
+       unsigned long  pfn, i;
        struct page   *page;
        long           rc;
        struct xen_memory_reservation reservation = {
@@ -203,8 +208,6 @@ static int increase_reservation(unsigned long nr_pages)
        if (nr_pages > ARRAY_SIZE(frame_list))
                nr_pages = ARRAY_SIZE(frame_list);
 
-       spin_lock_irqsave(&xen_reservation_lock, flags);
-
        page = balloon_first_page();
        for (i = 0; i < nr_pages; i++) {
                BUG_ON(page == NULL);
@@ -247,14 +250,12 @@ static int increase_reservation(unsigned long nr_pages)
        balloon_stats.current_pages += rc;
 
  out:
-       spin_unlock_irqrestore(&xen_reservation_lock, flags);
-
        return rc < 0 ? rc : rc != nr_pages;
 }
 
 static int decrease_reservation(unsigned long nr_pages)
 {
-       unsigned long  pfn, i, flags;
+       unsigned long  pfn, i;
        struct page   *page;
        int            need_sleep = 0;
        int ret;
@@ -292,8 +293,6 @@ static int decrease_reservation(unsigned long nr_pages)
        kmap_flush_unused();
        flush_tlb_all();
 
-       spin_lock_irqsave(&xen_reservation_lock, flags);
-
        /* No more mappings: invalidate P2M and add to balloon. */
        for (i = 0; i < nr_pages; i++) {
                pfn = mfn_to_pfn(frame_list[i]);
@@ -308,8 +307,6 @@ static int decrease_reservation(unsigned long nr_pages)
 
        balloon_stats.current_pages -= nr_pages;
 
-       spin_unlock_irqrestore(&xen_reservation_lock, flags);
-
        return need_sleep;
 }
 
@@ -395,7 +392,7 @@ static struct notifier_block xenstore_notifier;
 
 static int __init balloon_init(void)
 {
-       unsigned long pfn;
+       unsigned long pfn, extra_pfn_end;
        struct page *page;
 
        if (!xen_pv_domain())
@@ -416,10 +413,15 @@ static int __init balloon_init(void)
        register_balloon(&balloon_sysdev);
 
        /* Initialise the balloon with excess memory space. */
-       for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
+       extra_pfn_end = min(e820_end_of_ram_pfn(),
+                           (unsigned long)PFN_DOWN(xen_extra_mem_start + xen_extra_mem_size));
+       for (pfn = PFN_UP(xen_extra_mem_start);
+            pfn < extra_pfn_end;
+            pfn++) {
                page = pfn_to_page(pfn);
-               if (!PageReserved(page))
-                       balloon_append(page);
+               /* totalram_pages doesn't include the boot-time
+                  balloon extension, so don't subtract from it. */
+               __balloon_append(page);
        }
 
        target_watch.callback = watch_target;
index 97612f548a8e821c82821cb84218917dce136d03..2811bb988ea0551b85bc4c77d15b8590382abdf4 100644 (file)
@@ -278,17 +278,17 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
        cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
 #endif
 
-       __clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
-       __set_bit(chn, cpu_evtchn_mask(cpu));
+       clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
+       set_bit(chn, cpu_evtchn_mask(cpu));
 
        irq_info[irq].cpu = cpu;
 }
 
 static void init_evtchn_cpu_bindings(void)
 {
+       int i;
 #ifdef CONFIG_SMP
        struct irq_desc *desc;
-       int i;
 
        /* By default all event channels notify CPU#0. */
        for_each_irq_desc(i, desc) {
@@ -296,7 +296,10 @@ static void init_evtchn_cpu_bindings(void)
        }
 #endif
 
-       memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
+       for_each_possible_cpu(i)
+               memset(cpu_evtchn_mask(i),
+                      (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s));
+
 }
 
 static inline void clear_evtchn(int port)
@@ -752,7 +755,7 @@ int xen_destroy_irq(int irq)
                goto out;
 
        if (xen_initial_domain()) {
-               unmap_irq.pirq = info->u.pirq.gsi;
+               unmap_irq.pirq = info->u.pirq.pirq;
                unmap_irq.domid = DOMID_SELF;
                rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
                if (rc) {
@@ -1299,9 +1302,6 @@ static void restore_cpu_virqs(unsigned int cpu)
                evtchn_to_irq[evtchn] = irq;
                irq_info[irq] = mk_virq_info(evtchn, virq);
                bind_evtchn_to_cpu(evtchn, cpu);
-
-               /* Ready for use. */
-               unmask_evtchn(evtchn);
        }
 }
 
@@ -1327,10 +1327,6 @@ static void restore_cpu_ipis(unsigned int cpu)
                evtchn_to_irq[evtchn] = irq;
                irq_info[irq] = mk_ipi_info(evtchn, ipi);
                bind_evtchn_to_cpu(evtchn, cpu);
-
-               /* Ready for use. */
-               unmask_evtchn(evtchn);
-
        }
 }
 
@@ -1390,6 +1386,7 @@ void xen_poll_irq(int irq)
 void xen_irq_resume(void)
 {
        unsigned int cpu, irq, evtchn;
+       struct irq_desc *desc;
 
        init_evtchn_cpu_bindings();
 
@@ -1408,6 +1405,23 @@ void xen_irq_resume(void)
                restore_cpu_virqs(cpu);
                restore_cpu_ipis(cpu);
        }
+
+       /*
+        * Unmask any IRQF_NO_SUSPEND IRQs which are enabled. These
+        * are not handled by the IRQ core.
+        */
+       for_each_irq_desc(irq, desc) {
+               if (!desc->action || !(desc->action->flags & IRQF_NO_SUSPEND))
+                       continue;
+               if (desc->status & IRQ_DISABLED)
+                       continue;
+
+               evtchn = evtchn_from_irq(irq);
+               if (evtchn == -1)
+                       continue;
+
+               unmask_evtchn(evtchn);
+       }
 }
 
 static struct irq_chip xen_dynamic_chip __read_mostly = {
index fec6ba3c08a8e885d663ce3ac9c8b031ff971273..ef11daf0cafe9f086f3944b42fd32ff48811f4b2 100644 (file)
@@ -69,20 +69,51 @@ struct per_user_data {
        const char *name;
 };
 
-/* Who's bound to each port? */
-static struct per_user_data *port_user[NR_EVENT_CHANNELS];
+/*
+ * Who's bound to each port?  This is logically an array of struct
+ * per_user_data *, but we encode the current enabled-state in bit 0.
+ */
+static unsigned long *port_user;
 static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
 
-irqreturn_t evtchn_interrupt(int irq, void *data)
+static inline struct per_user_data *get_port_user(unsigned port)
+{
+       return (struct per_user_data *)(port_user[port] & ~1);
+}
+
+static inline void set_port_user(unsigned port, struct per_user_data *u)
+{
+       port_user[port] = (unsigned long)u;
+}
+
+static inline bool get_port_enabled(unsigned port)
+{
+       return port_user[port] & 1;
+}
+
+static inline void set_port_enabled(unsigned port, bool enabled)
+{
+       if (enabled)
+               port_user[port] |= 1;
+       else
+               port_user[port] &= ~1;
+}
+
+static irqreturn_t evtchn_interrupt(int irq, void *data)
 {
        unsigned int port = (unsigned long)data;
        struct per_user_data *u;
 
        spin_lock(&port_user_lock);
 
-       u = port_user[port];
+       u = get_port_user(port);
+
+       WARN(!get_port_enabled(port),
+            "Interrupt for port %d, but apparently not enabled; per-user %p\n",
+            port, u);
 
        disable_irq_nosync(irq);
+       set_port_enabled(port, false);
 
        if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
                u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
@@ -92,9 +123,8 @@ irqreturn_t evtchn_interrupt(int irq, void *data)
                        kill_fasync(&u->evtchn_async_queue,
                                    SIGIO, POLL_IN);
                }
-       } else {
+       } else
                u->ring_overflow = 1;
-       }
 
        spin_unlock(&port_user_lock);
 
@@ -198,9 +228,18 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
                goto out;
 
        spin_lock_irq(&port_user_lock);
-       for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
-               if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
-                       enable_irq(irq_from_evtchn(kbuf[i]));
+
+       for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
+               unsigned port = kbuf[i];
+
+               if (port < NR_EVENT_CHANNELS &&
+                   get_port_user(port) == u &&
+                   !get_port_enabled(port)) {
+                       set_port_enabled(port, true);
+                       enable_irq(irq_from_evtchn(port));
+               }
+       }
+
        spin_unlock_irq(&port_user_lock);
 
        rc = count;
@@ -222,8 +261,9 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
         * interrupt handler yet, and our caller has already
         * serialized bind operations.)
         */
-       BUG_ON(port_user[port] != NULL);
-       port_user[port] = u;
+       BUG_ON(get_port_user(port) != NULL);
+       set_port_user(port, u);
+       set_port_enabled(port, true); /* start enabled */
 
        rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
                                       u->name, (void *)(unsigned long)port);
@@ -239,10 +279,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, int port)
 
        unbind_from_irqhandler(irq, (void *)(unsigned long)port);
 
-       /* make sure we unbind the irq handler before clearing the port */
-       barrier();
-
-       port_user[port] = NULL;
+       set_port_user(port, NULL);
 }
 
 static long evtchn_ioctl(struct file *file,
@@ -333,15 +370,17 @@ static long evtchn_ioctl(struct file *file,
                spin_lock_irq(&port_user_lock);
 
                rc = -ENOTCONN;
-               if (port_user[unbind.port] != u) {
+               if (get_port_user(unbind.port) != u) {
                        spin_unlock_irq(&port_user_lock);
                        break;
                }
 
-               evtchn_unbind_from_user(u, unbind.port);
+               disable_irq(irq_from_evtchn(unbind.port));
 
                spin_unlock_irq(&port_user_lock);
 
+               evtchn_unbind_from_user(u, unbind.port);
+
                rc = 0;
                break;
        }
@@ -355,7 +394,7 @@ static long evtchn_ioctl(struct file *file,
 
                if (notify.port >= NR_EVENT_CHANNELS) {
                        rc = -EINVAL;
-               } else if (port_user[notify.port] != u) {
+               } else if (get_port_user(notify.port) != u) {
                        rc = -ENOTCONN;
                } else {
                        notify_remote_via_evtchn(notify.port);
@@ -431,7 +470,7 @@ static int evtchn_open(struct inode *inode, struct file *filp)
 
        filp->private_data = u;
 
-       return 0;
+       return nonseekable_open(inode, filp);;
 }
 
 static int evtchn_release(struct inode *inode, struct file *filp)
@@ -444,14 +483,21 @@ static int evtchn_release(struct inode *inode, struct file *filp)
        free_page((unsigned long)u->ring);
 
        for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-               if (port_user[i] != u)
+               if (get_port_user(i) != u)
                        continue;
 
-               evtchn_unbind_from_user(port_user[i], i);
+               disable_irq(irq_from_evtchn(i));
        }
 
        spin_unlock_irq(&port_user_lock);
 
+       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+               if (get_port_user(i) != u)
+                       continue;
+
+               evtchn_unbind_from_user(get_port_user(i), i);
+       }
+
        kfree(u->name);
        kfree(u);
 
@@ -467,12 +513,12 @@ static const struct file_operations evtchn_fops = {
        .fasync  = evtchn_fasync,
        .open    = evtchn_open,
        .release = evtchn_release,
-       .llseek = noop_llseek,
+       .llseek  = no_llseek,
 };
 
 static struct miscdevice evtchn_miscdev = {
        .minor        = MISC_DYNAMIC_MINOR,
-       .name         = "evtchn",
+       .name         = "xen/evtchn",
        .fops         = &evtchn_fops,
 };
 static int __init evtchn_init(void)
@@ -482,8 +528,11 @@ static int __init evtchn_init(void)
        if (!xen_domain())
                return -ENODEV;
 
+       port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL);
+       if (port_user == NULL)
+               return -ENOMEM;
+
        spin_lock_init(&port_user_lock);
-       memset(port_user, 0, sizeof(port_user));
 
        /* Create '/dev/misc/evtchn'. */
        err = misc_register(&evtchn_miscdev);
@@ -499,6 +548,9 @@ static int __init evtchn_init(void)
 
 static void __exit evtchn_cleanup(void)
 {
+       kfree(port_user);
+       port_user = NULL;
+
        misc_deregister(&evtchn_miscdev);
 }
 
index f80be7f6eb95265d223a40f2166bc29b6fb8d3c6..dbd3b16fd1317adc9f1fa8afedfd0e6d3fc53400 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/mman.h>
 #include <linux/uaccess.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
@@ -266,9 +265,7 @@ static int mmap_return_errors(void *data, void *state)
        xen_pfn_t *mfnp = data;
        struct mmap_batch_state *st = state;
 
-       put_user(*mfnp, st->user++);
-
-       return 0;
+       return put_user(*mfnp, st->user++);
 }
 
 static struct vm_operations_struct privcmd_vm_ops;
@@ -323,10 +320,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata)
        up_write(&mm->mmap_sem);
 
        if (state.err > 0) {
-               ret = 0;
-
                state.user = m.arr;
-               traverse_pages(m.num, sizeof(xen_pfn_t),
+               ret = traverse_pages(m.num, sizeof(xen_pfn_t),
                               &pagelist,
                               mmap_return_errors, &state);
        }
@@ -384,8 +379,9 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return -ENOSYS;
 
-       /* DONTCOPY is essential for Xen as copy_page_range is broken. */
-       vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
+       /* DONTCOPY is essential for Xen because copy_page_range doesn't know
+        * how to recreate these mappings */
+       vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
        vma->vm_ops = &privcmd_vm_ops;
        vma->vm_private_data = NULL;
 
index f6339d11d59cbdebc8d558f552cc199175003e05..1aa3897198462112a3bc1db479986653cf0a716f 100644 (file)
@@ -12,8 +12,6 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/magic.h>
-#include <linux/mm.h>
-#include <linux/backing-dev.h>
 
 #include <xen/xen.h>
 
 MODULE_DESCRIPTION("Xen filesystem");
 MODULE_LICENSE("GPL");
 
-static int xenfs_set_page_dirty(struct page *page)
-{
-       return !TestSetPageDirty(page);
-}
-
-static const struct address_space_operations xenfs_aops = {
-       .set_page_dirty = xenfs_set_page_dirty,
-};
-
-static struct backing_dev_info xenfs_backing_dev_info = {
-       .ra_pages       = 0,    /* No readahead */
-       .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK,
-};
-
 static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
 {
        struct inode *ret = new_inode(sb);
 
        if (ret) {
                ret->i_mode = mode;
-               ret->i_mapping->a_ops = &xenfs_aops;
-               ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
                ret->i_uid = ret->i_gid = 0;
                ret->i_blocks = 0;
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
@@ -121,9 +103,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
        return rc;
 }
 
-static int xenfs_mount(struct file_system_type *fs_type,
-                       int flags, const char *dev_name,
-                       void *data)
+static struct dentry *xenfs_mount(struct file_system_type *fs_type,
+                                 int flags, const char *dev_name,
+                                 void *data)
 {
        return mount_single(fs_type, flags, data, xenfs_fill_super);
 }
@@ -137,25 +119,11 @@ static struct file_system_type xenfs_type = {
 
 static int __init xenfs_init(void)
 {
-       int err;
-       if (!xen_domain()) {
-               printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
-               return 0;
-       }
-
-       err = register_filesystem(&xenfs_type);
-       if (err) {
-               printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
-               goto out;
-       }
-
-       err = bdi_init(&xenfs_backing_dev_info);
-       if (err)
-               unregister_filesystem(&xenfs_type);
-
- out:
+       if (xen_domain())
+               return register_filesystem(&xenfs_type);
 
-       return err;
+       printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
+       return 0;
 }
 
 static void __exit xenfs_exit(void)
index cafc504542927751f25650ce2ea2639dcdbc8bef..e0c84725d3e94e05a33482349dc90f45f59099a9 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/amigahw.h>
 #include <asm/setup.h>
index 8abb2dfb2e7c8b006f9c80b716808a1ff07a0189..4bd454fa844e3efc8c44755c7ea9847477f813ff 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -370,6 +370,9 @@ struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
 {
        struct bio *bio;
 
+       if (nr_iovecs > UIO_MAXIOV)
+               return NULL;
+
        bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec),
                      gfp_mask);
        if (unlikely(!bio))
@@ -697,8 +700,12 @@ static void bio_free_map_data(struct bio_map_data *bmd)
 static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
                                               gfp_t gfp_mask)
 {
-       struct bio_map_data *bmd = kmalloc(sizeof(*bmd), gfp_mask);
+       struct bio_map_data *bmd;
 
+       if (iov_count > UIO_MAXIOV)
+               return NULL;
+
+       bmd = kmalloc(sizeof(*bmd), gfp_mask);
        if (!bmd)
                return NULL;
 
@@ -827,6 +834,12 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
                end = (uaddr + iov[i].iov_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
                start = uaddr >> PAGE_SHIFT;
 
+               /*
+                * Overflow, abort
+                */
+               if (end < start)
+                       return ERR_PTR(-EINVAL);
+
                nr_pages += end - start;
                len += iov[i].iov_len;
        }
@@ -955,6 +968,12 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
                unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
                unsigned long start = uaddr >> PAGE_SHIFT;
 
+               /*
+                * Overflow, abort
+                */
+               if (end < start)
+                       return ERR_PTR(-EINVAL);
+
                nr_pages += end - start;
                /*
                 * buffer must be aligned to at least hardsector size for now
@@ -982,7 +1001,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
                unsigned long start = uaddr >> PAGE_SHIFT;
                const int local_nr_pages = end - start;
                const int page_limit = cur_page + local_nr_pages;
-               
+
                ret = get_user_pages_fast(uaddr, local_nr_pages,
                                write_to_vm, &pages[cur_page]);
                if (ret < local_nr_pages) {
index 06e8ff12b97c8fa74d4b2eb05c900801b3adb150..4230252fd6895c97cb81541741f9e8e584e04322 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/major.h>
-#include <linux/smp_lock.h>
 #include <linux/device_cgroup.h>
 #include <linux/highmem.h>
 #include <linux/blkdev.h>
index e9c874abc9e1f4a7ec00b68595fdd674a4f1da2e..561438b6a50cd3789b90d54e473562431d528ec8 100644 (file)
@@ -204,7 +204,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
        err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
                                  page->index << PAGE_CACHE_SHIFT, &len,
                                  ci->i_truncate_seq, ci->i_truncate_size,
-                                 &page, 1);
+                                 &page, 1, 0);
        if (err == -ENOENT)
                err = 0;
        if (err < 0) {
@@ -287,7 +287,7 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
        rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
                                 offset, &len,
                                 ci->i_truncate_seq, ci->i_truncate_size,
-                                pages, nr_pages);
+                                pages, nr_pages, 0);
        if (rc == -ENOENT)
                rc = 0;
        if (rc < 0)
@@ -774,7 +774,7 @@ get_more_pages:
                                            snapc, do_sync,
                                            ci->i_truncate_seq,
                                            ci->i_truncate_size,
-                                           &inode->i_mtime, true, 1);
+                                           &inode->i_mtime, true, 1, 0);
                                max_pages = req->r_num_pages;
 
                                alloc_page_vec(fsc, req);
index 98ab13e2b71d9d8ebcbf1715da112d78cb0bac17..60d27bc9eb83d82f61e448031495625e42c752d3 100644 (file)
@@ -1430,8 +1430,8 @@ static int try_nonblocking_invalidate(struct inode *inode)
            invalidating_gen == ci->i_rdcache_gen) {
                /* success. */
                dout("try_nonblocking_invalidate %p success\n", inode);
-               ci->i_rdcache_gen = 0;
-               ci->i_rdcache_revoking = 0;
+               /* save any racing async invalidate some trouble */
+               ci->i_rdcache_revoking = ci->i_rdcache_gen - 1;
                return 0;
        }
        dout("try_nonblocking_invalidate %p failed\n", inode);
@@ -2273,8 +2273,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
        int mds = session->s_mds;
-       unsigned seq = le32_to_cpu(grant->seq);
-       unsigned issue_seq = le32_to_cpu(grant->issue_seq);
+       int seq = le32_to_cpu(grant->seq);
        int newcaps = le32_to_cpu(grant->caps);
        int issued, implemented, used, wanted, dirty;
        u64 size = le64_to_cpu(grant->size);
@@ -2286,8 +2285,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        int revoked_rdcache = 0;
        int queue_invalidate = 0;
 
-       dout("handle_cap_grant inode %p cap %p mds%d seq %u/%u %s\n",
-            inode, cap, mds, seq, issue_seq, ceph_cap_string(newcaps));
+       dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
+            inode, cap, mds, seq, ceph_cap_string(newcaps));
        dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
                inode->i_size);
 
@@ -2383,7 +2382,6 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        }
 
        cap->seq = seq;
-       cap->issue_seq = issue_seq;
 
        /* file layout may have changed */
        ci->i_layout = grant->layout;
@@ -2691,6 +2689,11 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
                     NULL /* no caps context */);
        try_flush_caps(inode, session, NULL);
        up_read(&mdsc->snap_rwsem);
+
+       /* make sure we re-request max_size, if necessary */
+       spin_lock(&inode->i_lock);
+       ci->i_requested_max_size = 0;
+       spin_unlock(&inode->i_lock);
 }
 
 /*
index e0a2dc6fcafcb62266909c5ec71329e58083d1d7..7d447af84ec4861acee8cd82bcecf80a892132b1 100644 (file)
@@ -336,7 +336,10 @@ more:
                if (req->r_reply_info.dir_end) {
                        kfree(fi->last_name);
                        fi->last_name = NULL;
-                       fi->next_offset = 2;
+                       if (ceph_frag_is_rightmost(frag))
+                               fi->next_offset = 2;
+                       else
+                               fi->next_offset = 0;
                } else {
                        rinfo = &req->r_reply_info;
                        err = note_last_dentry(fi,
@@ -355,18 +358,22 @@ more:
                u64 pos = ceph_make_fpos(frag, off);
                struct ceph_mds_reply_inode *in =
                        rinfo->dir_in[off - fi->offset].in;
+               struct ceph_vino vino;
+               ino_t ino;
+
                dout("readdir off %d (%d/%d) -> %lld '%.*s' %p\n",
                     off, off - fi->offset, rinfo->dir_nr, pos,
                     rinfo->dir_dname_len[off - fi->offset],
                     rinfo->dir_dname[off - fi->offset], in);
                BUG_ON(!in);
                ftype = le32_to_cpu(in->mode) >> 12;
+               vino.ino = le64_to_cpu(in->ino);
+               vino.snap = le64_to_cpu(in->snapid);
+               ino = ceph_vino_to_ino(vino);
                if (filldir(dirent,
                            rinfo->dir_dname[off - fi->offset],
                            rinfo->dir_dname_len[off - fi->offset],
-                           pos,
-                           le64_to_cpu(in->ino),
-                           ftype) < 0) {
+                           pos, ino, ftype) < 0) {
                        dout("filldir stopping us...\n");
                        return 0;
                }
@@ -414,6 +421,7 @@ static void reset_readdir(struct ceph_file_info *fi)
                fi->last_readdir = NULL;
        }
        kfree(fi->last_name);
+       fi->last_name = NULL;
        fi->next_offset = 2;  /* compensate for . and .. */
        if (fi->dentry) {
                dput(fi->dentry);
index e77c28cf369059112dd06ee3b7c78c5146f0ffdc..8d79b8912e31e4cb8fcb4961ec1f81d63c3d5070 100644 (file)
@@ -154,11 +154,13 @@ int ceph_open(struct inode *inode, struct file *file)
        }
 
        /*
-        * No need to block if we have any caps.  Update wanted set
+        * No need to block if we have caps on the auth MDS (for
+        * write) or any MDS (for read).  Update wanted set
         * asynchronously.
         */
        spin_lock(&inode->i_lock);
-       if (__ceph_is_any_real_caps(ci)) {
+       if (__ceph_is_any_real_caps(ci) &&
+           (((fmode & CEPH_FILE_MODE_WR) == 0) || ci->i_auth_cap)) {
                int mds_wanted = __ceph_caps_mds_wanted(ci);
                int issued = __ceph_caps_issued(ci, NULL);
 
@@ -280,11 +282,12 @@ int ceph_release(struct inode *inode, struct file *file)
 static int striped_read(struct inode *inode,
                        u64 off, u64 len,
                        struct page **pages, int num_pages,
-                       int *checkeof)
+                       int *checkeof, bool align_to_pages)
 {
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_inode_info *ci = ceph_inode(inode);
        u64 pos, this_len;
+       int io_align, page_align;
        int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */
        int left, pages_left;
        int read;
@@ -300,14 +303,19 @@ static int striped_read(struct inode *inode,
        page_pos = pages;
        pages_left = num_pages;
        read = 0;
+       io_align = off & ~PAGE_MASK;
 
 more:
+       if (align_to_pages)
+               page_align = (pos - io_align) & ~PAGE_MASK;
+       else
+               page_align = pos & ~PAGE_MASK;
        this_len = left;
        ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode),
                                  &ci->i_layout, pos, &this_len,
                                  ci->i_truncate_seq,
                                  ci->i_truncate_size,
-                                 page_pos, pages_left);
+                                 page_pos, pages_left, page_align);
        hit_stripe = this_len < left;
        was_short = ret >= 0 && ret < this_len;
        if (ret == -ENOENT)
@@ -374,26 +382,25 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data,
        dout("sync_read on file %p %llu~%u %s\n", file, off, len,
             (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
 
-       if (file->f_flags & O_DIRECT) {
-               pages = ceph_get_direct_page_vector(data, num_pages, off, len);
-
-               /*
-                * flush any page cache pages in this range.  this
-                * will make concurrent normal and O_DIRECT io slow,
-                * but it will at least behave sensibly when they are
-                * in sequence.
-                */
-       } else {
+       if (file->f_flags & O_DIRECT)
+               pages = ceph_get_direct_page_vector(data, num_pages);
+       else
                pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
-       }
        if (IS_ERR(pages))
                return PTR_ERR(pages);
 
+       /*
+        * flush any page cache pages in this range.  this
+        * will make concurrent normal and sync io slow,
+        * but it will at least behave sensibly when they are
+        * in sequence.
+        */
        ret = filemap_write_and_wait(inode->i_mapping);
        if (ret < 0)
                goto done;
 
-       ret = striped_read(inode, off, len, pages, num_pages, checkeof);
+       ret = striped_read(inode, off, len, pages, num_pages, checkeof,
+                          file->f_flags & O_DIRECT);
 
        if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
                ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
@@ -448,6 +455,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
        int flags;
        int do_sync = 0;
        int check_caps = 0;
+       int page_align, io_align;
        int ret;
        struct timespec mtime = CURRENT_TIME;
 
@@ -462,6 +470,8 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
        else
                pos = *offset;
 
+       io_align = pos & ~PAGE_MASK;
+
        ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left);
        if (ret < 0)
                return ret;
@@ -486,20 +496,26 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
         */
 more:
        len = left;
+       if (file->f_flags & O_DIRECT)
+               /* write from beginning of first page, regardless of
+                  io alignment */
+               page_align = (pos - io_align) & ~PAGE_MASK;
+       else
+               page_align = pos & ~PAGE_MASK;
        req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
                                    ceph_vino(inode), pos, &len,
                                    CEPH_OSD_OP_WRITE, flags,
                                    ci->i_snap_realm->cached_context,
                                    do_sync,
                                    ci->i_truncate_seq, ci->i_truncate_size,
-                                   &mtime, false, 2);
+                                   &mtime, false, 2, page_align);
        if (!req)
                return -ENOMEM;
 
        num_pages = calc_pages_for(pos, len);
 
        if (file->f_flags & O_DIRECT) {
-               pages = ceph_get_direct_page_vector(data, num_pages, pos, len);
+               pages = ceph_get_direct_page_vector(data, num_pages);
                if (IS_ERR(pages)) {
                        ret = PTR_ERR(pages);
                        goto out;
index 1d6a45b5a04c696591879d141165627746d6a476..bf1286588f26b3afb039e4036ddb2a469fcad638 100644 (file)
@@ -2,7 +2,6 @@
 
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/uaccess.h>
@@ -471,7 +470,9 @@ void ceph_fill_file_time(struct inode *inode, int issued,
 
        if (issued & (CEPH_CAP_FILE_EXCL|
                      CEPH_CAP_FILE_WR|
-                     CEPH_CAP_FILE_BUFFER)) {
+                     CEPH_CAP_FILE_BUFFER|
+                     CEPH_CAP_AUTH_EXCL|
+                     CEPH_CAP_XATTR_EXCL)) {
                if (timespec_compare(ctime, &inode->i_ctime) > 0) {
                        dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n",
                             inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
@@ -511,7 +512,7 @@ void ceph_fill_file_time(struct inode *inode, int issued,
                        warn = 1;
                }
        } else {
-               /* we have no write caps; whatever the MDS says is true */
+               /* we have no write|excl caps; whatever the MDS says is true */
                if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) {
                        inode->i_ctime = *ctime;
                        inode->i_mtime = *mtime;
@@ -567,12 +568,17 @@ static int fill_inode(struct inode *inode,
 
        /*
         * provided version will be odd if inode value is projected,
-        * even if stable.  skip the update if we have a newer info
-        * (e.g., due to inode info racing form multiple MDSs), or if
-        * we are getting projected (unstable) inode info.
+        * even if stable.  skip the update if we have newer stable
+        * info (ours>=theirs, e.g. due to racing mds replies), unless
+        * we are getting projected (unstable) info (in which case the
+        * version is odd, and we want ours>theirs).
+        *   us   them
+        *   2    2     skip
+        *   3    2     skip
+        *   3    3     update
         */
        if (le64_to_cpu(info->version) > 0 &&
-           (ci->i_version & ~1) > le64_to_cpu(info->version))
+           (ci->i_version & ~1) >= le64_to_cpu(info->version))
                goto no_change;
 
        issued = __ceph_caps_issued(ci, &implemented);
@@ -606,7 +612,14 @@ static int fill_inode(struct inode *inode,
                            le32_to_cpu(info->time_warp_seq),
                            &ctime, &mtime, &atime);
 
-       ci->i_max_size = le64_to_cpu(info->max_size);
+       /* only update max_size on auth cap */
+       if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) &&
+           ci->i_max_size != le64_to_cpu(info->max_size)) {
+               dout("max_size %lld -> %llu\n", ci->i_max_size,
+                    le64_to_cpu(info->max_size));
+               ci->i_max_size = le64_to_cpu(info->max_size);
+       }
+
        ci->i_layout = info->layout;
        inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
 
@@ -1055,7 +1068,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                ininfo = rinfo->targeti.in;
                vino.ino = le64_to_cpu(ininfo->ino);
                vino.snap = le64_to_cpu(ininfo->snapid);
-               if (!dn->d_inode) {
+               in = dn->d_inode;
+               if (!in) {
                        in = ceph_get_inode(sb, vino);
                        if (IS_ERR(in)) {
                                pr_err("fill_trace bad get_inode "
@@ -1386,11 +1400,8 @@ static void ceph_invalidate_work(struct work_struct *work)
        spin_lock(&inode->i_lock);
        dout("invalidate_pages %p gen %d revoking %d\n", inode,
             ci->i_rdcache_gen, ci->i_rdcache_revoking);
-       if (ci->i_rdcache_gen == 0 ||
-           ci->i_rdcache_revoking != ci->i_rdcache_gen) {
-               BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen);
+       if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
                /* nevermind! */
-               ci->i_rdcache_revoking = 0;
                spin_unlock(&inode->i_lock);
                goto out;
        }
@@ -1400,15 +1411,16 @@ static void ceph_invalidate_work(struct work_struct *work)
        ceph_invalidate_nondirty_pages(inode->i_mapping);
 
        spin_lock(&inode->i_lock);
-       if (orig_gen == ci->i_rdcache_gen) {
+       if (orig_gen == ci->i_rdcache_gen &&
+           orig_gen == ci->i_rdcache_revoking) {
                dout("invalidate_pages %p gen %d successful\n", inode,
                     ci->i_rdcache_gen);
-               ci->i_rdcache_gen = 0;
-               ci->i_rdcache_revoking = 0;
+               ci->i_rdcache_revoking--;
                check = 1;
        } else {
-               dout("invalidate_pages %p gen %d raced, gen now %d\n",
-                    inode, orig_gen, ci->i_rdcache_gen);
+               dout("invalidate_pages %p gen %d raced, now %d revoking %d\n",
+                    inode, orig_gen, ci->i_rdcache_gen,
+                    ci->i_rdcache_revoking);
        }
        spin_unlock(&inode->i_lock);
 
@@ -1739,7 +1751,7 @@ int ceph_do_getattr(struct inode *inode, int mask)
                return 0;
        }
 
-       dout("do_getattr inode %p mask %s\n", inode, ceph_cap_string(mask));
+       dout("do_getattr inode %p mask %s mode 0%o\n", inode, ceph_cap_string(mask), inode->i_mode);
        if (ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
                return 0;
 
index 3142b15940c25656a43ec3a5d72af3e1ee1cece9..098b185084791730ba0143111126bc066fdb9afb 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/sched.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -529,6 +528,9 @@ static void __register_request(struct ceph_mds_client *mdsc,
        ceph_mdsc_get_request(req);
        __insert_request(mdsc, req);
 
+       req->r_uid = current_fsuid();
+       req->r_gid = current_fsgid();
+
        if (dir) {
                struct ceph_inode_info *ci = ceph_inode(dir);
 
@@ -1588,8 +1590,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
 
        head->mdsmap_epoch = cpu_to_le32(mdsc->mdsmap->m_epoch);
        head->op = cpu_to_le32(req->r_op);
-       head->caller_uid = cpu_to_le32(current_fsuid());
-       head->caller_gid = cpu_to_le32(current_fsgid());
+       head->caller_uid = cpu_to_le32(req->r_uid);
+       head->caller_gid = cpu_to_le32(req->r_gid);
        head->args = req->r_args;
 
        ceph_encode_filepath(&p, end, ino1, path1);
index d66d63c7235526ef63d16ff0ea1e9ba3899df586..9341fd4f14320060a395c37f81b4a67b01c020d7 100644 (file)
@@ -170,6 +170,8 @@ struct ceph_mds_request {
 
        union ceph_mds_request_args r_args;
        int r_fmode;        /* file mode, if expecting cap */
+       uid_t r_uid;
+       gid_t r_gid;
 
        /* for choosing which mds to send this request to */
        int r_direct_mode;
index 1886294e12f7a3106c00f3376d92e43330514081..7f01728a46571f2fa22a47fbd062f6eadf4cba83 100644 (file)
@@ -293,9 +293,7 @@ struct ceph_inode_info {
        int i_rd_ref, i_rdcache_ref, i_wr_ref;
        int i_wrbuffer_ref, i_wrbuffer_ref_head;
        u32 i_shared_gen;       /* increment each time we get FILE_SHARED */
-       u32 i_rdcache_gen;      /* we increment this each time we get
-                                  FILE_CACHE.  If it's non-zero, we
-                                  _may_ have cached pages. */
+       u32 i_rdcache_gen;      /* incremented each time we get FILE_CACHE. */
        u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
 
        struct list_head i_unsafe_writes; /* uncommitted sync writes */
index 5aff46c61e521cbaef027b92d1a4bdd7bb86c547..355abcdcda980acfcd70dcb54d4bb798edf6fcae 100644 (file)
@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for
 
 v) mount check for unmatched uids
 
-w) Add support for new vfs entry points for setlease and fallocate 
+w) Add support for new vfs entry point for fallocate
 
 x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
 processes can proceed better in parallel (on the server)
index 525ba59a41058a6d13f4311fb841eb2604a00140..e9a393c9c2ca4ddb8ec3d75cfcf0766234ec1789 100644 (file)
@@ -15,7 +15,7 @@
  *   the GNU Lesser General Public License for more details.
  *
  */
-#include <linux/radix-tree.h>
+#include <linux/rbtree.h>
 
 #ifndef _CIFS_FS_SB_H
 #define _CIFS_FS_SB_H
@@ -42,9 +42,9 @@
 #define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
 
 struct cifs_sb_info {
-       struct radix_tree_root tlink_tree;
-#define CIFS_TLINK_MASTER_TAG          0       /* is "master" (mount) tcon */
+       struct rb_root tlink_tree;
        spinlock_t tlink_tree_lock;
+       struct tcon_link *master_tlink;
        struct nls_table *local_nls;
        unsigned int rsize;
        unsigned int wsize;
index 75c4eaa7958821483c6829658ab6469a8ad8c152..9c3789762ab7c4c92a7d67859c34b32cb196f1ab 100644 (file)
@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data,
                return -ENOMEM;
 
        spin_lock_init(&cifs_sb->tlink_tree_lock);
-       INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL);
+       cifs_sb->tlink_tree = RB_ROOT;
 
        rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
        if (rc) {
@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb)
        /* Until the file is open and we have gotten oplock
        info back from the server, can not assume caching of
        file data or metadata */
-       cifs_inode->clientCanCacheRead = false;
-       cifs_inode->clientCanCacheAll = false;
+       cifs_set_oplock_level(cifs_inode, 0);
        cifs_inode->delete_pending = false;
        cifs_inode->invalid_mapping = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
index f259e4d7612d5f2a50f70f6b65802b4fff01621c..b577bf0a1bb3622491ed0a885ca30b9e7684d24e 100644 (file)
@@ -336,7 +336,8 @@ struct cifsTconInfo {
  * "get" on the container.
  */
 struct tcon_link {
-       unsigned long           tl_index;
+       struct rb_node          tl_rbnode;
+       uid_t                   tl_uid;
        unsigned long           tl_flags;
 #define TCON_LINK_MASTER       0
 #define TCON_LINK_PENDING      1
index edb6d90efdf27ac2272c961c7269fbbfab2c0aa7..7ed69b6b5fe6719f66ed5af0a0b38d2cda1aa352 100644 (file)
@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
                                      int offset);
+extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
 extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
                                struct file *file, struct tcon_link *tlink,
index 9eb327defa1d39fc16d1c8f0837de36a65e43c92..251a17c03545dfc35e8ab37e1ea5a612e94f7536 100644 (file)
@@ -116,6 +116,7 @@ struct smb_vol {
 
 static int ipv4_connect(struct TCP_Server_Info *server);
 static int ipv6_connect(struct TCP_Server_Info *server);
+static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
 static void cifs_prune_tlinks(struct work_struct *work);
 
 /*
@@ -2900,24 +2901,16 @@ remote_path_check:
                goto mount_fail_check;
        }
 
-       tlink->tl_index = pSesInfo->linux_uid;
+       tlink->tl_uid = pSesInfo->linux_uid;
        tlink->tl_tcon = tcon;
        tlink->tl_time = jiffies;
        set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
        set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
 
-       rc = radix_tree_preload(GFP_KERNEL);
-       if (rc == -ENOMEM) {
-               kfree(tlink);
-               goto mount_fail_check;
-       }
-
+       cifs_sb->master_tlink = tlink;
        spin_lock(&cifs_sb->tlink_tree_lock);
-       radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
-       radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
-                          CIFS_TLINK_MASTER_TAG);
+       tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
-       radix_tree_preload_end();
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 int
 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 {
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node;
+       struct tcon_link *tlink;
        char *tmp;
-       struct tcon_link *tlink[8];
-       unsigned long index = 0;
 
        cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                                       tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       while ((node = rb_first(root))) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(node, root);
 
-               for (i = 0; i < ret; i++)
-                       cifs_put_tlink(tlink[i]);
-       } while (ret != 0);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        tmp = cifs_sb->prepath;
        cifs_sb->prepathlen = 0;
@@ -3271,22 +3257,10 @@ out:
        return tcon;
 }
 
-static struct tcon_link *
+static inline struct tcon_link *
 cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
 {
-       struct tcon_link *tlink;
-       unsigned int ret;
-
-       spin_lock(&cifs_sb->tlink_tree_lock);
-       ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
-                                       0, 1, CIFS_TLINK_MASTER_TAG);
-       spin_unlock(&cifs_sb->tlink_tree_lock);
-
-       /* the master tcon should always be present */
-       if (ret == 0)
-               BUG();
-
-       return tlink;
+       return cifs_sb->master_tlink;
 }
 
 struct cifsTconInfo *
@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused)
        return signal_pending(current) ? -ERESTARTSYS : 0;
 }
 
+/* find and return a tlink with given uid */
+static struct tcon_link *
+tlink_rb_search(struct rb_root *root, uid_t uid)
+{
+       struct rb_node *node = root->rb_node;
+       struct tcon_link *tlink;
+
+       while (node) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+
+               if (tlink->tl_uid > uid)
+                       node = node->rb_left;
+               else if (tlink->tl_uid < uid)
+                       node = node->rb_right;
+               else
+                       return tlink;
+       }
+       return NULL;
+}
+
+/* insert a tcon_link into the tree */
+static void
+tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct tcon_link *tlink;
+
+       while (*new) {
+               tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
+               parent = *new;
+
+               if (tlink->tl_uid > new_tlink->tl_uid)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&new_tlink->tl_rbnode, parent, new);
+       rb_insert_color(&new_tlink->tl_rbnode, root);
+}
+
 /*
  * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
  * current task.
@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused)
  * If the superblock doesn't refer to a multiuser mount, then just return
  * the master tcon for the mount.
  *
- * First, search the radix tree for an existing tcon for this fsuid. If one
+ * First, search the rbtree for an existing tcon for this fsuid. If one
  * exists, then check to see if it's pending construction. If it is then wait
  * for construction to complete. Once it's no longer pending, check to see if
  * it failed and either return an error or retry construction, depending on
@@ -3322,14 +3337,14 @@ struct tcon_link *
 cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
 {
        int ret;
-       unsigned long fsuid = (unsigned long) current_fsuid();
+       uid_t fsuid = current_fsuid();
        struct tcon_link *tlink, *newtlink;
 
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
 
        spin_lock(&cifs_sb->tlink_tree_lock);
-       tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+       tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
        if (tlink)
                cifs_get_tlink(tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
                newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
                if (newtlink == NULL)
                        return ERR_PTR(-ENOMEM);
-               newtlink->tl_index = fsuid;
+               newtlink->tl_uid = fsuid;
                newtlink->tl_tcon = ERR_PTR(-EACCES);
                set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
                set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
                cifs_get_tlink(newtlink);
 
-               ret = radix_tree_preload(GFP_KERNEL);
-               if (ret != 0) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
-
                spin_lock(&cifs_sb->tlink_tree_lock);
                /* was one inserted after previous search? */
-               tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+               tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
                if (tlink) {
                        cifs_get_tlink(tlink);
                        spin_unlock(&cifs_sb->tlink_tree_lock);
-                       radix_tree_preload_end();
                        kfree(newtlink);
                        goto wait_for_construction;
                }
-               ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
-               spin_unlock(&cifs_sb->tlink_tree_lock);
-               radix_tree_preload_end();
-               if (ret) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
                tlink = newtlink;
+               tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
        } else {
 wait_for_construction:
                ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work)
 {
        struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
                                                    prune_tlinks.work);
-       struct tcon_link *tlink[8];
-       unsigned long now = jiffies;
-       unsigned long index = 0;
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node = rb_first(root);
+       struct rb_node *tmp;
+       struct tcon_link *tlink;
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
-                           atomic_read(&tlink[i]->tl_count) != 0 ||
-                           time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
-                                      now)) {
-                               tlink[i] = NULL;
-                               continue;
-                       }
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                         tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       /*
+        * Because we drop the spinlock in the loop in order to put the tlink
+        * it's not guarded against removal of links from the tree. The only
+        * places that remove entries from the tree are this function and
+        * umounts. Because this function is non-reentrant and is canceled
+        * before umount can proceed, this is safe.
+        */
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       node = rb_first(root);
+       while (node != NULL) {
+               tmp = node;
+               node = rb_next(tmp);
+               tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
+
+               if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
+                   atomic_read(&tlink->tl_count) != 0 ||
+                   time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
+                       continue;
 
-               for (i = 0; i < ret; i++) {
-                       if (tlink[i] != NULL)
-                               cifs_put_tlink(tlink[i]);
-               }
-       } while (ret != 0);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(tmp, root);
+
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
index ae82159cf7fa6921bb3a27a1fc5e56fbb1045a5c..06c3e83fa387fecf63b93e33a0455dac6da45f6d 100644 (file)
@@ -146,12 +146,7 @@ client_can_cache:
                rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
                                         xid, NULL);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        return rc;
 }
@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
                list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
        spin_unlock(&cifs_file_list_lock);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        file->private_data = pCifsFile;
        return pCifsFile;
@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
  */
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
+       struct inode *inode = cifs_file->dentry->d_inode;
        struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
-       struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifsLockInfo *li, *tmp;
 
        spin_lock(&cifs_file_list_lock);
@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        if (list_empty(&cifsi->openFileList)) {
                cFYI(1, "closing last open instance for inode %p",
                        cifs_file->dentry->d_inode);
-               cifsi->clientCanCacheRead = false;
-               cifsi->clientCanCacheAll  = false;
+               cifs_set_oplock_level(cifsi, 0);
        }
        spin_unlock(&cifs_file_list_lock);
 
@@ -607,8 +597,6 @@ reopen_success:
                rc = filemap_write_and_wait(inode->i_mapping);
                mapping_set_error(inode->i_mapping, rc);
 
-               pCifsInode->clientCanCacheAll = false;
-               pCifsInode->clientCanCacheRead = false;
                if (tcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&inode,
                                full_path, inode->i_sb, xid);
@@ -622,18 +610,9 @@ reopen_success:
             invalidate the current end of file on the server
             we can not go to the server to get the new inod
             info */
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p",
-                        pCifsFile->dentry->d_inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ) {
-               pCifsInode->clientCanCacheRead = true;
-               pCifsInode->clientCanCacheAll = false;
-       } else {
-               pCifsInode->clientCanCacheRead = false;
-               pCifsInode->clientCanCacheAll = false;
-       }
+
+       cifs_set_oplock_level(pCifsInode, oplock);
+
        cifs_relock_file(pCifsFile);
 
 reopen_error_exit:
@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
-
-       if (file->private_data == NULL) {
-               rc = -EBADF;
-               FreeXid(xid);
-               return rc;
-       }
        netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        size_t write_size, loff_t *poffset)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        int rc = 0;
        unsigned int bytes_written = 0;
        unsigned int total_written;
@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        struct cifsTconInfo *pTcon;
        int xid, long_op;
        struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
        cifs_stats_bytes_written(pTcon, total_written);
 
-       /* since the write may have blocked check these pointers again */
-       if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
-               struct inode *inode = file->f_path.dentry->d_inode;
 /* Do not update local mtime - server will set its actual value on write
- *             inode->i_ctime = inode->i_mtime =
- *                     current_fs_time(inode->i_sb);*/
-               if (total_written > 0) {
-                       spin_lock(&inode->i_lock);
-                       if (*poffset > file->f_path.dentry->d_inode->i_size)
-                               i_size_write(file->f_path.dentry->d_inode,
-                                       *poffset);
-                       spin_unlock(&inode->i_lock);
-               }
-               mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ *     inode->i_ctime = inode->i_mtime =
+ *             current_fs_time(inode->i_sb);*/
+       if (total_written > 0) {
+               spin_lock(&inode->i_lock);
+               if (*poffset > inode->i_size)
+                       i_size_write(inode, *poffset);
+               spin_unlock(&inode->i_lock);
        }
+       mark_inode_dirty_sync(inode);
+
        FreeXid(xid);
        return total_written;
 }
@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
 {
        struct cifsFileInfo *open_file;
-       struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+       struct cifs_sb_info *cifs_sb;
        bool any_available = false;
        int rc;
 
@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                return NULL;
        }
 
+       cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
        /* only filter by fsuid on multiuser mounts */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
index 39869c3c3efbc2a08b87ba6661e48ace7e9789eb..ef3a55bf86b6d3700c521e074954548c6f53223f 100644 (file)
@@ -2177,7 +2177,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        setattr_copy(inode, attrs);
        mark_inode_dirty(inode);
-       return 0;
 
 cifs_setattr_exit:
        kfree(full_path);
index 077bf756f34231300c6b0d7fdae7cedf6023bd08..0c98672d01225ccadb67bb09705e7c21922332c7 100644 (file)
@@ -38,10 +38,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
        struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
        struct cifsFileInfo *pSMBFile = filep->private_data;
-       struct cifsTconInfo *tcon = tlink_tcon(pSMBFile->tlink);
+       struct cifsTconInfo *tcon;
        __u64   ExtAttrBits = 0;
        __u64   ExtAttrMask = 0;
-       __u64   caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       __u64   caps;
 #endif /* CONFIG_CIFS_POSIX */
 
        xid = GetXid();
@@ -62,9 +62,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        break;
 #ifdef CONFIG_CIFS_POSIX
                case FS_IOC_GETFLAGS:
+                       if (pSMBFile == NULL)
+                               break;
+                       tcon = tlink_tcon(pSMBFile->tlink);
+                       caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
-                               if (pSMBFile == NULL)
-                                       break;
                                rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
                                        &ExtAttrBits, &ExtAttrMask);
                                if (rc == 0)
@@ -75,13 +77,15 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        break;
 
                case FS_IOC_SETFLAGS:
+                       if (pSMBFile == NULL)
+                               break;
+                       tcon = tlink_tcon(pSMBFile->tlink);
+                       caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
                                if (get_user(ExtAttrBits, (int __user *)arg)) {
                                        rc = -EFAULT;
                                        break;
                                }
-                               if (pSMBFile == NULL)
-                                       break;
                                /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
                                        extAttrBits, &ExtAttrMask);*/
                        }
index c4e296fe351876252a48210f81f6cbae165562f8..43f10281bc19e80be48303e1bd9c974b4882cb37 100644 (file)
@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                cFYI(1, "file id match, oplock break");
                                pCifsInode = CIFS_I(netfile->dentry->d_inode);
-                               pCifsInode->clientCanCacheAll = false;
-                               if (pSMB->OplockLevel == 0)
-                                       pCifsInode->clientCanCacheRead = false;
 
+                               cifs_set_oplock_level(pCifsInode,
+                                                     pSMB->OplockLevel);
                                /*
                                 * cifs_oplock_break_put() can't be called
                                 * from here.  Get reference after queueing
@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
                           cifs_sb_master_tcon(cifs_sb)->treeName);
        }
 }
+
+void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       oplock &= 0xF;
+
+       if (oplock == OPLOCK_EXCLUSIVE) {
+               cinode->clientCanCacheAll = true;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock granted on inode %p",
+                    &cinode->vfs_inode);
+       } else if (oplock == OPLOCK_READ) {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Level II Oplock granted on inode %p",
+                   &cinode->vfs_inode);
+       } else {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = false;
+       }
+}
index 410ed188faa1376b7b0b10ed5bff0c36aa9c8806..a60579b007b03f38160ea541b099ab7a914bfbc1 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/if.h>
 #include <linux/if_bridge.h>
index 253732382d375e848edc61ca40a3eaadb60f80c7..2720178b7718a9335a28d7ed4b0422ab11d6331f 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/key.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/crypto.h>
 #include "ecryptfs_kernel.h"
index 2fedaf8b50125bf65ad9b550537742de3109ecd4..acf8695fa8f035935390dd6bc0c8e44e8d3e5961 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/parser.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/exportfs.h>
 #include <linux/vfs.h>
index 8b5dd6369f82c19d5ba28dea07018e4fb13a025f..6a5edea2d70b3ac7c56e8b272686b5a799eabbcf 100644 (file)
@@ -177,7 +177,7 @@ struct mpage_da_data {
 
 struct ext4_io_page {
        struct page     *p_page;
-       int             p_count;
+       atomic_t        p_count;
 };
 
 #define MAX_IO_PAGES 128
@@ -858,6 +858,7 @@ struct ext4_inode_info {
        spinlock_t i_completed_io_lock;
        /* current io_end structure for async DIO write*/
        ext4_io_end_t *cur_aio_dio;
+       atomic_t i_ioend_count; /* Number of outstanding io_end structs */
 
        /*
         * Transactions that contain inode's metadata needed to complete
@@ -2060,6 +2061,7 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
 /* page-io.c */
 extern int __init ext4_init_pageio(void);
 extern void ext4_exit_pageio(void);
+extern void ext4_ioend_wait(struct inode *);
 extern void ext4_free_io_end(ext4_io_end_t *io);
 extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
 extern int ext4_end_io_nolock(ext4_io_end_t *io);
index 1916164704667dc3c190ab327781933fa7c5f4b8..bdbe69902207c151df025d98690c4c016cf0b0e9 100644 (file)
@@ -53,6 +53,7 @@
 static inline int ext4_begin_ordered_truncate(struct inode *inode,
                                              loff_t new_size)
 {
+       trace_ext4_begin_ordered_truncate(inode, new_size);
        return jbd2_journal_begin_ordered_truncate(
                                        EXT4_SB(inode->i_sb)->s_journal,
                                        &EXT4_I(inode)->jinode,
@@ -178,6 +179,7 @@ void ext4_evict_inode(struct inode *inode)
        handle_t *handle;
        int err;
 
+       trace_ext4_evict_inode(inode);
        if (inode->i_nlink) {
                truncate_inode_pages(&inode->i_data, 0);
                goto no_delete;
@@ -5410,9 +5412,7 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
         * will return the blocks that include the delayed allocation
         * blocks for this file.
         */
-       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        delalloc_blocks = EXT4_I(inode)->i_reserved_data_blocks;
-       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
        stat->blocks += (delalloc_blocks << inode->i_sb->s_blocksize_bits)>>9;
        return 0;
@@ -5649,6 +5649,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
        int err, ret;
 
        might_sleep();
+       trace_ext4_mark_inode_dirty(inode, _RET_IP_);
        err = ext4_reserve_inode_write(handle, inode, &iloc);
        if (ext4_handle_valid(handle) &&
            EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
index bf5ae883b1bdc30ff55cbc616bab7c24f9d57dbb..eb3bc2fe647e710de889f04da3afaf5821e00556 100644 (file)
@@ -331,6 +331,30 @@ mext_out:
                return err;
        }
 
+       case FITRIM:
+       {
+               struct super_block *sb = inode->i_sb;
+               struct fstrim_range range;
+               int ret = 0;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+
+               if (copy_from_user(&range, (struct fstrim_range *)arg,
+                   sizeof(range)))
+                       return -EFAULT;
+
+               ret = ext4_trim_fs(sb, &range);
+               if (ret < 0)
+                       return ret;
+
+               if (copy_to_user((struct fstrim_range *)arg, &range,
+                   sizeof(range)))
+                       return -EFAULT;
+
+               return 0;
+       }
+
        default:
                return -ENOTTY;
        }
index c58eba34724a4281f1cb8bb405ab607ef09b49ff..5b4d4e3a4d58e3506c15e891e7b8df394bc0838f 100644 (file)
@@ -4640,8 +4640,6 @@ do_more:
                 * with group lock held. generate_buddy look at
                 * them with group lock_held
                 */
-               if (test_opt(sb, DISCARD))
-                       ext4_issue_discard(sb, block_group, bit, count);
                ext4_lock_group(sb, block_group);
                mb_clear_bits(bitmap_bh->b_data, bit, count);
                mb_free_blocks(inode, &e4b, bit, count);
index 46a7d6a9d9764b82075071c94f661cc65c3675fc..beacce11ac506ff3dd9958d1a3f82db095a36468 100644 (file)
 
 static struct kmem_cache *io_page_cachep, *io_end_cachep;
 
+#define WQ_HASH_SZ             37
+#define to_ioend_wq(v) (&ioend_wq[((unsigned long)v) % WQ_HASH_SZ])
+static wait_queue_head_t ioend_wq[WQ_HASH_SZ];
+
 int __init ext4_init_pageio(void)
 {
+       int i;
+
        io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
        if (io_page_cachep == NULL)
                return -ENOMEM;
@@ -42,6 +48,8 @@ int __init ext4_init_pageio(void)
                kmem_cache_destroy(io_page_cachep);
                return -ENOMEM;
        }
+       for (i = 0; i < WQ_HASH_SZ; i++)
+               init_waitqueue_head(&ioend_wq[i]);
 
        return 0;
 }
@@ -52,24 +60,37 @@ void ext4_exit_pageio(void)
        kmem_cache_destroy(io_page_cachep);
 }
 
+void ext4_ioend_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = to_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
+}
+
+static void put_io_page(struct ext4_io_page *io_page)
+{
+       if (atomic_dec_and_test(&io_page->p_count)) {
+               end_page_writeback(io_page->p_page);
+               put_page(io_page->p_page);
+               kmem_cache_free(io_page_cachep, io_page);
+       }
+}
+
 void ext4_free_io_end(ext4_io_end_t *io)
 {
        int i;
+       wait_queue_head_t *wq;
 
        BUG_ON(!io);
        if (io->page)
                put_page(io->page);
-       for (i = 0; i < io->num_io_pages; i++) {
-               if (--io->pages[i]->p_count == 0) {
-                       struct page *page = io->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io->pages[i]);
-               }
-       }
+       for (i = 0; i < io->num_io_pages; i++)
+               put_io_page(io->pages[i]);
        io->num_io_pages = 0;
-       iput(io->inode);
+       wq = to_ioend_wq(io->inode);
+       if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
+           waitqueue_active(wq))
+               wake_up_all(wq);
        kmem_cache_free(io_end_cachep, io);
 }
 
@@ -142,8 +163,8 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
        io = kmem_cache_alloc(io_end_cachep, flags);
        if (io) {
                memset(io, 0, sizeof(*io));
-               io->inode = igrab(inode);
-               BUG_ON(!io->inode);
+               atomic_inc(&EXT4_I(inode)->i_ioend_count);
+               io->inode = inode;
                INIT_WORK(&io->work, ext4_end_io_work);
                INIT_LIST_HEAD(&io->list);
        }
@@ -171,35 +192,15 @@ static void ext4_end_bio(struct bio *bio, int error)
        struct workqueue_struct *wq;
        struct inode *inode;
        unsigned long flags;
-       ext4_fsblk_t err_block;
        int i;
 
        BUG_ON(!io_end);
-       inode = io_end->inode;
        bio->bi_private = NULL;
        bio->bi_end_io = NULL;
        if (test_bit(BIO_UPTODATE, &bio->bi_flags))
                error = 0;
-       err_block = bio->bi_sector >> (inode->i_blkbits - 9);
        bio_put(bio);
 
-       if (!(inode->i_sb->s_flags & MS_ACTIVE)) {
-               pr_err("sb umounted, discard end_io request for inode %lu\n",
-                       io_end->inode->i_ino);
-               ext4_free_io_end(io_end);
-               return;
-       }
-
-       if (error) {
-               io_end->flag |= EXT4_IO_END_ERROR;
-               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
-                            "(offset %llu size %ld starting block %llu)",
-                            inode->i_ino,
-                            (unsigned long long) io_end->offset,
-                            (long) io_end->size,
-                            (unsigned long long) err_block);
-       }
-
        for (i = 0; i < io_end->num_io_pages; i++) {
                struct page *page = io_end->pages[i]->p_page;
                struct buffer_head *bh, *head;
@@ -236,14 +237,6 @@ static void ext4_end_bio(struct bio *bio, int error)
                        } while (bh != head);
                }
 
-               if (--io_end->pages[i]->p_count == 0) {
-                       struct page *page = io_end->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io_end->pages[i]);
-               }
-
                /*
                 * If this is a partial write which happened to make
                 * all buffers uptodate then we can optimize away a
@@ -253,9 +246,22 @@ static void ext4_end_bio(struct bio *bio, int error)
                 */
                if (!partial_write)
                        SetPageUptodate(page);
-       }
 
+               put_io_page(io_end->pages[i]);
+       }
        io_end->num_io_pages = 0;
+       inode = io_end->inode;
+
+       if (error) {
+               io_end->flag |= EXT4_IO_END_ERROR;
+               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
+                            "(offset %llu size %ld starting block %llu)",
+                            inode->i_ino,
+                            (unsigned long long) io_end->offset,
+                            (long) io_end->size,
+                            (unsigned long long)
+                            bio->bi_sector >> (inode->i_blkbits - 9));
+       }
 
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
@@ -305,7 +311,6 @@ static int io_submit_init(struct ext4_io_submit *io,
        bio->bi_private = io->io_end = io_end;
        bio->bi_end_io = ext4_end_bio;
 
-       io_end->inode = inode;
        io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
 
        io->io_bio = bio;
@@ -360,7 +365,7 @@ submit_and_retry:
        if ((io_end->num_io_pages == 0) ||
            (io_end->pages[io_end->num_io_pages-1] != io_page)) {
                io_end->pages[io_end->num_io_pages++] = io_page;
-               io_page->p_count++;
+               atomic_inc(&io_page->p_count);
        }
        return 0;
 }
@@ -389,7 +394,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
                return -ENOMEM;
        }
        io_page->p_page = page;
-       io_page->p_count = 0;
+       atomic_set(&io_page->p_count, 1);
        get_page(page);
 
        for (bh = head = page_buffers(page), block_start = 0;
@@ -421,10 +426,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
         * PageWriteback bit from the page to prevent the system from
         * wedging later on.
         */
-       if (io_page->p_count == 0) {
-               put_page(page);
-               end_page_writeback(page);
-               kmem_cache_free(io_page_cachep, io_page);
-       }
+       put_io_page(io_page);
        return ret;
 }
index 40131b777af66c3112bb1df16265faadac435d0f..e32195d6aac34656b13a5619c3750e8b30586c08 100644 (file)
@@ -828,12 +828,22 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->cur_aio_dio = NULL;
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
+       atomic_set(&ei->i_ioend_count, 0);
 
        return &ei->vfs_inode;
 }
 
+static int ext4_drop_inode(struct inode *inode)
+{
+       int drop = generic_drop_inode(inode);
+
+       trace_ext4_drop_inode(inode, drop);
+       return drop;
+}
+
 static void ext4_destroy_inode(struct inode *inode)
 {
+       ext4_ioend_wait(inode);
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
                ext4_msg(inode->i_sb, KERN_ERR,
                         "Inode %lu (%p): orphan list check failed!",
@@ -1173,6 +1183,7 @@ static const struct super_operations ext4_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .put_super      = ext4_put_super,
        .sync_fs        = ext4_sync_fs,
@@ -1186,7 +1197,6 @@ static const struct super_operations ext4_sops = {
        .quota_write    = ext4_quota_write,
 #endif
        .bdev_try_to_free_page = bdev_try_to_free_page,
-       .trim_fs        = ext4_trim_fs
 };
 
 static const struct super_operations ext4_nojournal_sops = {
@@ -1194,6 +1204,7 @@ static const struct super_operations ext4_nojournal_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .write_super    = ext4_write_super,
        .put_super      = ext4_put_super,
@@ -2699,7 +2710,6 @@ static int ext4_lazyinit_thread(void *arg)
        struct ext4_li_request *elr;
        unsigned long next_wakeup;
        DEFINE_WAIT(wait);
-       int ret;
 
        BUG_ON(NULL == eli);
 
@@ -2723,13 +2733,12 @@ cont_thread:
                        elr = list_entry(pos, struct ext4_li_request,
                                         lr_request);
 
-                       if (time_after_eq(jiffies, elr->lr_next_sched))
-                               ret = ext4_run_li_request(elr);
-
-                       if (ret) {
-                               ret = 0;
-                               ext4_remove_li_request(elr);
-                               continue;
+                       if (time_after_eq(jiffies, elr->lr_next_sched)) {
+                               if (ext4_run_li_request(elr) != 0) {
+                                       /* error, remove the lazy_init job */
+                                       ext4_remove_li_request(elr);
+                                       continue;
+                               }
                        }
 
                        if (time_before(elr->lr_next_sched, next_wakeup))
@@ -2740,7 +2749,8 @@ cont_thread:
                if (freezing(current))
                        refrigerator();
 
-               if (time_after_eq(jiffies, next_wakeup)) {
+               if ((time_after_eq(jiffies, next_wakeup)) ||
+                   (MAX_JIFFY_OFFSET == next_wakeup)) {
                        cond_resched();
                        continue;
                }
@@ -2788,9 +2798,6 @@ static void ext4_clear_request_list(void)
        struct ext4_li_request *elr;
 
        mutex_lock(&ext4_li_info->li_list_mtx);
-       if (list_empty(&ext4_li_info->li_request_list))
-               return;
-
        list_for_each_safe(pos, n, &ext4_li_info->li_request_list) {
                elr = list_entry(pos, struct ext4_li_request,
                                 lr_request);
@@ -3257,13 +3264,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * Test whether we have more sectors than will fit in sector_t,
         * and whether the max offset is addressable by the page cache.
         */
-       ret = generic_check_addressable(sb->s_blocksize_bits,
+       err = generic_check_addressable(sb->s_blocksize_bits,
                                        ext4_blocks_count(es));
-       if (ret) {
+       if (err) {
                ext4_msg(sb, KERN_ERR, "filesystem"
                         " too large to mount safely on this system");
                if (sizeof(sector_t) < 8)
                        ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled");
+               ret = err;
                goto failed_mount;
        }
 
@@ -3348,6 +3356,24 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                       ext4_count_free_blocks(sb));
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                               ext4_count_free_inodes(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                               ext4_count_dirs(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       }
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
+               goto failed_mount3;
+       }
+
        sbi->s_stripe = ext4_get_stripe_size(sbi);
        sbi->s_max_writeback_mb_bump = 128;
 
@@ -3446,22 +3472,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
-no_journal:
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                                 ext4_count_free_blocks(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                                         ext4_count_free_inodes(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                                         ext4_count_dirs(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "insufficient memory");
-               goto failed_mount_wq;
-       }
+       /*
+        * The journal may have updated the bg summary counts, so we
+        * need to update the global counters.
+        */
+       percpu_counter_set(&sbi->s_freeblocks_counter,
+                          ext4_count_free_blocks(sb));
+       percpu_counter_set(&sbi->s_freeinodes_counter,
+                          ext4_count_free_inodes(sb));
+       percpu_counter_set(&sbi->s_dirs_counter,
+                          ext4_count_dirs(sb));
+       percpu_counter_set(&sbi->s_dirtyblocks_counter, 0);
 
+no_journal:
        EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
@@ -3611,10 +3634,6 @@ failed_mount_wq:
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
-       percpu_counter_destroy(&sbi->s_freeblocks_counter);
-       percpu_counter_destroy(&sbi->s_freeinodes_counter);
-       percpu_counter_destroy(&sbi->s_dirs_counter);
-       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount3:
        if (sbi->s_flex_groups) {
                if (is_vmalloc_addr(sbi->s_flex_groups))
@@ -3622,6 +3641,10 @@ failed_mount3:
                else
                        kfree(sbi->s_flex_groups);
        }
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -3949,13 +3972,11 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        else
                es->s_kbytes_written =
                        cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
-               ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeblocks_counter));
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
-               es->s_free_inodes_count =
-                       cpu_to_le32(percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeinodes_counter));
+       ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
+                                          &EXT4_SB(sb)->s_freeblocks_counter));
+       es->s_free_inodes_count =
+               cpu_to_le32(percpu_counter_sum_positive(
+                               &EXT4_SB(sb)->s_freeinodes_counter));
        sb->s_dirt = 0;
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
@@ -4556,12 +4577,10 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
 
 static int ext4_quota_off(struct super_block *sb, int type)
 {
-       /* Force all delayed allocation blocks to be allocated */
-       if (test_opt(sb, DELALLOC)) {
-               down_read(&sb->s_umount);
+       /* Force all delayed allocation blocks to be allocated.
+        * Caller already holds s_umount sem */
+       if (test_opt(sb, DELALLOC))
                sync_filesystem(sb);
-               up_read(&sb->s_umount);
-       }
 
        return dquot_quota_off(sb, type);
 }
index 06d582732d3427a058864d03ca6cb667c5063481..5ab3839dfcb97719d3b9e2f96e99062eef3b3c5f 100644 (file)
@@ -138,10 +138,8 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
                                      struct gfs2_inum_host *inum)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       struct gfs2_holder i_gh;
        struct inode *inode;
        struct dentry *dentry;
-       int error;
 
        inode = gfs2_ilookup(sb, inum->no_addr);
        if (inode) {
@@ -152,52 +150,16 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb,
                goto out_inode;
        }
 
-       error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
-                                 LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
-       if (error)
-               return ERR_PTR(error);
-
-       error = gfs2_check_blk_type(sdp, inum->no_addr, GFS2_BLKST_DINODE);
-       if (error)
-               goto fail;
-
-       inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0);
-       if (IS_ERR(inode)) {
-               error = PTR_ERR(inode);
-               goto fail;
-       }
-
-       error = gfs2_inode_refresh(GFS2_I(inode));
-       if (error) {
-               iput(inode);
-               goto fail;
-       }
-
-       /* Pick up the works we bypass in gfs2_inode_lookup */
-       if (inode->i_state & I_NEW) 
-               gfs2_set_iop(inode);
-
-       if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
-               iput(inode);
-               goto fail;
-       }
-
-       error = -EIO;
-       if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) {
-               iput(inode);
-               goto fail;
-       }
-
-       gfs2_glock_dq_uninit(&i_gh);
+       inode = gfs2_lookup_by_inum(sdp, inum->no_addr, &inum->no_formal_ino,
+                                   GFS2_BLKST_DINODE);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
 
 out_inode:
        dentry = d_obtain_alias(inode);
        if (!IS_ERR(dentry))
                dentry->d_op = &gfs2_dops;
        return dentry;
-fail:
-       gfs2_glock_dq_uninit(&i_gh);
-       return ERR_PTR(error);
 }
 
 static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
index 87778857f0994fa504224d93c7c5611d10bc1e8c..f92c1770416981df8b625b6f918bac6c061c6e5e 100644 (file)
@@ -686,21 +686,20 @@ static void delete_work_func(struct work_struct *work)
 {
        struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
        struct gfs2_sbd *sdp = gl->gl_sbd;
-       struct gfs2_inode *ip = NULL;
+       struct gfs2_inode *ip;
        struct inode *inode;
-       u64 no_addr = 0;
+       u64 no_addr = gl->gl_name.ln_number;
+
+       ip = gl->gl_object;
+       /* Note: Unsafe to dereference ip as we don't hold right refs/locks */
 
-       spin_lock(&gl->gl_spin);
-       ip = (struct gfs2_inode *)gl->gl_object;
        if (ip)
-               no_addr = ip->i_no_addr;
-       spin_unlock(&gl->gl_spin);
-       if (ip) {
                inode = gfs2_ilookup(sdp->sd_vfs, no_addr);
-               if (inode) {
-                       d_prune_aliases(inode);
-                       iput(inode);
-               }
+       else
+               inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED);
+       if (inode && !IS_ERR(inode)) {
+               d_prune_aliases(inode);
+               iput(inode);
        }
        gfs2_glock_put(gl);
 }
index 06370f8bd8cf4aafa95fd4df64e93ec8d657328d..e1213f7f92179aa2472304ff0db4294be66040d8 100644 (file)
@@ -73,49 +73,6 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
        return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);
 }
 
-struct gfs2_skip_data {
-       u64     no_addr;
-       int     skipped;
-};
-
-static int iget_skip_test(struct inode *inode, void *opaque)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_skip_data *data = opaque;
-
-       if (ip->i_no_addr == data->no_addr) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE)){
-                       data->skipped = 1;
-                       return 0;
-               }
-               return 1;
-       }
-       return 0;
-}
-
-static int iget_skip_set(struct inode *inode, void *opaque)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_skip_data *data = opaque;
-
-       if (data->skipped)
-               return 1;
-       inode->i_ino = (unsigned long)(data->no_addr);
-       ip->i_no_addr = data->no_addr;
-       return 0;
-}
-
-static struct inode *gfs2_iget_skip(struct super_block *sb,
-                                   u64 no_addr)
-{
-       struct gfs2_skip_data data;
-       unsigned long hash = (unsigned long)no_addr;
-
-       data.no_addr = no_addr;
-       data.skipped = 0;
-       return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data);
-}
-
 /**
  * GFS2 lookup code fills in vfs inode contents based on info obtained
  * from directory entry inside gfs2_inode_lookup(). This has caused issues
@@ -243,93 +200,54 @@ fail:
        return ERR_PTR(error);
 }
 
-/**
- * gfs2_process_unlinked_inode - Lookup an unlinked inode for reclamation
- *                               and try to reclaim it by doing iput.
- *
- * This function assumes no rgrp locks are currently held.
- *
- * @sb: The super block
- * no_addr: The inode number
- *
- */
-
-void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr)
+struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
+                                 u64 *no_formal_ino, unsigned int blktype)
 {
-       struct gfs2_sbd *sdp;
-       struct gfs2_inode *ip;
-       struct gfs2_glock *io_gl = NULL;
-       int error;
-       struct gfs2_holder gh;
+       struct super_block *sb = sdp->sd_vfs;
+       struct gfs2_holder i_gh;
        struct inode *inode;
+       int error;
 
-       inode = gfs2_iget_skip(sb, no_addr);
-
-       if (!inode)
-               return;
-
-       /* If it's not a new inode, someone's using it, so leave it alone. */
-       if (!(inode->i_state & I_NEW)) {
-               iput(inode);
-               return;
-       }
-
-       ip = GFS2_I(inode);
-       sdp = GFS2_SB(inode);
-       ip->i_no_formal_ino = -1;
+       error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops,
+                                 LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+       if (error)
+               return ERR_PTR(error);
 
-       error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
-       if (unlikely(error))
+       error = gfs2_check_blk_type(sdp, no_addr, blktype);
+       if (error)
                goto fail;
-       ip->i_gl->gl_object = ip;
 
-       error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
-       if (unlikely(error))
-               goto fail_put;
-
-       set_bit(GIF_INVALID, &ip->i_flags);
-       error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, LM_FLAG_TRY | GL_EXACT,
-                                  &ip->i_iopen_gh);
-       if (unlikely(error))
-               goto fail_iopen;
+       inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0);
+       if (IS_ERR(inode))
+               goto fail;
 
-       ip->i_iopen_gh.gh_gl->gl_object = ip;
-       gfs2_glock_put(io_gl);
-       io_gl = NULL;
+       error = gfs2_inode_refresh(GFS2_I(inode));
+       if (error)
+               goto fail_iput;
 
-       inode->i_mode = DT2IF(DT_UNKNOWN);
+       /* Pick up the works we bypass in gfs2_inode_lookup */
+       if (inode->i_state & I_NEW) 
+               gfs2_set_iop(inode);
 
-       /*
-        * We must read the inode in order to work out its type in
-        * this case. Note that this doesn't happen often as we normally
-        * know the type beforehand. This code path only occurs during
-        * unlinked inode recovery (where it is safe to do this glock,
-        * which is not true in the general case).
-        */
-       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY,
-                                  &gh);
-       if (unlikely(error))
-               goto fail_glock;
+       /* Two extra checks for NFS only */
+       if (no_formal_ino) {
+               error = -ESTALE;
+               if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino)
+                       goto fail_iput;
 
-       /* Inode is now uptodate */
-       gfs2_glock_dq_uninit(&gh);
-       gfs2_set_iop(inode);
+               error = -EIO;
+               if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM)
+                       goto fail_iput;
 
-       /* The iput will cause it to be deleted. */
-       iput(inode);
-       return;
+               error = 0;
+       }
 
-fail_glock:
-       gfs2_glock_dq(&ip->i_iopen_gh);
-fail_iopen:
-       if (io_gl)
-               gfs2_glock_put(io_gl);
-fail_put:
-       ip->i_gl->gl_object = NULL;
-       gfs2_glock_put(ip->i_gl);
 fail:
-       iget_failed(inode);
-       return;
+       gfs2_glock_dq_uninit(&i_gh);
+       return error ? ERR_PTR(error) : inode;
+fail_iput:
+       iput(inode);
+       goto fail;
 }
 
 static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
index 6720d7d5fbc6aac91083b399b95ba6c978922c67..d8499fadcc53915837a8ae7e7bdcc77213f825cc 100644 (file)
@@ -99,7 +99,9 @@ err:
 extern void gfs2_set_iop(struct inode *inode);
 extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
                                       u64 no_addr, u64 no_formal_ino);
-extern void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr);
+extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
+                                        u64 *no_formal_ino,
+                                        unsigned int blktype);
 extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
 
 extern int gfs2_inode_refresh(struct gfs2_inode *ip);
index bef3ab6cf5c1aeb2d0f28d7955e4e62c8cb34be2..33c8407b876f00ceef0741221ebae4ba46ecb426 100644 (file)
@@ -963,17 +963,18 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
  *          The inode, if one has been found, in inode.
  */
 
-static u64 try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
-                          u64 skip)
+static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip)
 {
        u32 goal = 0, block;
        u64 no_addr;
        struct gfs2_sbd *sdp = rgd->rd_sbd;
        unsigned int n;
+       struct gfs2_glock *gl;
+       struct gfs2_inode *ip;
+       int error;
+       int found = 0;
 
-       for(;;) {
-               if (goal >= rgd->rd_data)
-                       break;
+       while (goal < rgd->rd_data) {
                down_write(&sdp->sd_log_flush_lock);
                n = 1;
                block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
@@ -990,11 +991,32 @@ static u64 try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked,
                if (no_addr == skip)
                        continue;
                *last_unlinked = no_addr;
-               return no_addr;
+
+               error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &gl);
+               if (error)
+                       continue;
+
+               /* If the inode is already in cache, we can ignore it here
+                * because the existing inode disposal code will deal with
+                * it when all refs have gone away. Accessing gl_object like
+                * this is not safe in general. Here it is ok because we do
+                * not dereference the pointer, and we only need an approx
+                * answer to whether it is NULL or not.
+                */
+               ip = gl->gl_object;
+
+               if (ip || queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0)
+                       gfs2_glock_put(gl);
+               else
+                       found++;
+
+               /* Limit reclaim to sensible number of tasks */
+               if (found > 2*NR_CPUS)
+                       return;
        }
 
        rgd->rd_flags &= ~GFS2_RDF_CHECK;
-       return 0;
+       return;
 }
 
 /**
@@ -1075,11 +1097,9 @@ static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
  * Try to acquire rgrp in way which avoids contending with others.
  *
  * Returns: errno
- *          unlinked: the block address of an unlinked block to be reclaimed
  */
 
-static int get_local_rgrp(struct gfs2_inode *ip, u64 *unlinked,
-                         u64 *last_unlinked)
+static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrpd *rgd, *begin = NULL;
@@ -1089,7 +1109,6 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *unlinked,
        int loops = 0;
        int error, rg_locked;
 
-       *unlinked = 0;
        rgd = gfs2_blk2rgrpd(sdp, ip->i_goal);
 
        while (rgd) {
@@ -1106,17 +1125,10 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *unlinked,
                case 0:
                        if (try_rgrp_fit(rgd, al))
                                goto out;
-                       /* If the rg came in already locked, there's no
-                          way we can recover from a failed try_rgrp_unlink
-                          because that would require an iput which can only
-                          happen after the rgrp is unlocked. */
-                       if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK)
-                               *unlinked = try_rgrp_unlink(rgd, last_unlinked,
-                                                          ip->i_no_addr);
+                       if (rgd->rd_flags & GFS2_RDF_CHECK)
+                               try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
                        if (!rg_locked)
                                gfs2_glock_dq_uninit(&al->al_rgd_gh);
-                       if (*unlinked)
-                               return -EAGAIN;
                        /* fall through */
                case GLR_TRYFAILED:
                        rgd = recent_rgrp_next(rgd);
@@ -1145,13 +1157,10 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *unlinked,
                case 0:
                        if (try_rgrp_fit(rgd, al))
                                goto out;
-                       if (!rg_locked && rgd->rd_flags & GFS2_RDF_CHECK)
-                               *unlinked = try_rgrp_unlink(rgd, last_unlinked,
-                                                           ip->i_no_addr);
+                       if (rgd->rd_flags & GFS2_RDF_CHECK)
+                               try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr);
                        if (!rg_locked)
                                gfs2_glock_dq_uninit(&al->al_rgd_gh);
-                       if (*unlinked)
-                               return -EAGAIN;
                        break;
 
                case GLR_TRYFAILED:
@@ -1204,12 +1213,12 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = ip->i_alloc;
        int error = 0;
-       u64 last_unlinked = NO_BLOCK, unlinked;
+       u64 last_unlinked = NO_BLOCK;
+       int tries = 0;
 
        if (gfs2_assert_warn(sdp, al->al_requested))
                return -EINVAL;
 
-try_again:
        if (hold_rindex) {
                /* We need to hold the rindex unless the inode we're using is
                   the rindex itself, in which case it's already held. */
@@ -1218,31 +1227,23 @@ try_again:
                else if (!sdp->sd_rgrps) /* We may not have the rindex read
                                            in, so: */
                        error = gfs2_ri_update_special(ip);
+               if (error)
+                       return error;
        }
 
-       if (error)
-               return error;
+       do {
+               error = get_local_rgrp(ip, &last_unlinked);
+               /* If there is no space, flushing the log may release some */
+               if (error)
+                       gfs2_log_flush(sdp, NULL);
+       } while (error && tries++ < 3);
 
-       /* Find an rgrp suitable for allocation.  If it encounters any unlinked
-          dinodes along the way, error will equal -EAGAIN and unlinked will
-          contains it block address. We then need to look up that inode and
-          try to free it, and try the allocation again. */
-       error = get_local_rgrp(ip, &unlinked, &last_unlinked);
        if (error) {
                if (hold_rindex && ip != GFS2_I(sdp->sd_rindex))
                        gfs2_glock_dq_uninit(&al->al_ri_gh);
-               if (error != -EAGAIN)
-                       return error;
-
-               gfs2_process_unlinked_inode(ip->i_inode.i_sb, unlinked);
-               /* regardless of whether or not gfs2_process_unlinked_inode
-                  was successful, we don't want to repeat it again. */
-               last_unlinked = unlinked;
-               gfs2_log_flush(sdp, NULL);
-               error = 0;
-
-               goto try_again;
+               return error;
        }
+
        /* no error, so we have the rgrp set in the inode's allocation. */
        al->al_file = file;
        al->al_line = line;
index d6cfac1f0a40cc20357961bd7895f6985440dee7..a5fe68189eed00d76e0d3027fead3edc648c9aff 100644 (file)
@@ -932,8 +932,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
        if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
                *user = current_user();
                if (user_shm_lock(size, *user)) {
-                       WARN_ONCE(1,
-                         "Using mlock ulimits for SHM_HUGETLB deprecated\n");
+                       printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated\n");
                } else {
                        *user = NULL;
                        return ERR_PTR(-EPERM);
index e92fdbb3bc3aebd5b52221d2b0e5ec4094a37fe9..d6cc16476620760b6f01233f87fe5842335ba760 100644 (file)
@@ -6,7 +6,6 @@
 
 #include <linux/syscalls.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/capability.h>
 #include <linux/file.h>
 #include <linux/fs.h>
@@ -530,41 +529,6 @@ static int ioctl_fsthaw(struct file *filp)
        return thaw_super(sb);
 }
 
-static int ioctl_fstrim(struct file *filp, void __user *argp)
-{
-       struct super_block *sb = filp->f_path.dentry->d_inode->i_sb;
-       struct fstrim_range range;
-       int ret = 0;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       /* If filesystem doesn't support trim feature, return. */
-       if (sb->s_op->trim_fs == NULL)
-               return -EOPNOTSUPP;
-
-       /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */
-       if (sb->s_bdev == NULL)
-               return -EINVAL;
-
-       if (argp == NULL) {
-               range.start = 0;
-               range.len = ULLONG_MAX;
-               range.minlen = 0;
-       } else if (copy_from_user(&range, argp, sizeof(range)))
-               return -EFAULT;
-
-       ret = sb->s_op->trim_fs(sb, &range);
-       if (ret < 0)
-               return ret;
-
-       if ((argp != NULL) &&
-           (copy_to_user(argp, &range, sizeof(range))))
-               return -EFAULT;
-
-       return 0;
-}
-
 /*
  * When you add any new common ioctls to the switches above and below
  * please update compat_sys_ioctl() too.
@@ -615,10 +579,6 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                error = ioctl_fsthaw(filp);
                break;
 
-       case FITRIM:
-               error = ioctl_fstrim(filp, argp);
-               break;
-
        case FS_IOC_FIEMAP:
                return ioctl_fiemap(filp, arg);
 
index 748cfb92dcc6203897c62d87ee113876f197a28b..2f7d05c899220e06d99ac9ecc9f8047903faa3a0 100644 (file)
@@ -111,12 +111,14 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
        read_lock(&tasklist_lock);
        switch (which) {
                case IOPRIO_WHO_PROCESS:
+                       rcu_read_lock();
                        if (!who)
                                p = current;
                        else
                                p = find_task_by_vpid(who);
                        if (p)
                                ret = set_task_ioprio(p, ioprio);
+                       rcu_read_unlock();
                        break;
                case IOPRIO_WHO_PGRP:
                        if (!who)
@@ -139,7 +141,12 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
                                break;
 
                        do_each_thread(g, p) {
-                               if (__task_cred(p)->uid != who)
+                               int match;
+
+                               rcu_read_lock();
+                               match = __task_cred(p)->uid == who;
+                               rcu_read_unlock();
+                               if (!match)
                                        continue;
                                ret = set_task_ioprio(p, ioprio);
                                if (ret)
@@ -200,12 +207,14 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
        read_lock(&tasklist_lock);
        switch (which) {
                case IOPRIO_WHO_PROCESS:
+                       rcu_read_lock();
                        if (!who)
                                p = current;
                        else
                                p = find_task_by_vpid(who);
                        if (p)
                                ret = get_task_ioprio(p);
+                       rcu_read_unlock();
                        break;
                case IOPRIO_WHO_PGRP:
                        if (!who)
@@ -232,7 +241,12 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
                                break;
 
                        do_each_thread(g, p) {
-                               if (__task_cred(p)->uid != user->uid)
+                               int match;
+
+                               rcu_read_lock();
+                               match = __task_cred(p)->uid == user->uid;
+                               rcu_read_unlock();
+                               if (!match)
                                        continue;
                                tmpio = get_task_ioprio(p);
                                if (tmpio < 0)
index c590d155c0959bfbe1f8ce2f6be9702afd2904f4..f837ba953529690e9de45c1e1731470897edeeb4 100644 (file)
@@ -899,6 +899,14 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
 
        /* journal descriptor can store up to n blocks -bzzz */
        journal->j_blocksize = blocksize;
+       journal->j_dev = bdev;
+       journal->j_fs_dev = fs_dev;
+       journal->j_blk_offset = start;
+       journal->j_maxlen = len;
+       bdevname(journal->j_dev, journal->j_devname);
+       p = journal->j_devname;
+       while ((p = strchr(p, '/')))
+               *p = '!';
        jbd2_stats_proc_init(journal);
        n = journal->j_blocksize / sizeof(journal_block_tag_t);
        journal->j_wbufsize = n;
@@ -908,14 +916,6 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
                        __func__);
                goto out_err;
        }
-       journal->j_dev = bdev;
-       journal->j_fs_dev = fs_dev;
-       journal->j_blk_offset = start;
-       journal->j_maxlen = len;
-       bdevname(journal->j_dev, journal->j_devname);
-       p = journal->j_devname;
-       while ((p = strchr(p, '/')))
-               *p = '!';
 
        bh = __getblk(journal->j_dev, start, journal->j_blocksize);
        if (!bh) {
index d5bb86866e6c19f85a359373742a37e24ad39ad7..25509eb28fd71980fa030aa39a1e81f225da43f9 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
-#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 
 #define NLMDBG_FACILITY                NLMDBG_CLIENT
index 47ea1e1925b8c4fded4b156ea7cef916322377bf..332c54cf75e0f465f5ba91cc66999df386d4d4e0 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/errno.h>
index 25e21e4023b22a3f51ceb9d1c1869c2b7518f6d0..ed0c59fe23cef0dd038dd485545a14209fa11b78 100644 (file)
@@ -124,7 +124,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
                        continue;
                if (host->h_server != ni->server)
                        continue;
-               if (ni->server &&
+               if (ni->server && ni->src_len != 0 &&
                    !rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap))
                        continue;
 
@@ -167,6 +167,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
        host->h_addrlen = ni->salen;
        rpc_set_port(nlm_addr(host), 0);
        memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
+       host->h_srcaddrlen = ni->src_len;
        host->h_version    = ni->version;
        host->h_proto      = ni->protocol;
        host->h_rpcclnt    = NULL;
@@ -238,9 +239,6 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
                                     const char *hostname,
                                     int noresvport)
 {
-       const struct sockaddr source = {
-               .sa_family      = AF_UNSPEC,
-       };
        struct nlm_lookup_host_info ni = {
                .server         = 0,
                .sap            = sap,
@@ -249,8 +247,6 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
                .version        = version,
                .hostname       = hostname,
                .hostname_len   = strlen(hostname),
-               .src_sap        = &source,
-               .src_len        = sizeof(source),
                .noresvport     = noresvport,
        };
 
@@ -357,7 +353,6 @@ nlm_bind_host(struct nlm_host *host)
                        .protocol       = host->h_proto,
                        .address        = nlm_addr(host),
                        .addrsize       = host->h_addrlen,
-                       .saddress       = nlm_srcaddr(host),
                        .timeout        = &timeparms,
                        .servername     = host->h_name,
                        .program        = &nlm_program,
@@ -376,6 +371,8 @@ nlm_bind_host(struct nlm_host *host)
                        args.flags |= RPC_CLNT_CREATE_HARDRTRY;
                if (host->h_noresvport)
                        args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+               if (host->h_srcaddrlen)
+                       args.saddress = nlm_srcaddr(host);
 
                clnt = rpc_create(&args);
                if (!IS_ERR(clnt))
index a336e832475db7ffd5516a4cbe7e32daff49fd7c..38d261192453b5ee11300d577d0ebe66d3b9be72 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/types.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
 
index c462d346acbda920a78ef03c153dc088b70ef7f4..ef5659b211e96cbcc8e4aa03d1cd332fd68c1a85 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/nlm.h>
index c3069f38d60220e82726d5c318d0942e125ddb03..0caea5310ac3f0ea7ba24d36cdacaed03a55f9d3 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/types.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
 
index 65765cb6afedaee442c1e1ab21bf7269ce9b07c7..8729347bcd1a1b0ab9953c85e7c3ffa46a1fce9c 100644 (file)
 #include <linux/module.h>
 #include <linux/security.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/time.h>
 #include <linux/rcupdate.h>
@@ -1504,9 +1503,8 @@ static int do_fcntl_delete_lease(struct file *filp)
 
 static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
 {
-       struct file_lock *fl;
+       struct file_lock *fl, *ret;
        struct fasync_struct *new;
-       struct inode *inode = filp->f_path.dentry->d_inode;
        int error;
 
        fl = lease_alloc(filp, arg);
@@ -1518,13 +1516,16 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                locks_free_lock(fl);
                return -ENOMEM;
        }
+       ret = fl;
        lock_flocks();
-       error = __vfs_setlease(filp, arg, &fl);
+       error = __vfs_setlease(filp, arg, &ret);
        if (error) {
                unlock_flocks();
                locks_free_lock(fl);
                goto out_free_fasync;
        }
+       if (ret != fl)
+               locks_free_lock(fl);
 
        /*
         * fasync_insert_entry() returns the old entry if any.
@@ -1532,17 +1533,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
         * inserted it into the fasync list. Clear new so that
         * we don't release it here.
         */
-       if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new))
+       if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new))
                new = NULL;
 
-       if (error < 0) {
-               /* remove lease just inserted by setlease */
-               fl->fl_type = F_UNLCK | F_INPROGRESS;
-               fl->fl_break_time = jiffies - 10;
-               time_out_leases(inode);
-       } else {
-               error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
-       }
+       error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
        unlock_flocks();
 
 out_free_fasync:
index cd51a36b37f0956bf7eafde8ced983d5ae437b05..57afd4a6fabbb992b0b08ea9bb5399071ea576c2 100644 (file)
@@ -486,7 +486,7 @@ static inline int logfs_get_sb_bdev(struct logfs_super *s,
 
 /* dev_mtd.c */
 #ifdef CONFIG_MTD
-int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
+int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr);
 #else
 static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
 {
index 8a415c9c5e552efd945cdb85af6f74af4b2b6de6..3dbfc072ec70aa0099b79b3ff1040455543c46ca 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/percpu.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/acct.h>
index aac8832e919e9a56cb95af787af658fb03d8d0d1..f22b12e7d337c37abc957ee2b4c2b204f52206b1 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
-#include <linux/smp_lock.h>
 
 #include <linux/ncp_fs.h>
 
index 6c754f70c5296be3fbe5c323bbb985d7ee326512..cb50aaf981dff5bf32dd2d4993ac14a1202dc27e 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
index d290545aa0c4b98c932e316c7dd4fcf3961b1126..8fb93b604e73a3a337a5f43ebc97b25d9f02d7f8 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
index c2a1f9a155c3a6e8f82800334337b1b1b0aaa65a..d40a547e337707da380e752864926a65c70013cc 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mount.h>
 #include <linux/slab.h>
 #include <linux/highuid.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 
index aeec017fe814acbdf17947a68553765a335359ae..93a8b3bd69e37871795b93355e0550970cf7f421 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/completion.h>
 #include <linux/ip.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/nfs_fs.h>
index 232a7eead33a488c4a5d67bc83e3a1971d9665df..1fd62fc49be36310b45e54028f69905b4e4f0237 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 
 #include <linux/nfs4.h>
index 07ac3847e562b54c26efd30c9a9eabab468c309d..662df2a5fad5d06fac235314220e7270fe9eef02 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mount.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
+#include <linux/kmemleak.h>
 
 #include "delegation.h"
 #include "iostat.h"
@@ -194,9 +195,13 @@ typedef struct {
 static
 struct nfs_cache_array *nfs_readdir_get_array(struct page *page)
 {
+       void *ptr;
        if (page == NULL)
                return ERR_PTR(-EIO);
-       return (struct nfs_cache_array *)kmap(page);
+       ptr = kmap(page);
+       if (ptr == NULL)
+               return ERR_PTR(-ENOMEM);
+       return ptr;
 }
 
 static
@@ -213,6 +218,9 @@ int nfs_readdir_clear_array(struct page *page, gfp_t mask)
 {
        struct nfs_cache_array *array = nfs_readdir_get_array(page);
        int i;
+
+       if (IS_ERR(array))
+               return PTR_ERR(array);
        for (i = 0; i < array->size; i++)
                kfree(array->array[i].string.name);
        nfs_readdir_release_array(page);
@@ -231,6 +239,11 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le
        string->name = kmemdup(name, len, GFP_KERNEL);
        if (string->name == NULL)
                return -ENOMEM;
+       /*
+        * Avoid a kmemleak false positive. The pointer to the name is stored
+        * in a page cache page which kmemleak does not scan.
+        */
+       kmemleak_not_leak(string->name);
        string->hash = full_name_hash(name, len);
        return 0;
 }
@@ -244,7 +257,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
 
        if (IS_ERR(array))
                return PTR_ERR(array);
-       ret = -EIO;
+       ret = -ENOSPC;
        if (array->size >= MAX_READDIR_ARRAY)
                goto out;
 
@@ -255,9 +268,9 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
        if (ret)
                goto out;
        array->last_cookie = entry->cookie;
+       array->size++;
        if (entry->eof == 1)
                array->eof_index = array->size;
-       array->size++;
 out:
        nfs_readdir_release_array(page);
        return ret;
@@ -272,7 +285,7 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
        if (diff < 0)
                goto out_eof;
        if (diff >= array->size) {
-               if (array->eof_index > 0)
+               if (array->eof_index >= 0)
                        goto out_eof;
                desc->current_index += array->size;
                return -EAGAIN;
@@ -281,8 +294,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
        index = (unsigned int)diff;
        *desc->dir_cookie = array->array[index].cookie;
        desc->cache_entry_index = index;
-       if (index == array->eof_index)
-               desc->eof = 1;
        return 0;
 out_eof:
        desc->eof = 1;
@@ -296,17 +307,17 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
        int status = -EAGAIN;
 
        for (i = 0; i < array->size; i++) {
-               if (i == array->eof_index) {
-                       desc->eof = 1;
-                       status = -EBADCOOKIE;
-               }
                if (array->array[i].cookie == *desc->dir_cookie) {
                        desc->cache_entry_index = i;
                        status = 0;
-                       break;
+                       goto out;
                }
        }
-
+       if (i == array->eof_index) {
+               desc->eof = 1;
+               status = -EBADCOOKIE;
+       }
+out:
        return status;
 }
 
@@ -449,7 +460,7 @@ out:
 
 /* Perform conversion from xdr to cache array */
 static
-void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
+int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
                                void *xdr_page, struct page *page, unsigned int buflen)
 {
        struct xdr_stream stream;
@@ -471,21 +482,29 @@ void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *e
 
        do {
                status = xdr_decode(desc, entry, &stream);
-               if (status != 0)
+               if (status != 0) {
+                       if (status == -EAGAIN)
+                               status = 0;
                        break;
+               }
 
-               if (nfs_readdir_add_to_array(entry, page) == -1)
-                       break;
                if (desc->plus == 1)
                        nfs_prime_dcache(desc->file->f_path.dentry, entry);
+
+               status = nfs_readdir_add_to_array(entry, page);
+               if (status != 0)
+                       break;
        } while (!entry->eof);
 
        if (status == -EBADCOOKIE && entry->eof) {
                array = nfs_readdir_get_array(page);
-               array->eof_index = array->size - 1;
-               status = 0;
-               nfs_readdir_release_array(page);
+               if (!IS_ERR(array)) {
+                       array->eof_index = array->size;
+                       status = 0;
+                       nfs_readdir_release_array(page);
+               }
        }
+       return status;
 }
 
 static
@@ -537,7 +556,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
        struct nfs_entry entry;
        struct file     *file = desc->file;
        struct nfs_cache_array *array;
-       int status = 0;
+       int status = -ENOMEM;
        unsigned int array_size = ARRAY_SIZE(pages);
 
        entry.prev_cookie = 0;
@@ -549,6 +568,10 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
                goto out;
 
        array = nfs_readdir_get_array(page);
+       if (IS_ERR(array)) {
+               status = PTR_ERR(array);
+               goto out;
+       }
        memset(array, 0, sizeof(struct nfs_cache_array));
        array->eof_index = -1;
 
@@ -556,12 +579,19 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
        if (!pages_ptr)
                goto out_release_array;
        do {
+               unsigned int pglen;
                status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
 
                if (status < 0)
                        break;
-               nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE);
-       } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY);
+               pglen = status;
+               status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
+               if (status < 0) {
+                       if (status == -ENOSPC)
+                               status = 0;
+                       break;
+               }
+       } while (array->eof_index < 0);
 
        nfs_readdir_free_large_page(pages_ptr, pages, array_size);
 out_release_array:
@@ -582,8 +612,10 @@ static
 int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
 {
        struct inode    *inode = desc->file->f_path.dentry->d_inode;
+       int ret;
 
-       if (nfs_readdir_xdr_to_array(desc, page, inode) < 0)
+       ret = nfs_readdir_xdr_to_array(desc, page, inode);
+       if (ret < 0)
                goto error;
        SetPageUptodate(page);
 
@@ -595,7 +627,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
        return 0;
  error:
        unlock_page(page);
-       return -EIO;
+       return ret;
 }
 
 static
@@ -608,12 +640,8 @@ void cache_page_release(nfs_readdir_descriptor_t *desc)
 static
 struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
 {
-       struct page *page;
-       page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
+       return read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
                        desc->page_index, (filler_t *)nfs_readdir_filler, desc);
-       if (IS_ERR(page))
-               desc->eof = 1;
-       return page;
 }
 
 /*
@@ -639,8 +667,10 @@ int find_cache_page(nfs_readdir_descriptor_t *desc)
 static inline
 int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
 {
-       int res = -EAGAIN;
+       int res;
 
+       if (desc->page_index == 0)
+               desc->current_index = 0;
        while (1) {
                res = find_cache_page(desc);
                if (res != -EAGAIN)
@@ -670,6 +700,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct dentry *dentry = NULL;
 
        array = nfs_readdir_get_array(desc->page);
+       if (IS_ERR(array))
+               return PTR_ERR(array);
 
        for (i = desc->cache_entry_index; i < array->size; i++) {
                d_type = DT_UNKNOWN;
@@ -685,11 +717,9 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                        *desc->dir_cookie = array->array[i+1].cookie;
                else
                        *desc->dir_cookie = array->last_cookie;
-               if (i == array->eof_index) {
-                       desc->eof = 1;
-                       break;
-               }
        }
+       if (i == array->eof_index)
+               desc->eof = 1;
 
        nfs_readdir_release_array(desc->page);
        cache_page_release(desc);
@@ -1345,12 +1375,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
                                res = NULL;
                                goto out;
                        /* This turned out not to be a regular file */
-                       case -EISDIR:
                        case -ENOTDIR:
                                goto no_open;
                        case -ELOOP:
                                if (!(nd->intent.open.flags & O_NOFOLLOW))
                                        goto no_open;
+                       /* case -EISDIR: */
                        /* case -EINVAL: */
                        default:
                                res = ERR_CAST(inode);
index e6bf45710cc7fcd0348459ed7a27cc9454ee7e88..2563f765c9b4ba49b37615657f4c3f5f76e7576d 100644 (file)
@@ -423,7 +423,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
        struct page **page;
        size_t hdrlen;
        unsigned int pglen, recvd;
-       int status, nr = 0;
+       int status;
 
        if ((status = ntohl(*p++)))
                return nfs_stat_to_errno(status);
@@ -443,7 +443,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
        if (pglen > recvd)
                pglen = recvd;
        page = rcvbuf->pages;
-       return nr;
+       return pglen;
 }
 
 static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
index d9a5e832c2579f9b20c0164944ae139509d8fb79..748dc91a4a147466529d9b1b49a20cc0ab2aad93 100644 (file)
@@ -555,7 +555,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
        struct page **page;
        size_t hdrlen;
        u32 recvd, pglen;
-       int status, nr = 0;
+       int status;
 
        status = ntohl(*p++);
        /* Decode post_op_attrs */
@@ -586,7 +586,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
                pglen = recvd;
        page = rcvbuf->pages;
 
-       return nr;
+       return pglen;
 }
 
 __be32 *
index 0f24cdf2cb132b1ad7018a520a7abbea753ce330..6a653ffd8e4e121e37c29d88ff2f5b0b4dbe264f 100644 (file)
@@ -2852,8 +2852,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
        nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
        res.pgbase = args.pgbase;
        status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0);
-       if (status == 0)
+       if (status >= 0) {
                memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
+               status += args.pgbase;
+       }
 
        nfs_invalidate_atime(dir);
 
index f313c4cce7e4d1d087b8a1b47b55f769edf40a21..b7a204ff6fe1504efe287b7620532407cc692f89 100644 (file)
@@ -4518,7 +4518,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
        xdr_read_pages(xdr, pglen);
 
 
-       return 0;
+       return pglen;
 }
 
 static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
index 0a42e8f4adcbc1723b57a7dac93c78b0a34b975e..3c045044fca25183147704f3689c744549ebd77b 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
 #include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/mount.h>
 #include <linux/mnt_namespace.h>
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
+#ifdef CONFIG_NFS_V3
+#define NFS_DEFAULT_VERSION 3
+#else
+#define NFS_DEFAULT_VERSION 2
+#endif
+
 enum {
        /* Mount options that take no arguments */
        Opt_soft, Opt_hard,
@@ -2277,7 +2282,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
        };
        int error = -ENOMEM;
 
-       data = nfs_alloc_parsed_mount_data(3);
+       data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
        mntfh = nfs_alloc_fhandle();
        if (data == NULL || mntfh == NULL)
                goto out_free_fh;
index f1e5ec6b5105fe46a1537df2041f9d114d222f8d..116cab970e0f3d737c8377bde9c3d97192568c71 100644 (file)
@@ -673,16 +673,17 @@ static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
        spin_unlock(&clp->cl_lock);
 }
 
-static void nfsd4_register_conn(struct nfsd4_conn *conn)
+static int nfsd4_register_conn(struct nfsd4_conn *conn)
 {
        conn->cn_xpt_user.callback = nfsd4_conn_lost;
-       register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
+       return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
 }
 
 static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
 {
        struct nfsd4_conn *conn;
        u32 flags = NFS4_CDFC4_FORE;
+       int ret;
 
        if (ses->se_flags & SESSION4_BACK_CHAN)
                flags |= NFS4_CDFC4_BACK;
@@ -690,7 +691,10 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
        if (!conn)
                return nfserr_jukebox;
        nfsd4_hash_conn(conn, ses);
-       nfsd4_register_conn(conn);
+       ret = nfsd4_register_conn(conn);
+       if (ret)
+               /* oops; xprt is already down: */
+               nfsd4_conn_lost(&conn->cn_xpt_user);
        return nfs_ok;
 }
 
@@ -1644,6 +1648,7 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi
 {
        struct nfs4_client *clp = ses->se_client;
        struct nfsd4_conn *c;
+       int ret;
 
        spin_lock(&clp->cl_lock);
        c = __nfsd4_find_conn(new->cn_xprt, ses);
@@ -1654,7 +1659,10 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi
        }
        __nfsd4_hash_conn(new, ses);
        spin_unlock(&clp->cl_lock);
-       nfsd4_register_conn(new);
+       ret = nfsd4_register_conn(new);
+       if (ret)
+               /* oops; xprt is already down: */
+               nfsd4_conn_lost(&new->cn_xpt_user);
        return;
 }
 
@@ -2254,7 +2262,7 @@ nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
  * Spawn a thread to perform a recall on the delegation represented
  * by the lease (file_lock)
  *
- * Called from break_lease() with lock_kernel() held.
+ * Called from break_lease() with lock_flocks() held.
  * Note: we assume break_lease will only call this *once* for any given
  * lease.
  */
@@ -2278,7 +2286,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
        list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
        spin_unlock(&recall_lock);
 
-       /* only place dl_time is set. protected by lock_kernel*/
+       /* only place dl_time is set. protected by lock_flocks*/
        dp->dl_time = get_seconds();
 
        /*
@@ -2295,7 +2303,7 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
 /*
  * The file_lock is being reapd.
  *
- * Called by locks_free_lock() with lock_kernel() held.
+ * Called by locks_free_lock() with lock_flocks() held.
  */
 static
 void nfsd_release_deleg_cb(struct file_lock *fl)
@@ -2310,7 +2318,7 @@ void nfsd_release_deleg_cb(struct file_lock *fl)
 }
 
 /*
- * Called from setlease() with lock_kernel() held
+ * Called from setlease() with lock_flocks() held
  */
 static
 int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
index d8408217e3bd0657a3446f77a56833a20f03ad52..1efea3615589ae1d5c30509d73cd03c09ccc973e 100644 (file)
@@ -159,7 +159,9 @@ struct ocfs2_lock_res {
        char                     l_name[OCFS2_LOCK_ID_MAX_LEN];
        unsigned int             l_ro_holders;
        unsigned int             l_ex_holders;
-       unsigned char            l_level;
+       char                     l_level;
+       char                     l_requested;
+       char                     l_blocking;
 
        /* Data packed - type enum ocfs2_lock_type */
        unsigned char            l_type;
@@ -169,8 +171,6 @@ struct ocfs2_lock_res {
        unsigned char            l_action;
        /* Data packed - enum type ocfs2_unlock_action */
        unsigned char            l_unlock_action;
-       unsigned char            l_requested;
-       unsigned char            l_blocking;
        unsigned int             l_pending_gen;
 
        spinlock_t               l_lock;
index f02c0ef315788427e1f8b51e964f9b9dec513a10..cfeab7ce36974b6d448e7e0b7d96fd0a992dbaa5 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/quotaops.h>
-#include <linux/smp_lock.h>
 
 #define MLOG_MASK_PREFIX ML_SUPER
 #include <cluster/masklog.h>
index ddb1f41376e532060da94bdbcf5f12502012ed95..911e61f348fc0fecb5dd748e96153c0c21974c10 100644 (file)
@@ -418,7 +418,7 @@ out_no_root:
 static struct dentry *openprom_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       return mount_single(fs_type, flags, data, openprom_fill_super)
+       return mount_single(fs_type, flags, data, openprom_fill_super);
 }
 
 static struct file_system_type openprom_fs_type = {
index 9c2b5f484879ad37a1633a6023524e2cb0151a3f..3ddb6068177c9a7d359f45b8aa60d6fb92dec9b4 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/limits.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/sysctl.h>
 #include <linux/slab.h>
 
index 431a0ed610c83a8750592e516ff23ac35ffbe524..5d431bacbea967e7a66755bf9320f20d9f464902 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/uio.h>
-#include <linux/smp_lock.h>
 #include <linux/fsnotify.h>
 #include <linux/security.h>
 #include <linux/module.h>
index 41656d40dc5c87fc8bcfd9ec5aea4bc635ebc092..0bae036831e2ca2aeeae94eb78d74f2aa769b54d 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/reiserfs_acl.h>
 #include <linux/reiserfs_xattr.h>
 #include <linux/exportfs.h>
-#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
index adf22b485ceac01e0f5ed7b0a8d1593956a7b81f..bd9763e76bae42844a6cf792d1da86a3454dbe38 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/time.h>
 #include <asm/uaccess.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/compat.h>
 
 /*
index 076c8b19468297dc71add1987b249ab054d6e20d..d31bce1a9f908e1df4c8046f371bec748c215440 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/workqueue.h>
 #include <linux/writeback.h>
index 3bf7a6457f4d3f021db9d561a34ab7fb07bf1e01..b243117b8752d0a9c81fa8f12773ca202a9cfabb 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/crc32.h>
-#include <linux/smp_lock.h>
 
 struct file_system_type reiserfs_fs_type;
 
index c9af48fffcd77fc559f73d5d97317e22ec4d3413..7d287afccde58ac16c854ee5dc2eb31f2f7b1637 100644 (file)
@@ -1111,11 +1111,12 @@ xfs_vm_writepage(
                        uptodate = 0;
 
                /*
-                * A hole may still be marked uptodate because discard_buffer
-                * leaves the flag set.
+                * set_page_dirty dirties all buffers in a page, independent
+                * of their state.  The dirty state however is entirely
+                * meaningless for holes (!mapped && uptodate), so skip
+                * buffers covering holes here.
                 */
                if (!buffer_mapped(bh) && buffer_uptodate(bh)) {
-                       ASSERT(!buffer_dirty(bh));
                        imap_valid = 0;
                        continue;
                }
index 63fd2c07cb57d861837bf463d9ad7b3aa5392088..aa1d353def29c64903cf02db9af159d612259b87 100644 (file)
@@ -1781,7 +1781,6 @@ xfs_buf_delwri_split(
        INIT_LIST_HEAD(list);
        spin_lock(dwlk);
        list_for_each_entry_safe(bp, n, dwq, b_list) {
-               trace_xfs_buf_delwri_split(bp, _RET_IP_);
                ASSERT(bp->b_flags & XBF_DELWRI);
 
                if (!XFS_BUF_ISPINNED(bp) && !xfs_buf_cond_lock(bp)) {
@@ -1795,6 +1794,7 @@ xfs_buf_delwri_split(
                                         _XBF_RUN_QUEUES);
                        bp->b_flags |= XBF_WRITE;
                        list_move_tail(&bp->b_list, list);
+                       trace_xfs_buf_delwri_split(bp, _RET_IP_);
                } else
                        skipped++;
        }
index 2ea238f6d38eb0504187d674a70c57d9acc5b382..ad442d9e392e480ab242f5d13922ee3ec0feab2e 100644 (file)
@@ -416,7 +416,7 @@ xfs_attrlist_by_handle(
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
-       kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);
+       kbuf = kzalloc(al_hreq.buflen, GFP_KERNEL);
        if (!kbuf)
                goto out_dput;
 
index 96107efc0c61908c3f1a94a646604836fc2131e1..94d5fd6a2973042239bd22f19047947494f57581 100644 (file)
@@ -762,7 +762,8 @@ xfs_setup_inode(
        inode->i_state = I_NEW;
 
        inode_sb_list_add(inode);
-       insert_inode_hash(inode);
+       /* make the inode look hashed for the writeback code */
+       hlist_add_fake(&inode->i_hash);
 
        inode->i_mode   = ip->i_d.di_mode;
        inode->i_nlink  = ip->i_d.di_nlink;
index 9f3a78fe6ae4e1f8463129d0d8ef5967bdde2408..064f964d4f3c201ce52bf6bb42e7dbbd3c0526bd 100644 (file)
@@ -353,9 +353,6 @@ xfs_parseargs(
                        mp->m_qflags &= ~XFS_OQUOTA_ENFD;
                } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
                        mp->m_flags |= XFS_MOUNT_DELAYLOG;
-                       cmn_err(CE_WARN,
-                               "Enabling EXPERIMENTAL delayed logging feature "
-                               "- use at your own risk.\n");
                } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
                        mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
                } else if (!strcmp(this_char, "ihashsize")) {
index 37d33254981da7026cffb7e586f072c1a93eae9d..afb0d7cfad1cceafef852098d955cd8dfb42bee3 100644 (file)
@@ -853,6 +853,7 @@ restart:
                if (trylock) {
                        if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) {
                                skipped++;
+                               xfs_perag_put(pag);
                                continue;
                        }
                        first_index = pag->pag_ici_reclaim_cursor;
index 9b715dce5699df0833ea92058683a5b9f30f8868..9124425b7f2fe9a07c3479047e7c3ea7c3a74693 100644 (file)
@@ -744,9 +744,15 @@ xfs_filestream_new_ag(
         * If the file's parent directory is known, take its iolock in exclusive
         * mode to prevent two sibling files from racing each other to migrate
         * themselves and their parent to different AGs.
+        *
+        * Note that we lock the parent directory iolock inside the child
+        * iolock here.  That's fine as we never hold both parent and child
+        * iolock in any other place.  This is different from the ilock,
+        * which requires locking of the child after the parent for namespace
+        * operations.
         */
        if (pip)
-               xfs_ilock(pip, XFS_IOLOCK_EXCL);
+               xfs_ilock(pip, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
 
        /*
         * A new AG needs to be found for the file.  If the file's parent
index b1498ab5a399b627b3f7b643e2bca6256ae5a49f..19e9dfa1c2543e3a47c05ea1a25cb954b47d9736 100644 (file)
@@ -275,6 +275,7 @@ xfs_free_perag(
                pag = radix_tree_delete(&mp->m_perag_tree, agno);
                spin_unlock(&mp->m_perag_lock);
                ASSERT(pag);
+               ASSERT(atomic_read(&pag->pag_ref) == 0);
                call_rcu(&pag->rcu_head, __xfs_free_perag);
        }
 }
index e0e64b113bd66e91b22933ab6eaf8192e67e936a..9bb6eda4cd215903077612233bf3b6c0d1577327 100644 (file)
@@ -346,8 +346,17 @@ xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
 #define xfs_trans_mod_dquot_byino(tp, ip, fields, delta)
 #define xfs_trans_apply_dquot_deltas(tp)
 #define xfs_trans_unreserve_and_mod_dquots(tp)
-#define xfs_trans_reserve_quota_nblks(tp, ip, nblks, ninos, flags)     (0)
-#define xfs_trans_reserve_quota_bydquots(tp, mp, u, g, nb, ni, fl)     (0)
+static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp,
+               struct xfs_inode *ip, long nblks, long ninos, uint flags)
+{
+       return 0;
+}
+static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
+               struct xfs_mount *mp, struct xfs_dquot *udqp,
+               struct xfs_dquot *gdqp, long nblks, long nions, uint flags)
+{
+       return 0;
+}
 #define xfs_qm_vop_create_dqattach(tp, ip, u, g)
 #define xfs_qm_vop_rename_dqattach(it)                                 (0)
 #define xfs_qm_vop_chown(tp, ip, old, new)                             (NULL)
@@ -357,11 +366,14 @@ xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
 #define xfs_qm_dqdetach(ip)
 #define xfs_qm_dqrele(d)
 #define xfs_qm_statvfs(ip, s)
-#define xfs_qm_sync(mp, fl)                                            (0)
+static inline int xfs_qm_sync(struct xfs_mount *mp, int flags)
+{
+       return 0;
+}
 #define xfs_qm_newmount(mp, a, b)                                      (0)
 #define xfs_qm_mount_quotas(mp)
 #define xfs_qm_unmount(mp)
-#define xfs_qm_unmount_quotas(mp)                                      (0)
+#define xfs_qm_unmount_quotas(mp)
 #endif /* CONFIG_XFS_QUOTA */
 
 #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \
index 47e64170305d8f862e2f67d73420eb3e0a8ed9e4..bd8cad21998e0e41ac88435b55ae9f3d275c0283 100644 (file)
@@ -33,18 +33,18 @@ struct stat {
        int             st_blksize;     /* Optimal block size for I/O.  */
        int             __pad2;
        long            st_blocks;      /* Number 512-byte blocks allocated. */
-       int             st_atime;       /* Time of last access.  */
-       unsigned int    st_atime_nsec;
-       int             st_mtime;       /* Time of last modification.  */
-       unsigned int    st_mtime_nsec;
-       int             st_ctime;       /* Time of last status change.  */
-       unsigned int    st_ctime_nsec;
+       long            st_atime;       /* Time of last access.  */
+       unsigned long   st_atime_nsec;
+       long            st_mtime;       /* Time of last modification.  */
+       unsigned long   st_mtime_nsec;
+       long            st_ctime;       /* Time of last status change.  */
+       unsigned long   st_ctime_nsec;
        unsigned int    __unused4;
        unsigned int    __unused5;
 };
 
-#if __BITS_PER_LONG != 64
 /* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64)
 struct stat64 {
        unsigned long long st_dev;      /* Device.  */
        unsigned long long st_ino;      /* File serial number.  */
index 01a7141195068c8e0fd384c0dde661adfb9601b6..bc5590b1a1acbe852314995f11b479e221ba6281 100644 (file)
@@ -80,6 +80,7 @@ struct drm_nouveau_gpuobj_free {
 #define NOUVEAU_GETPARAM_VM_VRAM_BASE    12
 #define NOUVEAU_GETPARAM_GRAPH_UNITS     13
 #define NOUVEAU_GETPARAM_PTIMER_TIME     14
+#define NOUVEAU_GETPARAM_HAS_BO_USAGE    15
 struct drm_nouveau_getparam {
        uint64_t param;
        uint64_t value;
@@ -95,6 +96,12 @@ struct drm_nouveau_setparam {
 #define NOUVEAU_GEM_DOMAIN_GART      (1 << 2)
 #define NOUVEAU_GEM_DOMAIN_MAPPABLE  (1 << 3)
 
+#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00
+#define NOUVEAU_GEM_TILE_16BPP       0x00000001
+#define NOUVEAU_GEM_TILE_32BPP       0x00000002
+#define NOUVEAU_GEM_TILE_ZETA        0x00000004
+#define NOUVEAU_GEM_TILE_NONCONTIG   0x00000008
+
 struct drm_nouveau_gem_info {
        uint32_t handle;
        uint32_t domain;
index 5afa5b52063e6d385926de88ec49faf1324a185a..beafc156a5353259d6b077ca57b2dd13af39f48d 100644 (file)
@@ -432,6 +432,10 @@ extern void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo);
  * together with the @destroy function,
  * enables driver-specific objects derived from a ttm_buffer_object.
  * On successful return, the object kref and list_kref are set to 1.
+ * If a failure occurs, the function will call the @destroy function, or
+ * kfree() if @destroy is NULL. Thus, after a failure, dereferencing @bo is
+ * illegal and will likely cause memory corruption.
+ *
  * Returns
  * -ENOMEM: Out of memory.
  * -EINVAL: Invalid placement flags.
index d01b4ddbdc56acb88fd1064b0e4580f82aa03b76..8e0c848326b6df5ccc95fc4ae16b965d81bfa0c8 100644 (file)
@@ -206,14 +206,84 @@ struct ttm_tt {
 struct ttm_mem_type_manager;
 
 struct ttm_mem_type_manager_func {
+       /**
+        * struct ttm_mem_type_manager member init
+        *
+        * @man: Pointer to a memory type manager.
+        * @p_size: Implementation dependent, but typically the size of the
+        * range to be managed in pages.
+        *
+        * Called to initialize a private range manager. The function is
+        * expected to initialize the man::priv member.
+        * Returns 0 on success, negative error code on failure.
+        */
        int  (*init)(struct ttm_mem_type_manager *man, unsigned long p_size);
+
+       /**
+        * struct ttm_mem_type_manager member takedown
+        *
+        * @man: Pointer to a memory type manager.
+        *
+        * Called to undo the setup done in init. All allocated resources
+        * should be freed.
+        */
        int  (*takedown)(struct ttm_mem_type_manager *man);
+
+       /**
+        * struct ttm_mem_type_manager member get_node
+        *
+        * @man: Pointer to a memory type manager.
+        * @bo: Pointer to the buffer object we're allocating space for.
+        * @placement: Placement details.
+        * @mem: Pointer to a struct ttm_mem_reg to be filled in.
+        *
+        * This function should allocate space in the memory type managed
+        * by @man. Placement details if
+        * applicable are given by @placement. If successful,
+        * @mem::mm_node should be set to a non-null value, and
+        * @mem::start should be set to a value identifying the beginning
+        * of the range allocated, and the function should return zero.
+        * If the memory region accomodate the buffer object, @mem::mm_node
+        * should be set to NULL, and the function should return 0.
+        * If a system error occured, preventing the request to be fulfilled,
+        * the function should return a negative error code.
+        *
+        * Note that @mem::mm_node will only be dereferenced by
+        * struct ttm_mem_type_manager functions and optionally by the driver,
+        * which has knowledge of the underlying type.
+        *
+        * This function may not be called from within atomic context, so
+        * an implementation can and must use either a mutex or a spinlock to
+        * protect any data structures managing the space.
+        */
        int  (*get_node)(struct ttm_mem_type_manager *man,
                         struct ttm_buffer_object *bo,
                         struct ttm_placement *placement,
                         struct ttm_mem_reg *mem);
+
+       /**
+        * struct ttm_mem_type_manager member put_node
+        *
+        * @man: Pointer to a memory type manager.
+        * @mem: Pointer to a struct ttm_mem_reg to be filled in.
+        *
+        * This function frees memory type resources previously allocated
+        * and that are identified by @mem::mm_node and @mem::start. May not
+        * be called from within atomic context.
+        */
        void (*put_node)(struct ttm_mem_type_manager *man,
                         struct ttm_mem_reg *mem);
+
+       /**
+        * struct ttm_mem_type_manager member debug
+        *
+        * @man: Pointer to a memory type manager.
+        * @prefix: Prefix to be used in printout to identify the caller.
+        *
+        * This function is called to print out the state of the memory
+        * type manager to aid debugging of out-of-memory conditions.
+        * It may not be called from within atomic context.
+        */
        void (*debug)(struct ttm_mem_type_manager *man, const char *prefix);
 };
 
@@ -231,14 +301,13 @@ struct ttm_mem_type_manager {
        uint64_t size;
        uint32_t available_caching;
        uint32_t default_caching;
+       const struct ttm_mem_type_manager_func *func;
+       void *priv;
 
        /*
-        * Protected by the bdev->lru_lock.
-        * TODO: Consider one lru_lock per ttm_mem_type_manager.
-        * Plays ill with list removal, though.
+        * Protected by the global->lru_lock.
         */
-       const struct ttm_mem_type_manager_func *func;
-       void *priv;
+
        struct list_head lru;
 };
 
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
new file mode 100644 (file)
index 0000000..96c038e
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _LINUX_ATOMIC_H
+#define _LINUX_ATOMIC_H
+#include <asm/atomic.h>
+
+/**
+ * atomic_inc_not_zero_hint - increment if not null
+ * @v: pointer of type atomic_t
+ * @hint: probable value of the atomic before the increment
+ *
+ * This version of atomic_inc_not_zero() gives a hint of probable
+ * value of the atomic. This helps processor to not read the memory
+ * before doing the atomic read/modify/write cycle, lowering
+ * number of bus transactions on some arches.
+ *
+ * Returns: 0 if increment was not done, 1 otherwise.
+ */
+#ifndef atomic_inc_not_zero_hint
+static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint)
+{
+       int val, c = hint;
+
+       /* sanity test, should be removed by compiler if hint is a constant */
+       if (!hint)
+               return atomic_inc_not_zero(v);
+
+       do {
+               val = atomic_cmpxchg(v, c, c + 1);
+               if (val == c)
+                       return 1;
+               c = val;
+       } while (c);
+
+       return 0;
+}
+#endif
+
+#endif /* _LINUX_ATOMIC_H */
index ba679992d39b4e08ebf0314b784a72a80dd41506..35dcdb3589bc9a59047a58e166efc540c22a3105 100644 (file)
 #define bio_offset(bio)                bio_iovec((bio))->bv_offset
 #define bio_segments(bio)      ((bio)->bi_vcnt - (bio)->bi_idx)
 #define bio_sectors(bio)       ((bio)->bi_size >> 9)
-#define bio_empty_barrier(bio) \
-       ((bio->bi_rw & REQ_HARDBARRIER) && \
-        !bio_has_data(bio) && \
-        !(bio->bi_rw & REQ_DISCARD))
 
 static inline unsigned int bio_cur_bytes(struct bio *bio)
 {
index 0437ab6bb54c0b2265c39bb961e88eda09d38739..46ad5197537af19697396a4e43179e6322a255aa 100644 (file)
@@ -122,7 +122,6 @@ enum rq_flag_bits {
        __REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */
        __REQ_FAILFAST_DRIVER,  /* no driver retries of driver errors */
 
-       __REQ_HARDBARRIER,      /* may not be passed by drive either */
        __REQ_SYNC,             /* request is sync (sync write or read) */
        __REQ_META,             /* metadata io request */
        __REQ_DISCARD,          /* request to discard sectors */
@@ -159,7 +158,6 @@ enum rq_flag_bits {
 #define REQ_FAILFAST_DEV       (1 << __REQ_FAILFAST_DEV)
 #define REQ_FAILFAST_TRANSPORT (1 << __REQ_FAILFAST_TRANSPORT)
 #define REQ_FAILFAST_DRIVER    (1 << __REQ_FAILFAST_DRIVER)
-#define REQ_HARDBARRIER                (1 << __REQ_HARDBARRIER)
 #define REQ_SYNC               (1 << __REQ_SYNC)
 #define REQ_META               (1 << __REQ_META)
 #define REQ_DISCARD            (1 << __REQ_DISCARD)
@@ -168,8 +166,8 @@ enum rq_flag_bits {
 #define REQ_FAILFAST_MASK \
        (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER)
 #define REQ_COMMON_MASK \
-       (REQ_WRITE | REQ_FAILFAST_MASK | REQ_HARDBARRIER | REQ_SYNC | \
-        REQ_META | REQ_DISCARD | REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
+       (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_DISCARD | \
+        REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
 #define REQ_CLONE_MASK         REQ_COMMON_MASK
 
 #define REQ_UNPLUG             (1 << __REQ_UNPLUG)
index 5027a599077d89cd72aa5c09aaaa56254b971886..aae86fd10c4f5dcea0eaf43cf6c39667a805dae4 100644 (file)
@@ -552,8 +552,7 @@ static inline void blk_clear_queue_full(struct request_queue *q, int sync)
  * it already be started by driver.
  */
 #define RQ_NOMERGE_FLAGS       \
-       (REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER | \
-        REQ_FLUSH | REQ_FUA)
+       (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA)
 #define rq_mergeable(rq)       \
        (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
         (((rq)->cmd_flags & REQ_DISCARD) || \
index f22b2e941686fc370f85b942526ee392f1f9ead6..9e76d35670d204d6425b20d17595737fde4453ff 100644 (file)
@@ -227,8 +227,7 @@ extern int ceph_open_session(struct ceph_client *client);
 extern void ceph_release_page_vector(struct page **pages, int num_pages);
 
 extern struct page **ceph_get_direct_page_vector(const char __user *data,
-                                           int num_pages,
-                                           loff_t off, size_t len);
+                                                int num_pages);
 extern void ceph_put_page_vector(struct page **pages, int num_pages);
 extern void ceph_release_page_vector(struct page **pages, int num_pages);
 extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
index 5956d62c3057139ac6634df8e13556659d07725e..a108b425fee25aff2cbf4dd1924c047b925f7ab0 100644 (file)
@@ -82,6 +82,7 @@ struct ceph_msg {
        struct ceph_buffer *middle;
        struct page **pages;            /* data payload.  NOT OWNER. */
        unsigned nr_pages;              /* size of page array */
+       unsigned page_alignment;        /* io offset in first page */
        struct ceph_pagelist *pagelist; /* instead of pages */
        struct list_head list_head;
        struct kref kref;
index 6c91fb032c39cd907a3ac509db75a3a860e564c1..a1af29648fb54be5c0b5ac1cfc62879314145d56 100644 (file)
@@ -79,6 +79,7 @@ struct ceph_osd_request {
        struct ceph_file_layout r_file_layout;
        struct ceph_snap_context *r_snapc;    /* snap context for writes */
        unsigned          r_num_pages;        /* size of page array (follows) */
+       unsigned          r_page_alignment;   /* io offset in first page */
        struct page     **r_pages;            /* pages for data payload */
        int               r_pages_from_pool;
        int               r_own_pages;        /* if true, i own page list */
@@ -194,7 +195,8 @@ extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *,
                                      int do_sync, u32 truncate_seq,
                                      u64 truncate_size,
                                      struct timespec *mtime,
-                                     bool use_mempool, int num_reply);
+                                     bool use_mempool, int num_reply,
+                                     int page_align);
 
 static inline void ceph_osdc_get_request(struct ceph_osd_request *req)
 {
@@ -218,7 +220,8 @@ extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
                               struct ceph_file_layout *layout,
                               u64 off, u64 *plen,
                               u32 truncate_seq, u64 truncate_size,
-                              struct page **pages, int nr_pages);
+                              struct page **pages, int nr_pages,
+                              int page_align);
 
 extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
                                struct ceph_vino vino,
index 9b2a0158f399af00af84e4e65805df81f5b935c6..ef44c7a0638cdaaf087a65e01476aca73d29239b 100644 (file)
@@ -53,7 +53,7 @@
 
 
 extern const char *drbd_buildtag(void);
-#define REL_VERSION "8.3.9rc2"
+#define REL_VERSION "8.3.9"
 #define API_VERSION 88
 #define PRO_VERSION_MIN 86
 #define PRO_VERSION_MAX 95
index 334d68a171081472a25f98baa510bc7eb4cfeb8e..eedc00b7b1ee7a6c6ed887e264891911fa370c3c 100644 (file)
@@ -1612,7 +1612,6 @@ struct super_operations {
        ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
 #endif
        int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
-       int (*trim_fs) (struct super_block *, struct fstrim_range *);
 };
 
 /*
index fc295d7ea4632ad9c1c0cef1905699feabb979d2..781d4671415f9c5f25aaa50250a06190ea91f0bb 100644 (file)
@@ -54,7 +54,6 @@ struct aoi_display_offset {
 };
 
 #define MFB_SET_CHROMA_KEY     _IOW('M', 1, struct mfb_chroma_key)
-#define MFB_WAIT_FOR_VSYNC     _IOW('F', 0x20, u_int32_t)
 #define MFB_SET_BRIGHTNESS     _IOW('M', 3, __u8)
 
 #define MFB_SET_ALPHA          0x80014d00
index 8a389b608ce3b568e85d14dcbfb71f8f98cf0c13..32f9fd6619b4160c997bba07e2661382f3afaacf 100644 (file)
@@ -2,9 +2,6 @@
 #define LINUX_HARDIRQ_H
 
 #include <linux/preempt.h>
-#ifdef CONFIG_PREEMPT
-#include <linux/smp_lock.h>
-#endif
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
 #include <asm/hardirq.h>
  */
 #define in_nmi()       (preempt_count() & NMI_MASK)
 
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_BKL)
+# include <linux/sched.h>
+# define PREEMPT_INATOMIC_BASE (current->lock_depth >= 0)
+#else
+# define PREEMPT_INATOMIC_BASE 0
+#endif
+
 #if defined(CONFIG_PREEMPT)
-# define PREEMPT_INATOMIC_BASE kernel_locked()
 # define PREEMPT_CHECK_OFFSET 1
 #else
-# define PREEMPT_INATOMIC_BASE 0
 # define PREEMPT_CHECK_OFFSET 0
 #endif
 
index e9138198e8239d878ba04e069112e45eef0d519a..b676c585574e1723a50fbb7bddf0b96d43706dbe 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/uaccess.h>
+#include <linux/hardirq.h>
 
 #include <asm/cacheflush.h>
 
index e844a0b186957c3fd49a7b0b2ff3578bea75e3e6..4bef5c55716014a15e3b49e049514d8040f77b3c 100644 (file)
  */
 
 /* --- Bit algorithm adapters                                          */
-#define I2C_HW_B_BT848         0x010005 /* BT848 video boards */
-#define I2C_HW_B_RIVA          0x010010 /* Riva based graphics cards */
-#define I2C_HW_B_ZR36067       0x010019 /* Zoran-36057/36067 based boards */
 #define I2C_HW_B_CX2388x       0x01001b /* connexant 2388x based tv cards */
-#define I2C_HW_B_EM28XX                0x01001f /* em28xx video capture cards */
-#define I2C_HW_B_CX2341X       0x010020 /* Conexant CX2341X MPEG encoder cards */
-#define I2C_HW_B_CX23885       0x010022 /* conexant 23885 based tv cards (bus1) */
-#define I2C_HW_B_AU0828                0x010023 /* auvitek au0828 usb bridge */
-#define I2C_HW_B_CX231XX       0x010024 /* Conexant CX231XX USB based cards */
-#define I2C_HW_B_HDPVR         0x010025 /* Hauppauge HD PVR */
-
-/* --- SGI adapters                                                    */
-#define I2C_HW_SGI_VINO                0x160000
-
-/* --- SMBus only adapters                                             */
-#define I2C_HW_SMBUS_W9968CF   0x04000d
-#define I2C_HW_SMBUS_OV511     0x04000e /* OV511(+) USB 1.1 webcam ICs */
-#define I2C_HW_SMBUS_OV518     0x04000f /* OV518(+) USB 1.1 webcam ICs */
-#define I2C_HW_SMBUS_CAFE      0x040012 /* Marvell 88ALP01 "CAFE" cam  */
-
-/* --- Miscellaneous adapters */
-#define I2C_HW_SAA7146         0x060000 /* SAA7146 video decoder bus */
-#define I2C_HW_SAA7134         0x090000 /* SAA7134 video decoder bus */
 
 #endif /* LINUX_I2C_ID_H */
index 889b35abaedac162061d01872237de109d62dbbb..56cfe23ffb39b5f600fd0aa5bb9616d150b4e2f0 100644 (file)
@@ -353,7 +353,7 @@ struct i2c_algorithm {
  */
 struct i2c_adapter {
        struct module *owner;
-       unsigned int id;
+       unsigned int id __deprecated;
        unsigned int class;               /* classes to allow probing for */
        const struct i2c_algorithm *algo; /* the algorithm to access the bus */
        void *algo_data;
index 3c5d6b6e765c22b06f6125a606eef9b5107958aa..cec17cf6cac2b6044d820066419164d2faeccabc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
  /* Configuration Register1 */
 #define ADP5588_AUTO_INC       (1 << 7)
 #define ADP5588_GPIEM_CFG      (1 << 6)
+#define ADP5588_OVR_FLOW_M     (1 << 5)
 #define ADP5588_INT_CFG                (1 << 4)
+#define ADP5588_OVR_FLOW_IEN   (1 << 3)
+#define ADP5588_K_LCK_IM       (1 << 2)
 #define ADP5588_GPI_IEN                (1 << 1)
+#define ADP5588_KE_IEN         (1 << 0)
 
 /* Interrupt Status Register */
+#define ADP5588_CMP2_INT       (1 << 5)
+#define ADP5588_CMP1_INT       (1 << 4)
+#define ADP5588_OVR_FLOW_INT   (1 << 3)
+#define ADP5588_K_LCK_INT      (1 << 2)
 #define ADP5588_GPI_INT                (1 << 1)
 #define ADP5588_KE_INT         (1 << 0)
 
+/* Key Lock and Event Counter Register */
+#define ADP5588_K_LCK_EN       (1 << 6)
+#define ADP5588_LCK21          0x30
+#define ADP5588_KEC            0xF
+
 #define ADP5588_MAXGPIO                18
 #define ADP5588_BANK(offs)     ((offs) >> 3)
 #define ADP5588_BIT(offs)      (1u << ((offs) & 0x7))
index c2f3a72712cec86a63699690096b928f1a1db6a2..635e1faec412db465a429a626da4c373510f2d98 100644 (file)
@@ -339,6 +339,31 @@ static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
        }
 }
 
+/**
+ * vlan_get_protocol - get protocol EtherType.
+ * @skb: skbuff to query
+ *
+ * Returns the EtherType of the packet, regardless of whether it is
+ * vlan encapsulated (normal or hardware accelerated) or not.
+ */
+static inline __be16 vlan_get_protocol(const struct sk_buff *skb)
+{
+       __be16 protocol = 0;
+
+       if (vlan_tx_tag_present(skb) ||
+            skb->protocol != cpu_to_be16(ETH_P_8021Q))
+               protocol = skb->protocol;
+       else {
+               __be16 proto, *protop;
+               protop = skb_header_pointer(skb, offsetof(struct vlan_ethhdr,
+                                               h_vlan_encapsulated_proto),
+                                               sizeof(proto), &proto);
+               if (likely(protop))
+                       protocol = *protop;
+       }
+
+       return protocol;
+}
 #endif /* __KERNEL__ */
 
 /* VLAN IOCTLs are found in sockios.h */
index 51af441f3a21268fe40f8b78810d801cdc5b6416..6ef44465db8ddc31c41be1de00eeef38c53b5fa5 100644 (file)
@@ -1406,6 +1406,8 @@ static inline void input_set_drvdata(struct input_dev *dev, void *data)
 int __must_check input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
+void input_reset_device(struct input_dev *);
+
 int __must_check input_register_handler(struct input_handler *);
 void input_unregister_handler(struct input_handler *);
 
@@ -1421,7 +1423,7 @@ void input_release_device(struct input_handle *);
 int input_open_device(struct input_handle *);
 void input_close_device(struct input_handle *);
 
-int input_flush_device(struct input_handle* handle, struct file* file);
+int input_flush_device(struct input_handle *handle, struct file *file);
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
index 3e70b21884a948880f90e28684e5d5778e7a3d35..b2eee896dcbc7506f528be8b06a1fe3728aca141 100644 (file)
@@ -76,7 +76,6 @@ int put_io_context(struct io_context *ioc);
 void exit_io_context(struct task_struct *task);
 struct io_context *get_io_context(gfp_t gfp_flags, int node);
 struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
-void copy_io_context(struct io_context **pdst, struct io_context **psrc);
 #else
 static inline void exit_io_context(struct task_struct *task)
 {
index 450092c1e35f459f6db7dba29dbb94ec1a2c683c..b6de9a6f7018b6132de91c7142bafefdd1e68962 100644 (file)
 #include <linux/bitops.h>
 #include <linux/log2.h>
 #include <linux/typecheck.h>
+#include <linux/printk.h>
 #include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
 #include <asm/bug.h>
 
-extern const char linux_banner[];
-extern const char linux_proc_banner[];
-
 #define USHRT_MAX      ((u16)(~0U))
 #define SHRT_MAX       ((s16)(USHRT_MAX>>1))
 #define SHRT_MIN       ((s16)(-SHRT_MAX - 1))
@@ -60,7 +58,7 @@ extern const char linux_proc_banner[];
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 #define roundup(x, y) (                                        \
 {                                                      \
-       typeof(y) __y = y;                              \
+       const typeof(y) __y = y;                        \
        (((x) + (__y - 1)) / __y) * __y;                \
 }                                                      \
 )
@@ -110,31 +108,6 @@ extern const char linux_proc_banner[];
  */
 #define lower_32_bits(n) ((u32)(n))
 
-#define        KERN_EMERG      "<0>"   /* system is unusable                   */
-#define        KERN_ALERT      "<1>"   /* action must be taken immediately     */
-#define        KERN_CRIT       "<2>"   /* critical conditions                  */
-#define        KERN_ERR        "<3>"   /* error conditions                     */
-#define        KERN_WARNING    "<4>"   /* warning conditions                   */
-#define        KERN_NOTICE     "<5>"   /* normal but significant condition     */
-#define        KERN_INFO       "<6>"   /* informational                        */
-#define        KERN_DEBUG      "<7>"   /* debug-level messages                 */
-
-/* Use the default kernel loglevel */
-#define KERN_DEFAULT   "<d>"
-/*
- * Annotation for a "continued" line of log printout (only done after a
- * line that had no enclosing \n). Only to be used by core/arch code
- * during early bootup (a continued line is not SMP-safe otherwise).
- */
-#define        KERN_CONT       "<c>"
-
-extern int console_printk[];
-
-#define console_loglevel (console_printk[0])
-#define default_message_loglevel (console_printk[1])
-#define minimum_console_loglevel (console_printk[2])
-#define default_console_loglevel (console_printk[3])
-
 struct completion;
 struct pt_regs;
 struct user;
@@ -187,11 +160,6 @@ static inline void might_fault(void)
 }
 #endif
 
-struct va_format {
-       const char *fmt;
-       va_list *va;
-};
-
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(int state);
 NORET_TYPE void panic(const char * fmt, ...)
@@ -245,114 +213,8 @@ extern int func_ptr_is_kernel_text(void *ptr);
 struct pid;
 extern struct pid *session_of_pgrp(struct pid *pgrp);
 
-/*
- * FW_BUG
- * Add this to a message where you are sure the firmware is buggy or behaves
- * really stupid or out of spec. Be aware that the responsible BIOS developer
- * should be able to fix this issue or at least get a concrete idea of the
- * problem by reading your message without the need of looking at the kernel
- * code.
- * 
- * Use it for definite and high priority BIOS bugs.
- *
- * FW_WARN
- * Use it for not that clear (e.g. could the kernel messed up things already?)
- * and medium priority BIOS bugs.
- *
- * FW_INFO
- * Use this one if you want to tell the user or vendor about something
- * suspicious, but generally harmless related to the firmware.
- *
- * Use it for information or very low priority BIOS bugs.
- */
-#define FW_BUG         "[Firmware Bug]: "
-#define FW_WARN                "[Firmware Warn]: "
-#define FW_INFO                "[Firmware Info]: "
-
-/*
- * HW_ERR
- * Add this to a message for hardware errors, so that user can report
- * it to hardware vendor instead of LKML or software vendor.
- */
-#define HW_ERR         "[Hardware Error]: "
-
-#ifdef CONFIG_PRINTK
-asmlinkage int vprintk(const char *fmt, va_list args)
-       __attribute__ ((format (printf, 1, 0)));
-asmlinkage int printk(const char * fmt, ...)
-       __attribute__ ((format (printf, 1, 2))) __cold;
-
-/*
- * Please don't use printk_ratelimit(), because it shares ratelimiting state
- * with all other unrelated printk_ratelimit() callsites.  Instead use
- * printk_ratelimited() or plain old __ratelimit().
- */
-extern int __printk_ratelimit(const char *func);
-#define printk_ratelimit() __printk_ratelimit(__func__)
-extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
-                                  unsigned int interval_msec);
-
-extern int printk_delay_msec;
-
-/*
- * Print a one-time message (analogous to WARN_ONCE() et al):
- */
-#define printk_once(x...) ({                   \
-       static bool __print_once;               \
-                                               \
-       if (!__print_once) {                    \
-               __print_once = true;            \
-               printk(x);                      \
-       }                                       \
-})
-
-void log_buf_kexec_setup(void);
-#else
-static inline int vprintk(const char *s, va_list args)
-       __attribute__ ((format (printf, 1, 0)));
-static inline int vprintk(const char *s, va_list args) { return 0; }
-static inline int printk(const char *s, ...)
-       __attribute__ ((format (printf, 1, 2)));
-static inline int __cold printk(const char *s, ...) { return 0; }
-static inline int printk_ratelimit(void) { return 0; }
-static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \
-                                         unsigned int interval_msec)   \
-               { return false; }
-
-/* No effect, but we still get type checking even in the !PRINTK case: */
-#define printk_once(x...) printk(x)
-
-static inline void log_buf_kexec_setup(void)
-{
-}
-#endif
-
-/*
- * Dummy printk for disabled debugging statements to use whilst maintaining
- * gcc's format and side-effect checking.
- */
-static inline __attribute__ ((format (printf, 1, 2)))
-int no_printk(const char *s, ...) { return 0; }
-
-extern int printk_needs_cpu(int cpu);
-extern void printk_tick(void);
-
-extern void asmlinkage __attribute__((format(printf, 1, 2)))
-       early_printk(const char *fmt, ...);
-
 unsigned long int_sqrt(unsigned long);
 
-static inline void console_silent(void)
-{
-       console_loglevel = 0;
-}
-
-static inline void console_verbose(void)
-{
-       if (console_loglevel)
-               console_loglevel = 15;
-}
-
 extern void bust_spinlocks(int yes);
 extern void wake_up_klogd(void);
 extern int oops_in_progress;           /* If set, an oops, panic(), BUG() or die() is in progress */
@@ -389,22 +251,6 @@ extern enum system_states {
 #define TAINT_CRAP                     10
 #define TAINT_FIRMWARE_WORKAROUND      11
 
-extern void dump_stack(void) __cold;
-
-enum {
-       DUMP_PREFIX_NONE,
-       DUMP_PREFIX_ADDRESS,
-       DUMP_PREFIX_OFFSET
-};
-extern void hex_dump_to_buffer(const void *buf, size_t len,
-                               int rowsize, int groupsize,
-                               char *linebuf, size_t linebuflen, bool ascii);
-extern void print_hex_dump(const char *level, const char *prefix_str,
-                               int prefix_type, int rowsize, int groupsize,
-                               const void *buf, size_t len, bool ascii);
-extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
-                       const void *buf, size_t len);
-
 extern const char hex_asc[];
 #define hex_asc_lo(x)  hex_asc[((x) & 0x0f)]
 #define hex_asc_hi(x)  hex_asc[((x) & 0xf0) >> 4]
@@ -418,94 +264,6 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
 
 extern int hex_to_bin(char ch);
 
-#ifndef pr_fmt
-#define pr_fmt(fmt) fmt
-#endif
-
-#define pr_emerg(fmt, ...) \
-        printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_alert(fmt, ...) \
-        printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_crit(fmt, ...) \
-        printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_err(fmt, ...) \
-        printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_warning(fmt, ...) \
-        printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_warn pr_warning
-#define pr_notice(fmt, ...) \
-        printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_info(fmt, ...) \
-        printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_cont(fmt, ...) \
-       printk(KERN_CONT fmt, ##__VA_ARGS__)
-
-/* pr_devel() should produce zero code unless DEBUG is defined */
-#ifdef DEBUG
-#define pr_devel(fmt, ...) \
-       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-#else
-#define pr_devel(fmt, ...) \
-       ({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
-#endif
-
-/* If you are writing a driver, please use dev_dbg instead */
-#if defined(DEBUG)
-#define pr_debug(fmt, ...) \
-       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
-/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
-#define pr_debug(fmt, ...) \
-       dynamic_pr_debug(fmt, ##__VA_ARGS__)
-#else
-#define pr_debug(fmt, ...) \
-       ({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
-#endif
-
-/*
- * ratelimited messages with local ratelimit_state,
- * no local ratelimit_state used in the !PRINTK case
- */
-#ifdef CONFIG_PRINTK
-#define printk_ratelimited(fmt, ...)  ({                               \
-       static DEFINE_RATELIMIT_STATE(_rs,                              \
-                                     DEFAULT_RATELIMIT_INTERVAL,       \
-                                     DEFAULT_RATELIMIT_BURST);         \
-                                                                       \
-       if (__ratelimit(&_rs))                                          \
-               printk(fmt, ##__VA_ARGS__);                             \
-})
-#else
-/* No effect, but we still get type checking even in the !PRINTK case: */
-#define printk_ratelimited printk
-#endif
-
-#define pr_emerg_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_alert_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_crit_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_err_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_warning_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_warn_ratelimited pr_warning_ratelimited
-#define pr_notice_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
-#define pr_info_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
-/* no pr_cont_ratelimited, don't do that... */
-/* If you are writing a driver, please use dev_dbg instead */
-#if defined(DEBUG)
-#define pr_debug_ratelimited(fmt, ...) \
-       printk_ratelimited(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-#else
-#define pr_debug_ratelimited(fmt, ...) \
-       ({ if (0) printk_ratelimited(KERN_DEBUG pr_fmt(fmt), \
-                                    ##__VA_ARGS__); 0; })
-#endif
-
 /*
  * General tracing related utility functions - trace_printk(),
  * tracing_on/tracing_off and tracing_start()/tracing_stop
diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h
new file mode 100644 (file)
index 0000000..38368d7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * LP5521 LED chip driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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_LP5521_H
+#define __LINUX_LP5521_H
+
+/* See Documentation/leds/leds-lp5521.txt */
+
+struct lp5521_led_config {
+       u8              chan_nr;
+       u8              led_current; /* mA x10, 0 if led is not connected */
+       u8              max_current;
+};
+
+#define LP5521_CLOCK_AUTO      0
+#define LP5521_CLOCK_INT       1
+#define LP5521_CLOCK_EXT       2
+
+struct lp5521_platform_data {
+       struct lp5521_led_config *led_config;
+       u8      num_channels;
+       u8      clock_mode;
+       int     (*setup_resources)(void);
+       void    (*release_resources)(void);
+       void    (*enable)(bool state);
+};
+
+#endif /* __LINUX_LP5521_H */
diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h
new file mode 100644 (file)
index 0000000..7967476
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * LP5523 LED Driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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_LP5523_H
+#define __LINUX_LP5523_H
+
+/* See Documentation/leds/leds-lp5523.txt */
+
+struct lp5523_led_config {
+       u8              chan_nr;
+       u8              led_current; /* mA x10, 0 if led is not connected */
+       u8              max_current;
+};
+
+#define LP5523_CLOCK_AUTO      0
+#define LP5523_CLOCK_INT       1
+#define LP5523_CLOCK_EXT       2
+
+struct lp5523_platform_data {
+       struct lp5523_led_config *led_config;
+       u8      num_channels;
+       u8      clock_mode;
+       int     (*setup_resources)(void);
+       void    (*release_resources)(void);
+       void    (*enable)(bool state);
+};
+
+#endif /* __LINUX_LP5523_H */
index ba6986a11663a417625a259a612019df46f0ad97..0f19df9e37b0fec0394d0350abf86a3aa63cc518 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
+#include <linux/timer.h>
 
 struct device;
 /*
@@ -45,10 +46,14 @@ struct led_classdev {
        /* Get LED brightness level */
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
 
-       /* Activate hardware accelerated blink, delays are in
-        * miliseconds and if none is provided then a sensible default
-        * should be chosen. The call can adjust the timings if it can't
-        * match the values specified exactly. */
+       /*
+        * Activate hardware accelerated blink, delays are in milliseconds
+        * and if both are zero then a sensible default should be chosen.
+        * The call should adjust the timings in that case and if it can't
+        * match the values specified exactly.
+        * Deactivate blinking again when the brightness is set to a fixed
+        * value via the brightness_set() callback.
+        */
        int             (*blink_set)(struct led_classdev *led_cdev,
                                     unsigned long *delay_on,
                                     unsigned long *delay_off);
@@ -57,6 +62,10 @@ struct led_classdev {
        struct list_head         node;                  /* LED Device list */
        const char              *default_trigger;       /* Trigger to use */
 
+       unsigned long            blink_delay_on, blink_delay_off;
+       struct timer_list        blink_timer;
+       int                      blink_brightness;
+
 #ifdef CONFIG_LEDS_TRIGGERS
        /* Protects the trigger data below */
        struct rw_semaphore      trigger_lock;
@@ -73,6 +82,36 @@ extern void led_classdev_unregister(struct led_classdev *led_cdev);
 extern void led_classdev_suspend(struct led_classdev *led_cdev);
 extern void led_classdev_resume(struct led_classdev *led_cdev);
 
+/**
+ * led_blink_set - set blinking with software fallback
+ * @led_cdev: the LED to start blinking
+ * @delay_on: the time it should be on (in ms)
+ * @delay_off: the time it should ble off (in ms)
+ *
+ * This function makes the LED blink, attempting to use the
+ * hardware acceleration if possible, but falling back to
+ * software blinking if there is no hardware blinking or if
+ * the LED refuses the passed values.
+ *
+ * Note that if software blinking is active, simply calling
+ * led_cdev->brightness_set() will not stop the blinking,
+ * use led_classdev_brightness_set() instead.
+ */
+extern void led_blink_set(struct led_classdev *led_cdev,
+                         unsigned long *delay_on,
+                         unsigned long *delay_off);
+/**
+ * led_brightness_set - set LED brightness
+ * @led_cdev: the LED to set
+ * @brightness: the brightness to set it to
+ *
+ * Set an LED's brightness, and, if necessary, cancel the
+ * software blink timer that implements blinking when the
+ * hardware doesn't.
+ */
+extern void led_brightness_set(struct led_classdev *led_cdev,
+                              enum led_brightness brightness);
+
 /*
  * LED Triggers
  */
index 15b77b8dc7e11f529b93cc9ba629f464627d3a74..d947b1231662b9f69b388d0c5e3393972285faa3 100644 (file)
@@ -986,7 +986,7 @@ extern void ata_host_init(struct ata_host *, struct device *,
                          unsigned long, struct ata_port_operations *);
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
-extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
                            int cmd, void __user *arg);
 extern void ata_sas_port_destroy(struct ata_port *);
index a34dea46b62953cb2675f6b17c7539431f54114b..2dee05e5119a42138dda84e6aca032215994cfa0 100644 (file)
@@ -43,6 +43,7 @@ struct nlm_host {
        struct sockaddr_storage h_addr;         /* peer address */
        size_t                  h_addrlen;
        struct sockaddr_storage h_srcaddr;      /* our address (optional) */
+       size_t                  h_srcaddrlen;
        struct rpc_clnt         *h_rpcclnt;     /* RPC client to talk to peer */
        char                    *h_name;                /* remote hostname */
        u32                     h_version;      /* interface version */
index 1ff81b51b656a13f32c4d8b5253f803593cd033b..dd3c34ebca9a67e05c2e59649da81486210e802c 100644 (file)
@@ -11,6 +11,7 @@
 #define MARVELL_PHY_ID_88E1118         0x01410e10
 #define MARVELL_PHY_ID_88E1121R                0x01410cb0
 #define MARVELL_PHY_ID_88E1145         0x01410cd0
+#define MARVELL_PHY_ID_88E1149R                0x01410e50
 #define MARVELL_PHY_ID_88E1240         0x01410e30
 #define MARVELL_PHY_ID_88E1318S                0x01410e90
 
index d19e2114fd867782dc8a71b7b12367a9eff561ad..5c99da1078aa2e2906e0cc8f06428c231f76970a 100644 (file)
@@ -59,19 +59,19 @@ struct sh_mmcif_plat_data {
 #define MMCIF_CE_HOST_STS2     0x0000004C
 #define MMCIF_CE_VERSION       0x0000007C
 
-extern inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
+static inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
 {
        return readl(addr + reg);
 }
 
-extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
+static inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
 {
        writel(val, addr + reg);
 }
 
 #define SH_MMCIF_BBS 512 /* boot block size */
 
-extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
+static inline void sh_mmcif_boot_cmd_send(void __iomem *base,
                                          unsigned long cmd, unsigned long arg)
 {
        sh_mmcif_writel(base, MMCIF_CE_INT, 0);
@@ -79,7 +79,7 @@ extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
        sh_mmcif_writel(base, MMCIF_CE_CMD_SET, cmd);
 }
 
-extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
+static inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
 {
        unsigned long tmp;
        int cnt;
@@ -95,14 +95,14 @@ extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
        return -1;
 }
 
-extern inline int sh_mmcif_boot_cmd(void __iomem *base,
+static inline int sh_mmcif_boot_cmd(void __iomem *base,
                                    unsigned long cmd, unsigned long arg)
 {
        sh_mmcif_boot_cmd_send(base, cmd, arg);
        return sh_mmcif_boot_cmd_poll(base, 0x00010000);
 }
 
-extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
+static inline int sh_mmcif_boot_do_read_single(void __iomem *base,
                                               unsigned int block_nr,
                                               unsigned long *buf)
 {
@@ -125,7 +125,7 @@ extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
        return 0;
 }
 
-extern inline int sh_mmcif_boot_do_read(void __iomem *base,
+static inline int sh_mmcif_boot_do_read(void __iomem *base,
                                        unsigned long first_block,
                                        unsigned long nr_blocks,
                                        void *buf)
@@ -143,7 +143,7 @@ extern inline int sh_mmcif_boot_do_read(void __iomem *base,
        return ret;
 }
 
-extern inline void sh_mmcif_boot_init(void __iomem *base)
+static inline void sh_mmcif_boot_init(void __iomem *base)
 {
        unsigned long tmp;
 
@@ -177,7 +177,7 @@ extern inline void sh_mmcif_boot_init(void __iomem *base)
        sh_mmcif_boot_cmd(base, 0x03400040, 0x00010000);
 }
 
-extern inline void sh_mmcif_boot_slurp(void __iomem *base,
+static inline void sh_mmcif_boot_slurp(void __iomem *base,
                                       unsigned char *buf,
                                       unsigned long no_bytes)
 {
index 072652d94d9f5afe908f982c1acce9339bfbfc32..d8fd2c23a1b994ec10e0a204820d6c7daf7dca0e 100644 (file)
@@ -1554,6 +1554,11 @@ static inline void netif_tx_wake_all_queues(struct net_device *dev)
 
 static inline void netif_tx_stop_queue(struct netdev_queue *dev_queue)
 {
+       if (WARN_ON(!dev_queue)) {
+               printk(KERN_INFO "netif_stop_queue() cannot be called before "
+                      "register_netdev()");
+               return;
+       }
        set_bit(__QUEUE_STATE_XOFF, &dev_queue->state);
 }
 
index 89341c32631a5f965b1a65f757db1d7fb004cc30..03317c8d4077a6488148b646ee9327b05a7dcec1 100644 (file)
@@ -215,7 +215,7 @@ NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb,
        int ret;
 
        if (!cond ||
-           (ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN) == 1))
+           ((ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN)) == 1))
                ret = okfn(skb);
        return ret;
 }
index bba26684acdc5e0e9364419db9cc3fb7802c1109..c66fdb7d6998129701f6eaa653f1d28dd641e332 100644 (file)
@@ -593,12 +593,6 @@ nfs_fileid_to_ino_t(u64 fileid)
        return ino;
 }
 
-#define nfs_wait_event(clnt, wq, condition)                            \
-({                                                                     \
-       int __retval = wait_event_killable(wq, condition);              \
-       __retval;                                                       \
-})
-
 #define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
 
 #endif /* __KERNEL__ */
index 057bf22a8323463a6bd9279d6928d3fea7ed8eb8..40150f345982cd4fd40e8b80470505e569f05b03 100644 (file)
@@ -747,6 +747,16 @@ struct perf_event {
        u64                             tstamp_running;
        u64                             tstamp_stopped;
 
+       /*
+        * timestamp shadows the actual context timing but it can
+        * be safely used in NMI interrupt context. It reflects the
+        * context time as it was when the event was last scheduled in.
+        *
+        * ctx_time already accounts for ctx->timestamp. Therefore to
+        * compute ctx_time for a sample, simply add perf_clock().
+        */
+       u64                             shadow_ctx_time;
+
        struct perf_event_attr          attr;
        struct hw_perf_event            hw;
 
diff --git a/include/linux/printk.h b/include/linux/printk.h
new file mode 100644 (file)
index 0000000..b772ca5
--- /dev/null
@@ -0,0 +1,248 @@
+#ifndef __KERNEL_PRINTK__
+#define __KERNEL_PRINTK__
+
+extern const char linux_banner[];
+extern const char linux_proc_banner[];
+
+#define        KERN_EMERG      "<0>"   /* system is unusable                   */
+#define        KERN_ALERT      "<1>"   /* action must be taken immediately     */
+#define        KERN_CRIT       "<2>"   /* critical conditions                  */
+#define        KERN_ERR        "<3>"   /* error conditions                     */
+#define        KERN_WARNING    "<4>"   /* warning conditions                   */
+#define        KERN_NOTICE     "<5>"   /* normal but significant condition     */
+#define        KERN_INFO       "<6>"   /* informational                        */
+#define        KERN_DEBUG      "<7>"   /* debug-level messages                 */
+
+/* Use the default kernel loglevel */
+#define KERN_DEFAULT   "<d>"
+/*
+ * Annotation for a "continued" line of log printout (only done after a
+ * line that had no enclosing \n). Only to be used by core/arch code
+ * during early bootup (a continued line is not SMP-safe otherwise).
+ */
+#define        KERN_CONT       "<c>"
+
+extern int console_printk[];
+
+#define console_loglevel (console_printk[0])
+#define default_message_loglevel (console_printk[1])
+#define minimum_console_loglevel (console_printk[2])
+#define default_console_loglevel (console_printk[3])
+
+struct va_format {
+       const char *fmt;
+       va_list *va;
+};
+
+/*
+ * FW_BUG
+ * Add this to a message where you are sure the firmware is buggy or behaves
+ * really stupid or out of spec. Be aware that the responsible BIOS developer
+ * should be able to fix this issue or at least get a concrete idea of the
+ * problem by reading your message without the need of looking at the kernel
+ * code.
+ *
+ * Use it for definite and high priority BIOS bugs.
+ *
+ * FW_WARN
+ * Use it for not that clear (e.g. could the kernel messed up things already?)
+ * and medium priority BIOS bugs.
+ *
+ * FW_INFO
+ * Use this one if you want to tell the user or vendor about something
+ * suspicious, but generally harmless related to the firmware.
+ *
+ * Use it for information or very low priority BIOS bugs.
+ */
+#define FW_BUG         "[Firmware Bug]: "
+#define FW_WARN                "[Firmware Warn]: "
+#define FW_INFO                "[Firmware Info]: "
+
+/*
+ * HW_ERR
+ * Add this to a message for hardware errors, so that user can report
+ * it to hardware vendor instead of LKML or software vendor.
+ */
+#define HW_ERR         "[Hardware Error]: "
+
+#ifdef CONFIG_PRINTK
+asmlinkage int vprintk(const char *fmt, va_list args)
+       __attribute__ ((format (printf, 1, 0)));
+asmlinkage int printk(const char * fmt, ...)
+       __attribute__ ((format (printf, 1, 2))) __cold;
+
+/*
+ * Please don't use printk_ratelimit(), because it shares ratelimiting state
+ * with all other unrelated printk_ratelimit() callsites.  Instead use
+ * printk_ratelimited() or plain old __ratelimit().
+ */
+extern int __printk_ratelimit(const char *func);
+#define printk_ratelimit() __printk_ratelimit(__func__)
+extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
+                                  unsigned int interval_msec);
+
+extern int printk_delay_msec;
+extern int dmesg_restrict;
+
+/*
+ * Print a one-time message (analogous to WARN_ONCE() et al):
+ */
+#define printk_once(x...) ({                   \
+       static bool __print_once;               \
+                                               \
+       if (!__print_once) {                    \
+               __print_once = true;            \
+               printk(x);                      \
+       }                                       \
+})
+
+void log_buf_kexec_setup(void);
+#else
+static inline int vprintk(const char *s, va_list args)
+       __attribute__ ((format (printf, 1, 0)));
+static inline int vprintk(const char *s, va_list args) { return 0; }
+static inline int printk(const char *s, ...)
+       __attribute__ ((format (printf, 1, 2)));
+static inline int __cold printk(const char *s, ...) { return 0; }
+static inline int printk_ratelimit(void) { return 0; }
+static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \
+                                         unsigned int interval_msec)   \
+               { return false; }
+
+/* No effect, but we still get type checking even in the !PRINTK case: */
+#define printk_once(x...) printk(x)
+
+static inline void log_buf_kexec_setup(void)
+{
+}
+#endif
+
+/*
+ * Dummy printk for disabled debugging statements to use whilst maintaining
+ * gcc's format and side-effect checking.
+ */
+static inline __attribute__ ((format (printf, 1, 2)))
+int no_printk(const char *s, ...) { return 0; }
+
+extern int printk_needs_cpu(int cpu);
+extern void printk_tick(void);
+
+extern void asmlinkage __attribute__((format(printf, 1, 2)))
+       early_printk(const char *fmt, ...);
+
+static inline void console_silent(void)
+{
+       console_loglevel = 0;
+}
+
+static inline void console_verbose(void)
+{
+       if (console_loglevel)
+               console_loglevel = 15;
+}
+
+extern void dump_stack(void) __cold;
+
+enum {
+       DUMP_PREFIX_NONE,
+       DUMP_PREFIX_ADDRESS,
+       DUMP_PREFIX_OFFSET
+};
+extern void hex_dump_to_buffer(const void *buf, size_t len,
+                               int rowsize, int groupsize,
+                               char *linebuf, size_t linebuflen, bool ascii);
+extern void print_hex_dump(const char *level, const char *prefix_str,
+                               int prefix_type, int rowsize, int groupsize,
+                               const void *buf, size_t len, bool ascii);
+extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
+                       const void *buf, size_t len);
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+
+#define pr_emerg(fmt, ...) \
+        printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_alert(fmt, ...) \
+        printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_crit(fmt, ...) \
+        printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_err(fmt, ...) \
+        printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warning(fmt, ...) \
+        printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn pr_warning
+#define pr_notice(fmt, ...) \
+        printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info(fmt, ...) \
+        printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_cont(fmt, ...) \
+       printk(KERN_CONT fmt, ##__VA_ARGS__)
+
+/* pr_devel() should produce zero code unless DEBUG is defined */
+#ifdef DEBUG
+#define pr_devel(fmt, ...) \
+       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define pr_devel(fmt, ...) \
+       ({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
+#endif
+
+/* If you are writing a driver, please use dev_dbg instead */
+#if defined(DEBUG)
+#define pr_debug(fmt, ...) \
+       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#elif defined(CONFIG_DYNAMIC_DEBUG)
+/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
+#define pr_debug(fmt, ...) \
+       dynamic_pr_debug(fmt, ##__VA_ARGS__)
+#else
+#define pr_debug(fmt, ...) \
+       ({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; })
+#endif
+
+/*
+ * ratelimited messages with local ratelimit_state,
+ * no local ratelimit_state used in the !PRINTK case
+ */
+#ifdef CONFIG_PRINTK
+#define printk_ratelimited(fmt, ...)  ({                               \
+       static DEFINE_RATELIMIT_STATE(_rs,                              \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST);         \
+                                                                       \
+       if (__ratelimit(&_rs))                                          \
+               printk(fmt, ##__VA_ARGS__);                             \
+})
+#else
+/* No effect, but we still get type checking even in the !PRINTK case: */
+#define printk_ratelimited printk
+#endif
+
+#define pr_emerg_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_alert_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_crit_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_err_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warning_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn_ratelimited pr_warning_ratelimited
+#define pr_notice_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+/* no pr_cont_ratelimited, don't do that... */
+/* If you are writing a driver, please use dev_dbg instead */
+#if defined(DEBUG)
+#define pr_debug_ratelimited(fmt, ...) \
+       printk_ratelimited(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define pr_debug_ratelimited(fmt, ...) \
+       ({ if (0) printk_ratelimited(KERN_DEBUG pr_fmt(fmt), \
+                                    ##__VA_ARGS__); 0; })
+#endif
+
+#endif
index 01b3d759f1fccec7f88e1b276973aa6f70e5bae5..e031e1a486d9fc8e7d7d6539c75d39df1235d2c2 100644 (file)
@@ -8,6 +8,7 @@ struct platform_pwm_backlight_data {
        int pwm_id;
        unsigned int max_brightness;
        unsigned int dft_brightness;
+       unsigned int lth_brightness;
        unsigned int pwm_period_ns;
        int (*init)(struct device *dev);
        int (*notify)(struct device *dev, int brightness);
index a39cbed9ee17a5d771f7c3e7ca129e3a05171220..ab2baa5c488453cba50bf564d6220038d0224867 100644 (file)
  * needed for RCU lookups (because root->height is unreliable). The only
  * time callers need worry about this is when doing a lookup_slot under
  * RCU.
+ *
+ * Indirect pointer in fact is also used to tag the last pointer of a node
+ * when it is shrunk, before we rcu free the node. See shrink code for
+ * details.
  */
 #define RADIX_TREE_INDIRECT_PTR        1
-#define RADIX_TREE_RETRY ((void *)-1UL)
-
-static inline void *radix_tree_ptr_to_indirect(void *ptr)
-{
-       return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR);
-}
 
-static inline void *radix_tree_indirect_to_ptr(void *ptr)
-{
-       return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR);
-}
 #define radix_tree_indirect_to_ptr(ptr) \
        radix_tree_indirect_to_ptr((void __force *)(ptr))
 
@@ -140,16 +134,29 @@ do {                                                                      \
  *             removed.
  *
  * For use with radix_tree_lookup_slot().  Caller must hold tree at least read
- * locked across slot lookup and dereference.  More likely, will be used with
- * radix_tree_replace_slot(), as well, so caller will hold tree write locked.
+ * locked across slot lookup and dereference. Not required if write lock is
+ * held (ie. items cannot be concurrently inserted).
+ *
+ * radix_tree_deref_retry must be used to confirm validity of the pointer if
+ * only the read lock is held.
  */
 static inline void *radix_tree_deref_slot(void **pslot)
 {
-       void *ret = rcu_dereference(*pslot);
-       if (unlikely(radix_tree_is_indirect_ptr(ret)))
-               ret = RADIX_TREE_RETRY;
-       return ret;
+       return rcu_dereference(*pslot);
 }
+
+/**
+ * radix_tree_deref_retry      - check radix_tree_deref_slot
+ * @arg:       pointer returned by radix_tree_deref_slot
+ * Returns:    0 if retry is not required, otherwise retry is required
+ *
+ * radix_tree_deref_retry must be used with radix_tree_deref_slot.
+ */
+static inline int radix_tree_deref_retry(void *arg)
+{
+       return unlikely((unsigned long)arg & RADIX_TREE_INDIRECT_PTR);
+}
+
 /**
  * radix_tree_replace_slot     - replace item in a slot
  * @pslot:     pointer to slot, returned by radix_tree_lookup_slot
index 5ca47e59b7278ffbb0dd4fc624d9e4cf1697d0ae..c21072adbfad7e84417b8cf925e2fc0b21172cea 100644 (file)
@@ -22,7 +22,6 @@
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/reiserfs_fs_i.h>
 #include <linux/reiserfs_fs_sb.h>
index 88d36f9145bacfa34ee6c32823413b09715e6ef2..d01c96c1966e2724460eeaaef3bdd6c522fc7bda 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_RESOURCE_H
 
 #include <linux/time.h>
+#include <linux/types.h>
 
 /*
  * Resource control/accounting header file for linux
index d42f274418b884ea72f8de09cda464af817fd774..bbad657a37259c0f35e99341761a789731435e25 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/if_link.h>
 #include <linux/if_addr.h>
 #include <linux/neighbour.h>
-#include <linux/netdevice.h>
 
 /* rtnetlink families. Values up to 127 are reserved for real address
  * families, values above 128 may be used arbitrarily.
@@ -606,6 +605,7 @@ struct tcamsg {
 #ifdef __KERNEL__
 
 #include <linux/mutex.h>
+#include <linux/netdevice.h>
 
 static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
 {
index d0036e52a24a1c28eaef9e60bb5aa100aaa18af1..2c79e921a68baeb9d5afa9b0deaa731232685ed5 100644 (file)
@@ -862,6 +862,7 @@ struct sched_group {
         * single CPU.
         */
        unsigned int cpu_power, cpu_power_orig;
+       unsigned int group_weight;
 
        /*
         * The CPUs this group covers.
index b8246a8df7d2dc2ecc864ac192d694b369dd12d6..fd4d55fb884539fa0954937b0bbf5945e8bd5a6b 100644 (file)
@@ -77,7 +77,6 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 extern int cap_task_setscheduler(struct task_struct *p);
 extern int cap_task_setioprio(struct task_struct *p, int ioprio);
 extern int cap_task_setnice(struct task_struct *p, int nice);
-extern int cap_syslog(int type, bool from_file);
 extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
 
 struct msghdr;
@@ -1388,7 +1387,7 @@ struct security_operations {
        int (*sysctl) (struct ctl_table *table, int op);
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
        int (*quota_on) (struct dentry *dentry);
-       int (*syslog) (int type, bool from_file);
+       int (*syslog) (int type);
        int (*settime) (struct timespec *ts, struct timezone *tz);
        int (*vm_enough_memory) (struct mm_struct *mm, long pages);
 
@@ -1671,7 +1670,7 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap);
 int security_sysctl(struct ctl_table *table, int op);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
 int security_quota_on(struct dentry *dentry);
-int security_syslog(int type, bool from_file);
+int security_syslog(int type);
 int security_settime(struct timespec *ts, struct timezone *tz);
 int security_vm_enough_memory(long pages);
 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
@@ -1901,9 +1900,9 @@ static inline int security_quota_on(struct dentry *dentry)
        return 0;
 }
 
-static inline int security_syslog(int type, bool from_file)
+static inline int security_syslog(int type)
 {
-       return cap_syslog(type, from_file);
+       return 0;
 }
 
 static inline int security_settime(struct timespec *ts, struct timezone *tz)
index 4dca992f3093771993ac9d98d1233df5e2f33cfa..cea0c38e7a63dfad2544043c49fca25aea9a7563 100644 (file)
@@ -122,6 +122,10 @@ int clk_rate_table_find(struct clk *clk,
 long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
                              unsigned int div_max, unsigned long rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max);
+
 #define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)       \
 {                                                                      \
        .parent         = _parent,                                      \
index f656d1a43dc0219ebfd43fddc7cfe2b86eded613..5812fefbcedf1ac2685760c1d40fff52076cf054 100644 (file)
@@ -79,7 +79,7 @@ struct intc_hw_desc {
        unsigned int nr_subgroups;
 };
 
-#define _INTC_ARRAY(a) a, a == NULL ? 0 : sizeof(a)/sizeof(*a)
+#define _INTC_ARRAY(a) a, __same_type(a, NULL) ? 0 : sizeof(a)/sizeof(*a)
 
 #define INTC_HW_DESC(vectors, groups, mask_regs,       \
                     prio_regs, sense_regs, ack_regs)   \
index 864bd56bd3b0ba08a84958ff5d06e647d643e208..4d9dcd1383150088f598f0d0d58f7d51e7400046 100644 (file)
@@ -5,7 +5,6 @@ struct sh_timer_config {
        char *name;
        long channel_offset;
        int timer_bit;
-       char *clk;
        unsigned long clockevent_rating;
        unsigned long clocksource_rating;
 };
index 291f721144c2e23c51e4fbb92288f89e6b68dc11..3a1988202731e55563315703ed3f5cfb52f8abc9 100644 (file)
@@ -4,8 +4,6 @@
 #ifdef CONFIG_LOCK_KERNEL
 #include <linux/sched.h>
 
-#define kernel_locked()                (current->lock_depth >= 0)
-
 extern int __lockfunc __reacquire_kernel_lock(void);
 extern void __lockfunc __release_kernel_lock(void);
 
@@ -58,7 +56,6 @@ static inline void cycle_kernel_lock(void)
 #define lock_kernel()
 #define unlock_kernel()
 #define cycle_kernel_lock()                    do { } while(0)
-#define kernel_locked()                                1
 #endif /* CONFIG_BKL */
 
 #define release_kernel_lock(task)              do { } while(0)
index bbdb680ffbe9d46f31de3f88d82d48869543920f..aea0d438e3c716b3a0f62612f15e43b9abe1e2d8 100644 (file)
@@ -82,18 +82,28 @@ struct svc_xprt {
        struct net              *xpt_net;
 };
 
-static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
 {
        spin_lock(&xpt->xpt_lock);
-       list_add(&u->list, &xpt->xpt_users);
+       list_del_init(&u->list);
        spin_unlock(&xpt->xpt_lock);
 }
 
-static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
 {
        spin_lock(&xpt->xpt_lock);
-       list_del_init(&u->list);
+       if (test_bit(XPT_CLOSE, &xpt->xpt_flags)) {
+               /*
+                * The connection is about to be deleted soon (or,
+                * worse, may already be deleted--in which case we've
+                * already notified the xpt_users).
+                */
+               spin_unlock(&xpt->xpt_lock);
+               return -ENOTCONN;
+       }
+       list_add(&u->list, &xpt->xpt_users);
        spin_unlock(&xpt->xpt_lock);
+       return 0;
 }
 
 int    svc_reg_xprt_class(struct svc_xprt_class *);
index 2a754748dd5f3ea049ee293acf8d548aea927da9..032d79ff1d9d4ec7fcfb313261b27548f1d5f3dd 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_ldisc.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 
@@ -50,7 +49,7 @@
 #define N_V253         19      /* Codec control over voice modem */
 #define N_CAIF         20      /* CAIF protocol for talking to modems */
 #define N_GSM0710      21      /* GSM 0710 Mux */
-#define N_TI_WL        22      /* for TI's WL BT, FM, GPS combo chips */
+#define N_TI_WL                22      /* for TI's WL BT, FM, GPS combo chips */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
index 35fe6ab222bbb8c1247ab73fa7ccad96289b13f6..24300d8a1bc16eaf18c647056842102b47283980 100644 (file)
@@ -797,7 +797,7 @@ struct usbdrv_wrap {
  * @disconnect: Called when the interface is no longer accessible, usually
  *     because its device has been (or is being) disconnected or the
  *     driver module is being unloaded.
- * @ioctl: Used for drivers that want to talk to userspace through
+ * @unlocked_ioctl: Used for drivers that want to talk to userspace through
  *     the "usbfs" filesystem.  This lets devices provide ways to
  *     expose information to user space regardless of where they
  *     do (or don't) show up otherwise in the filesystem.
index ee2dd1d506ed575cd795963dc8cad50c7aefa419..2387f9fc81381dd517c7d3008de21aeb5790c0da 100644 (file)
@@ -89,6 +89,8 @@ struct musb_hdrc_config {
        /* A GPIO controlling VRSEL in Blackfin */
        unsigned int    gpio_vrsel;
        unsigned int    gpio_vrsel_active;
+       /* musb CLKIN in Blackfin in MHZ */
+       unsigned char   clkin;
 #endif
 
 };
index 6da573c75d54cfdde09f449f6cd3dd617c49fa20..8eff83b95366049b6f55d9efd268952453329227 100644 (file)
@@ -28,7 +28,7 @@ struct caif_param {
  * @sockaddr:          Socket address to connect.
  * @priority:          Priority of the connection.
  * @link_selector:     Link selector (high bandwidth or low latency)
- * @link_name:         Name of the CAIF Link Layer to use.
+ * @ifindex:           kernel index of the interface.
  * @param:             Connect Request parameters (CAIF_SO_REQ_PARAM).
  *
  * This struct is used when connecting a CAIF channel.
@@ -39,7 +39,7 @@ struct caif_connect_request {
        struct sockaddr_caif sockaddr;
        enum caif_channel_priority priority;
        enum caif_link_selector link_selector;
-       char link_name[16];
+       int ifindex;
        struct caif_param param;
 };
 
index ce4570dff020720c2ca6d5e22a0202a78c5c42c5..87c3d11b8e555ff2ebd9a07f504cd8ab2b5fcebd 100644 (file)
@@ -121,6 +121,8 @@ struct cfspi {
        wait_queue_head_t wait;
        spinlock_t lock;
        bool flow_stop;
+       bool slave;
+       bool slave_talked;
 #ifdef CONFIG_DEBUG_FS
        enum cfspi_state dbg_state;
        u16 pcmd;
index bd646faffa47bd8cd46ed4f15e1988c7bfac8247..f688478bfb84a4afc62039e57e212978ab24929b 100644 (file)
@@ -139,10 +139,10 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
                     enum cfcnfg_phy_preference phy_pref);
 
 /**
- * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer
+ * cfcnfg_get_id_from_ifi() - Get the Physical Identifier of ifindex,
+ *                     it matches caif physical id with the kernel interface id.
  * @cnfg:      Configuration object
- * @name:      Name of the Physical Layer (Caif Link Layer)
+ * @ifi:       ifindex obtained from socket.c bindtodevice.
  */
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name);
-
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi);
 #endif                         /* CFCNFG_H_ */
index 2a7936d7851d55de60251fc708672a87d5beb81b..97b8b7c9b63cf9854e3b8c2e83154c8ecb0bea06 100644 (file)
@@ -1355,7 +1355,7 @@ enum wiphy_flags {
        WIPHY_FLAG_4ADDR_AP                     = BIT(5),
        WIPHY_FLAG_4ADDR_STATION                = BIT(6),
        WIPHY_FLAG_CONTROL_PORT_PROTOCOL        = BIT(7),
-       WIPHY_FLAG_IBSS_RSN                     = BIT(7),
+       WIPHY_FLAG_IBSS_RSN                     = BIT(8),
 };
 
 struct mac_address {
index e5469f7b67a3b17d7916188a822348214120a81e..a514a3cf45730df7083e8c2169e90d3a4bc9084e 100644 (file)
@@ -225,7 +225,7 @@ extern int decnet_di_count;
 extern int decnet_dr_count;
 extern int decnet_no_fc_max_cwnd;
 
-extern int sysctl_decnet_mem[3];
+extern long sysctl_decnet_mem[3];
 extern int sysctl_decnet_wmem[3];
 extern int sysctl_decnet_rmem[3];
 
index 1fa5306e3e230d8340b3d01fb5ce5f99a679a6fd..51665b3461b8f9ba501c296d8a2259ecb92ae92c 100644 (file)
@@ -2,6 +2,7 @@
 #define _NET_DST_OPS_H
 #include <linux/types.h>
 #include <linux/percpu_counter.h>
+#include <linux/cache.h>
 
 struct dst_entry;
 struct kmem_cachep;
index 55590ab16b3ed5192413b4b6415a8785c1d1a5bb..6beb1ffc2b7fcfe9d360717ccde3f70bd8ac0e3d 100644 (file)
@@ -303,7 +303,7 @@ static inline void neigh_confirm(struct neighbour *neigh)
 
 static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
 {
-       unsigned long now = ACCESS_ONCE(jiffies);
+       unsigned long now = jiffies;
        
        if (neigh->used != now)
                neigh->used = now;
index f3b201d335b3532858c846a8aadb1672de80dce3..9801c55de5d64e5357006f9cfb129bce139572dd 100644 (file)
@@ -384,7 +384,7 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
  *
  * Returns the first attribute which matches the specified type.
  */
-static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh,
+static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh,
                                             int hdrlen, int attrtype)
 {
        return nla_find(nlmsg_attrdata(nlh, hdrlen),
index c7a736228ca2dcab930f7f4a9f07d5fda2858c7c..a6338d039857bf6b00bcff087f974ebf46ae0875 100644 (file)
@@ -762,7 +762,7 @@ struct proto {
 
        /* Memory pressure */
        void                    (*enter_memory_pressure)(struct sock *sk);
-       atomic_t                *memory_allocated;      /* Current allocated memory. */
+       atomic_long_t           *memory_allocated;      /* Current allocated memory. */
        struct percpu_counter   *sockets_allocated;     /* Current number of sockets. */
        /*
         * Pressure flag: try to collapse.
@@ -771,7 +771,7 @@ struct proto {
         * is strict, actions are advisory and have some latency.
         */
        int                     *memory_pressure;
-       int                     *sysctl_mem;
+       long                    *sysctl_mem;
        int                     *sysctl_wmem;
        int                     *sysctl_rmem;
        int                     max_header;
index 4fee0424af7eff7a053f0eef9376ad2644b2b723..e36c874c7fb16c47138428d4ecc106800c5fe48f 100644 (file)
@@ -224,7 +224,7 @@ extern int sysctl_tcp_fack;
 extern int sysctl_tcp_reordering;
 extern int sysctl_tcp_ecn;
 extern int sysctl_tcp_dsack;
-extern int sysctl_tcp_mem[3];
+extern long sysctl_tcp_mem[3];
 extern int sysctl_tcp_wmem[3];
 extern int sysctl_tcp_rmem[3];
 extern int sysctl_tcp_app_win;
@@ -247,7 +247,7 @@ extern int sysctl_tcp_cookie_size;
 extern int sysctl_tcp_thin_linear_timeouts;
 extern int sysctl_tcp_thin_dupack;
 
-extern atomic_t tcp_memory_allocated;
+extern atomic_long_t tcp_memory_allocated;
 extern struct percpu_counter tcp_sockets_allocated;
 extern int tcp_memory_pressure;
 
@@ -280,7 +280,7 @@ static inline bool tcp_too_many_orphans(struct sock *sk, int shift)
        }
 
        if (sk->sk_wmem_queued > SOCK_MIN_SNDBUF &&
-           atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])
+           atomic_long_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])
                return true;
        return false;
 }
index 200b82848c9a3606b0076c3f8621fb63342af6a9..bb967dd59bf74fa5abac83964486fabc4398cabd 100644 (file)
@@ -105,10 +105,10 @@ static inline struct udp_hslot *udp_hashslot2(struct udp_table *table,
 
 extern struct proto udp_prot;
 
-extern atomic_t udp_memory_allocated;
+extern atomic_long_t udp_memory_allocated;
 
 /* sysctl variables for udp */
-extern int sysctl_udp_mem[3];
+extern long sysctl_udp_mem[3];
 extern int sysctl_udp_rmem_min;
 extern int sysctl_udp_wmem_min;
 
index f986ab7ffe6f040e9e00ac23d404bd8ad31e1f4e..5c4c1678f7be65d2d57d314dc5f583a974a1526e 100644 (file)
@@ -1006,8 +1006,7 @@ void fc_fcp_destroy(struct fc_lport *);
 /*
  * SCSI INTERACTION LAYER
  *****************************/
-int fc_queuecommand(struct scsi_cmnd *,
-                   void (*done)(struct scsi_cmnd *));
+int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
 int fc_eh_abort(struct scsi_cmnd *);
 int fc_eh_device_reset(struct scsi_cmnd *);
 int fc_eh_host_reset(struct scsi_cmnd *);
index ae5196aae1a5311421e72ba22d9b9f43cb748500..b81d969ddc67cbbfde3f4522cf11a7b2f7487509 100644 (file)
@@ -341,8 +341,7 @@ extern int iscsi_eh_abort(struct scsi_cmnd *sc);
 extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
 extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
 extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
-extern int iscsi_queuecommand(struct scsi_cmnd *sc,
-                             void (*done)(struct scsi_cmnd *));
+extern int iscsi_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *sc);
 
 /*
  * iSCSI host helpers.
index 3dec1949f69cd75890368d40700f68399ac68427..90ce527ecf3d02c5c214308dc30098301d9892d5 100644 (file)
@@ -621,8 +621,7 @@ int sas_set_phy_speed(struct sas_phy *phy,
 int sas_phy_enable(struct sas_phy *phy, int enabled);
 int sas_phy_reset(struct sas_phy *phy, int hard_reset);
 int sas_queue_up(struct sas_task *task);
-extern int sas_queuecommand(struct scsi_cmnd *,
-                    void (*scsi_done)(struct scsi_cmnd *));
+extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);
 extern int sas_target_alloc(struct scsi_target *);
 extern int sas_slave_alloc(struct scsi_device *);
 extern int sas_slave_configure(struct scsi_device *);
index d0a6a845f2045fb874481539e0c55d21a70fe7bb..e7e385842a38746d348eee460af6bc3d9e1a2ab6 100644 (file)
@@ -127,8 +127,7 @@ struct scsi_host_template {
         *
         * STATUS: REQUIRED
         */
-       int (* queuecommand)(struct scsi_cmnd *,
-                            void (*done)(struct scsi_cmnd *));
+       int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);
 
        /*
         * The transfer functions are used to queue a scsi command to
@@ -504,6 +503,25 @@ struct scsi_host_template {
        u64 vendor_id;
 };
 
+/*
+ * Temporary #define for host lock push down. Can be removed when all
+ * drivers have been updated to take advantage of unlocked
+ * queuecommand.
+ *
+ */
+#define DEF_SCSI_QCMD(func_name) \
+       int func_name(struct Scsi_Host *shost, struct scsi_cmnd *cmd)   \
+       {                                                               \
+               unsigned long irq_flags;                                \
+               int rc;                                                 \
+               spin_lock_irqsave(shost->host_lock, irq_flags);         \
+               scsi_cmd_get_serial(shost, cmd);                        \
+               rc = func_name##_lck (cmd, cmd->scsi_done);                     \
+               spin_unlock_irqrestore(shost->host_lock, irq_flags);    \
+               return rc;                                              \
+       }
+
+
 /*
  * shost state: If you alter this, you also need to alter scsi_sysfs.c
  * (for the ascii descriptions) and the state model enforcer:
@@ -752,6 +770,7 @@ extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
 extern void scsi_host_put(struct Scsi_Host *t);
 extern struct Scsi_Host *scsi_host_lookup(unsigned short);
 extern const char *scsi_host_state_name(enum scsi_host_state);
+extern void scsi_cmd_get_serial(struct Scsi_Host *, struct scsi_cmnd *);
 
 extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
 
index 289010d3270bfa99191cfbdfa95a02564b6638bf..e5e345fb2a5c37db45de06bcdf02f3796aec64c4 100644 (file)
@@ -98,6 +98,103 @@ TRACE_EVENT(ext4_allocate_inode,
                  (unsigned long) __entry->dir, __entry->mode)
 );
 
+TRACE_EVENT(ext4_evict_inode,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        int,   dev_major                )
+               __field(        int,   dev_minor                )
+               __field(        ino_t,  ino                     )
+               __field(        int,    nlink                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->nlink  = inode->i_nlink;
+       ),
+
+       TP_printk("dev %d,%d ino %lu nlink %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->nlink)
+);
+
+TRACE_EVENT(ext4_drop_inode,
+       TP_PROTO(struct inode *inode, int drop),
+
+       TP_ARGS(inode, drop),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        int,    drop                    )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->drop   = drop;
+       ),
+
+       TP_printk("dev %d,%d ino %lu drop %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->drop)
+);
+
+TRACE_EVENT(ext4_mark_inode_dirty,
+       TP_PROTO(struct inode *inode, unsigned long IP),
+
+       TP_ARGS(inode, IP),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(unsigned long,  ip                      )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->ip     = IP;
+       ),
+
+       TP_printk("dev %d,%d ino %lu caller %pF",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, (void *)__entry->ip)
+);
+
+TRACE_EVENT(ext4_begin_ordered_truncate,
+       TP_PROTO(struct inode *inode, loff_t new_size),
+
+       TP_ARGS(inode, new_size),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        loff_t, new_size                )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->ino            = inode->i_ino;
+               __entry->new_size       = new_size;
+       ),
+
+       TP_printk("dev %d,%d ino %lu new_size %lld",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino,
+                 (long long) __entry->new_size)
+);
+
 DECLARE_EVENT_CLASS(ext4__write_begin,
 
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
index d7a6c13bde69cf505bef40027bcd555a4463d57f..eac3ce1537190228ba8dc74f0398d8e6e4795572 100644 (file)
@@ -140,6 +140,19 @@ struct xen_machphys_mfn_list {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
 
+/*
+ * Returns the location in virtual address space of the machine_to_phys
+ * mapping table. Architectures which do not have a m2p table, or which do not
+ * map it by default into guest address space, do not implement this command.
+ * arg == addr of xen_machphys_mapping_t.
+ */
+#define XENMEM_machphys_mapping     12
+struct xen_machphys_mapping {
+    unsigned long v_start, v_end; /* Start and end virtual addresses.   */
+    unsigned long max_mfn;        /* Maximum MFN that can be looked up. */
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t);
+
 /*
  * Sets the GPFN at which a particular page appears in the specified guest's
  * pseudophysical address space.
index eaf85fab12632d45cc00d8976d9108a3eacc2850..0be36b976f4b02905034532919e7fc576eba19d7 100644 (file)
@@ -1 +1,8 @@
+#ifndef _XEN_PAGE_H
+#define _XEN_PAGE_H
+
 #include <asm/xen/page.h>
+
+extern phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
+
+#endif /* _XEN_PAGE_H */
index b42cdfd92fee5becfa065aeaeec36b743b9664e8..17857fb4d5509b24a475609e2806af53c79d5317 100644 (file)
 #define __LINUX_PUBLIC_PRIVCMD_H__
 
 #include <linux/types.h>
+#include <linux/compiler.h>
 
 typedef unsigned long xen_pfn_t;
 
-#ifndef __user
-#define __user
-#endif
-
 struct privcmd_hypercall {
        __u64 op;
        __u64 arg[5];
index e59af24a0b7c0dbb8417ff3b5c0818d544ac8060..8646401f7a0e4b77579aa13f8de6ac191787be73 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
index 37755d621924e5256b3494d5e94b57415be5a3f1..a6e729766821307c7440fd4d321d3decdc3182d6 100644 (file)
@@ -82,7 +82,7 @@ static kdbtab_t kdb_base_commands[50];
 #define for_each_kdbcmd(cmd, num)                                      \
        for ((cmd) = kdb_base_commands, (num) = 0;                      \
             num < kdb_max_commands;                                    \
-            num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++, num++)
+            num++, num == KDB_BASE_CMD_MAX ? cmd = kdb_commands : cmd++)
 
 typedef struct _kdbmsg {
        int     km_diag;        /* kdb diagnostic */
@@ -646,7 +646,7 @@ static int kdb_defcmd2(const char *cmdstr, const char *argv0)
        }
        if (!s->usable)
                return KDB_NOTIMP;
-       s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB);
+       s->command = kzalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB);
        if (!s->command) {
                kdb_printf("Could not allocate new kdb_defcmd table for %s\n",
                           cmdstr);
@@ -2361,7 +2361,7 @@ static int kdb_pid(int argc, const char **argv)
  */
 static int kdb_ll(int argc, const char **argv)
 {
-       int diag;
+       int diag = 0;
        unsigned long addr;
        long offset = 0;
        unsigned long va;
@@ -2400,20 +2400,21 @@ static int kdb_ll(int argc, const char **argv)
                char buf[80];
 
                if (KDB_FLAG(CMD_INTERRUPT))
-                       return 0;
+                       goto out;
 
                sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va);
                diag = kdb_parse(buf);
                if (diag)
-                       return diag;
+                       goto out;
 
                addr = va + linkoffset;
                if (kdb_getword(&va, addr, sizeof(va)))
-                       return 0;
+                       goto out;
        }
-       kfree(command);
 
-       return 0;
+out:
+       kfree(command);
+       return diag;
 }
 
 static int kdb_kgdb(int argc, const char **argv)
@@ -2739,13 +2740,13 @@ int kdb_register_repeat(char *cmd,
                }
                if (kdb_commands) {
                        memcpy(new, kdb_commands,
-                              kdb_max_commands * sizeof(*new));
+                         (kdb_max_commands - KDB_BASE_CMD_MAX) * sizeof(*new));
                        kfree(kdb_commands);
                }
                memset(new + kdb_max_commands, 0,
                       kdb_command_extend * sizeof(*new));
                kdb_commands = new;
-               kp = kdb_commands + kdb_max_commands;
+               kp = kdb_commands + kdb_max_commands - KDB_BASE_CMD_MAX;
                kdb_max_commands += kdb_command_extend;
        }
 
index b194febf5799bab766e5aef261e566902a086b28..21aa7b3001fb49edce43446dd85898f62ab33d98 100644 (file)
@@ -95,6 +95,14 @@ static void __exit_signal(struct task_struct *tsk)
                tty = sig->tty;
                sig->tty = NULL;
        } else {
+               /*
+                * This can only happen if the caller is de_thread().
+                * FIXME: this is the temporary hack, we should teach
+                * posix-cpu-timers to handle this case correctly.
+                */
+               if (unlikely(has_group_leader_pid(tsk)))
+                       posix_cpu_timers_exit_group(tsk);
+
                /*
                 * If there is any task waiting for the group exit
                 * then notify it:
index 6c683b37f2ce25291a5a0c8f490a16c08c84d674..40a8777a27d0d85e173f4b7a3efbd4ecff1c9654 100644 (file)
@@ -2489,7 +2489,8 @@ void exit_robust_list(struct task_struct *curr)
 {
        struct robust_list_head __user *head = curr->robust_list;
        struct robust_list __user *entry, *next_entry, *pending;
-       unsigned int limit = ROBUST_LIST_LIMIT, pi, next_pi, pip;
+       unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
+       unsigned int uninitialized_var(next_pi);
        unsigned long futex_offset;
        int rc;
 
index 06da4dfc339b7362716858f92bec749962241808..a7934ac75e5bf4b2b7f5b819d24e8f6f08a1ff1a 100644 (file)
@@ -49,7 +49,8 @@ void compat_exit_robust_list(struct task_struct *curr)
 {
        struct compat_robust_list_head __user *head = curr->compat_robust_list;
        struct robust_list __user *entry, *next_entry, *pending;
-       unsigned int limit = ROBUST_LIST_LIMIT, pi, next_pi, pip;
+       unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
+       unsigned int uninitialized_var(next_pi);
        compat_uptr_t uentry, next_uentry, upending;
        compat_long_t futex_offset;
        int rc;
index 877fb306d4154465e184e19b73ca1984a179aece..17110a4a4fc28c68bf7993b9248432c0dd957d4f 100644 (file)
@@ -194,14 +194,7 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter)
 
        account_global_scheduler_latency(tsk, &lat);
 
-       /*
-        * short term hack; if we're > 32 we stop; future we recycle:
-        */
-       tsk->latency_record_count++;
-       if (tsk->latency_record_count >= LT_SAVECOUNT)
-               goto out_unlock;
-
-       for (i = 0; i < LT_SAVECOUNT; i++) {
+       for (i = 0; i < tsk->latency_record_count; i++) {
                struct latency_record *mylat;
                int same = 1;
 
@@ -227,8 +220,14 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter)
                }
        }
 
+       /*
+        * short term hack; if we're > 32 we stop; future we recycle:
+        */
+       if (tsk->latency_record_count >= LT_SAVECOUNT)
+               goto out_unlock;
+
        /* Allocated a new one: */
-       i = tsk->latency_record_count;
+       i = tsk->latency_record_count++;
        memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record));
 
 out_unlock:
index 517d827f498281da50210aa76a02b4693116154a..cb6c0d2af68f64b16bd0557f3c7fb7001151b71d 100644 (file)
@@ -674,6 +674,8 @@ event_sched_in(struct perf_event *event,
 
        event->tstamp_running += ctx->time - event->tstamp_stopped;
 
+       event->shadow_ctx_time = ctx->time - ctx->timestamp;
+
        if (!is_software_event(event))
                cpuctx->active_oncpu++;
        ctx->nr_active++;
@@ -3396,7 +3398,8 @@ static u32 perf_event_tid(struct perf_event *event, struct task_struct *p)
 }
 
 static void perf_output_read_one(struct perf_output_handle *handle,
-                                struct perf_event *event)
+                                struct perf_event *event,
+                                u64 enabled, u64 running)
 {
        u64 read_format = event->attr.read_format;
        u64 values[4];
@@ -3404,11 +3407,11 @@ static void perf_output_read_one(struct perf_output_handle *handle,
 
        values[n++] = perf_event_count(event);
        if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
-               values[n++] = event->total_time_enabled +
+               values[n++] = enabled +
                        atomic64_read(&event->child_total_time_enabled);
        }
        if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
-               values[n++] = event->total_time_running +
+               values[n++] = running +
                        atomic64_read(&event->child_total_time_running);
        }
        if (read_format & PERF_FORMAT_ID)
@@ -3421,7 +3424,8 @@ static void perf_output_read_one(struct perf_output_handle *handle,
  * XXX PERF_FORMAT_GROUP vs inherited events seems difficult.
  */
 static void perf_output_read_group(struct perf_output_handle *handle,
-                           struct perf_event *event)
+                           struct perf_event *event,
+                           u64 enabled, u64 running)
 {
        struct perf_event *leader = event->group_leader, *sub;
        u64 read_format = event->attr.read_format;
@@ -3431,10 +3435,10 @@ static void perf_output_read_group(struct perf_output_handle *handle,
        values[n++] = 1 + leader->nr_siblings;
 
        if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
-               values[n++] = leader->total_time_enabled;
+               values[n++] = enabled;
 
        if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
-               values[n++] = leader->total_time_running;
+               values[n++] = running;
 
        if (leader != event)
                leader->pmu->read(leader);
@@ -3459,13 +3463,35 @@ static void perf_output_read_group(struct perf_output_handle *handle,
        }
 }
 
+#define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\
+                                PERF_FORMAT_TOTAL_TIME_RUNNING)
+
 static void perf_output_read(struct perf_output_handle *handle,
                             struct perf_event *event)
 {
+       u64 enabled = 0, running = 0, now, ctx_time;
+       u64 read_format = event->attr.read_format;
+
+       /*
+        * compute total_time_enabled, total_time_running
+        * based on snapshot values taken when the event
+        * was last scheduled in.
+        *
+        * we cannot simply called update_context_time()
+        * because of locking issue as we are called in
+        * NMI context
+        */
+       if (read_format & PERF_FORMAT_TOTAL_TIMES) {
+               now = perf_clock();
+               ctx_time = event->shadow_ctx_time + now;
+               enabled = ctx_time - event->tstamp_enabled;
+               running = ctx_time - event->tstamp_running;
+       }
+
        if (event->attr.read_format & PERF_FORMAT_GROUP)
-               perf_output_read_group(handle, event);
+               perf_output_read_group(handle, event, enabled, running);
        else
-               perf_output_read_one(handle, event);
+               perf_output_read_one(handle, event, enabled, running);
 }
 
 void perf_output_sample(struct perf_output_handle *handle,
index c7a8f453919e65a42e0251b968a2d3652e0a4c3a..aeaa7f8468216eb1d8795b14ff74cfc502318771 100644 (file)
@@ -121,10 +121,10 @@ static inline int pm_qos_get_value(struct pm_qos_object *o)
 
        switch (o->type) {
        case PM_QOS_MIN:
-               return plist_last(&o->requests)->prio;
+               return plist_first(&o->requests)->prio;
 
        case PM_QOS_MAX:
-               return plist_first(&o->requests)->prio;
+               return plist_last(&o->requests)->prio;
 
        default:
                /* runtime check for not using enum */
index 29bff6117abca747d31131424f58927e1a30558d..a5aff3ebad38b68629d341cb5a28856afb970796 100644 (file)
@@ -246,9 +246,13 @@ config PM_OPS
        depends on PM_SLEEP || PM_RUNTIME
        default y
 
+config ARCH_HAS_OPP
+       bool
+
 config PM_OPP
        bool "Operating Performance Point (OPP) Layer library"
        depends on PM
+       depends on ARCH_HAS_OPP
        ---help---
          SOCs have a standard set of tuples consisting of frequency and
          voltage pairs that the device will support per voltage domain. This
index b2ebaee8c377d2aa92c073e772748242b5ce5c90..9a2264fc42cafac30d9264d569e4e673e9617f19 100644 (file)
@@ -261,6 +261,12 @@ static inline void boot_delay_msec(void)
 }
 #endif
 
+#ifdef CONFIG_SECURITY_DMESG_RESTRICT
+int dmesg_restrict = 1;
+#else
+int dmesg_restrict;
+#endif
+
 int do_syslog(int type, char __user *buf, int len, bool from_file)
 {
        unsigned i, j, limit, count;
@@ -268,7 +274,20 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
        char c;
        int error = 0;
 
-       error = security_syslog(type, from_file);
+       /*
+        * If this is from /proc/kmsg we only do the capabilities checks
+        * at open time.
+        */
+       if (type == SYSLOG_ACTION_OPEN || !from_file) {
+               if (dmesg_restrict && !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if ((type != SYSLOG_ACTION_READ_ALL &&
+                    type != SYSLOG_ACTION_SIZE_BUFFER) &&
+                   !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+       }
+
+       error = security_syslog(type);
        if (error)
                return error;
 
index 471b66acabb57e770dd552bfc5a9edae356acfd7..37fa9b99ad588356534b1457b7241d97573705b8 100644 (file)
@@ -119,7 +119,7 @@ static int cmp_range(const void *x1, const void *x2)
 
 int clean_sort_range(struct range *range, int az)
 {
-       int i, j, k = az - 1, nr_range = 0;
+       int i, j, k = az - 1, nr_range = az;
 
        for (i = 0; i < k; i++) {
                if (range[i].end)
index c7cf397fb92958bbcbd2772e13a8d4a4d9c00b6d..859ea5a9605fa40fe47aedcb865ab08c66a43797 100644 (file)
@@ -70,17 +70,10 @@ static const struct vm_operations_struct relay_file_mmap_ops = {
  */
 static struct page **relay_alloc_page_array(unsigned int n_pages)
 {
-       struct page **array;
-       size_t pa_size = n_pages * sizeof(struct page *);
-
-       if (pa_size > PAGE_SIZE) {
-               array = vmalloc(pa_size);
-               if (array)
-                       memset(array, 0, pa_size);
-       } else {
-               array = kzalloc(pa_size, GFP_KERNEL);
-       }
-       return array;
+       const size_t pa_size = n_pages * sizeof(struct page *);
+       if (pa_size > PAGE_SIZE)
+               return vzalloc(pa_size);
+       return kzalloc(pa_size, GFP_KERNEL);
 }
 
 /*
index aa14a56f9d037cde21ae19ef86b142e1c23fe736..dc91a4d09ac3b71a3c347187ff2a1691c952cebd 100644 (file)
@@ -560,18 +560,8 @@ struct rq {
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
 
-static inline
-void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
-{
-       rq->curr->sched_class->check_preempt_curr(rq, p, flags);
 
-       /*
-        * A queue event has occurred, and we're going to schedule.  In
-        * this case, we can save a useless back to back clock update.
-        */
-       if (test_tsk_need_resched(p))
-               rq->skip_clock_update = 1;
-}
+static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags);
 
 static inline int cpu_of(struct rq *rq)
 {
@@ -2118,6 +2108,31 @@ static inline void check_class_changed(struct rq *rq, struct task_struct *p,
                p->sched_class->prio_changed(rq, p, oldprio, running);
 }
 
+static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
+{
+       const struct sched_class *class;
+
+       if (p->sched_class == rq->curr->sched_class) {
+               rq->curr->sched_class->check_preempt_curr(rq, p, flags);
+       } else {
+               for_each_class(class) {
+                       if (class == rq->curr->sched_class)
+                               break;
+                       if (class == p->sched_class) {
+                               resched_task(rq->curr);
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * A queue event has occurred, and we're going to schedule.  In
+        * this case, we can save a useless back to back clock update.
+        */
+       if (test_tsk_need_resched(rq->curr))
+               rq->skip_clock_update = 1;
+}
+
 #ifdef CONFIG_SMP
 /*
  * Is this task likely cache-hot:
@@ -6960,6 +6975,8 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
        if (cpu != group_first_cpu(sd->groups))
                return;
 
+       sd->groups->group_weight = cpumask_weight(sched_group_cpus(sd->groups));
+
        child = sd->child;
 
        sd->groups->cpu_power = 0;
index f4f6a8326dd01ffc0353b369bbfddf5a4f0e2fde..52ab113d8bb95ee8e08299b9bad6b0df5691ea89 100644 (file)
@@ -1654,12 +1654,6 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
        struct cfs_rq *cfs_rq = task_cfs_rq(curr);
        int scale = cfs_rq->nr_running >= sched_nr_latency;
 
-       if (unlikely(rt_prio(p->prio)))
-               goto preempt;
-
-       if (unlikely(p->sched_class != &fair_sched_class))
-               return;
-
        if (unlikely(se == pse))
                return;
 
@@ -2035,13 +2029,16 @@ struct sd_lb_stats {
        unsigned long this_load_per_task;
        unsigned long this_nr_running;
        unsigned long this_has_capacity;
+       unsigned int  this_idle_cpus;
 
        /* Statistics of the busiest group */
+       unsigned int  busiest_idle_cpus;
        unsigned long max_load;
        unsigned long busiest_load_per_task;
        unsigned long busiest_nr_running;
        unsigned long busiest_group_capacity;
        unsigned long busiest_has_capacity;
+       unsigned int  busiest_group_weight;
 
        int group_imb; /* Is there imbalance in this sd */
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
@@ -2063,6 +2060,8 @@ struct sg_lb_stats {
        unsigned long sum_nr_running; /* Nr tasks running in the group */
        unsigned long sum_weighted_load; /* Weighted load of group's tasks */
        unsigned long group_capacity;
+       unsigned long idle_cpus;
+       unsigned long group_weight;
        int group_imb; /* Is there an imbalance in the group ? */
        int group_has_capacity; /* Is there extra capacity in the group? */
 };
@@ -2431,7 +2430,8 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
                sgs->group_load += load;
                sgs->sum_nr_running += rq->nr_running;
                sgs->sum_weighted_load += weighted_cpuload(i);
-
+               if (idle_cpu(i))
+                       sgs->idle_cpus++;
        }
 
        /*
@@ -2469,6 +2469,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
        sgs->group_capacity = DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE);
        if (!sgs->group_capacity)
                sgs->group_capacity = fix_small_capacity(sd, group);
+       sgs->group_weight = group->group_weight;
 
        if (sgs->group_capacity > sgs->sum_nr_running)
                sgs->group_has_capacity = 1;
@@ -2576,13 +2577,16 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
                        sds->this_nr_running = sgs.sum_nr_running;
                        sds->this_load_per_task = sgs.sum_weighted_load;
                        sds->this_has_capacity = sgs.group_has_capacity;
+                       sds->this_idle_cpus = sgs.idle_cpus;
                } else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {
                        sds->max_load = sgs.avg_load;
                        sds->busiest = sg;
                        sds->busiest_nr_running = sgs.sum_nr_running;
+                       sds->busiest_idle_cpus = sgs.idle_cpus;
                        sds->busiest_group_capacity = sgs.group_capacity;
                        sds->busiest_load_per_task = sgs.sum_weighted_load;
                        sds->busiest_has_capacity = sgs.group_has_capacity;
+                       sds->busiest_group_weight = sgs.group_weight;
                        sds->group_imb = sgs.group_imb;
                }
 
@@ -2860,8 +2864,26 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        if (sds.this_load >= sds.avg_load)
                goto out_balanced;
 
-       if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
-               goto out_balanced;
+       /*
+        * In the CPU_NEWLY_IDLE, use imbalance_pct to be conservative.
+        * And to check for busy balance use !idle_cpu instead of
+        * CPU_NOT_IDLE. This is because HT siblings will use CPU_NOT_IDLE
+        * even when they are idle.
+        */
+       if (idle == CPU_NEWLY_IDLE || !idle_cpu(this_cpu)) {
+               if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
+                       goto out_balanced;
+       } else {
+               /*
+                * This cpu is idle. If the busiest group load doesn't
+                * have more tasks than the number of available cpu's and
+                * there is no imbalance between this and busiest group
+                * wrt to idle cpu's, it is balanced.
+                */
+               if ((sds.this_idle_cpus  <= sds.busiest_idle_cpus + 1) &&
+                   sds.busiest_nr_running <= sds.busiest_group_weight)
+                       goto out_balanced;
+       }
 
 force_balance:
        /* Looks like there is an imbalance. Compute it */
index 45bddc0c104857f23e06c9126ed6dcb1d452450b..2bf6b47058c19f79a326a6b4f82d4baf7950cb1a 100644 (file)
@@ -19,14 +19,14 @@ select_task_rq_stop(struct rq *rq, struct task_struct *p,
 static void
 check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
 {
-       resched_task(rq->curr); /* we preempt everything */
+       /* we're never preempted */
 }
 
 static struct task_struct *pick_next_task_stop(struct rq *rq)
 {
        struct task_struct *stop = rq->stop;
 
-       if (stop && stop->state == TASK_RUNNING)
+       if (stop && stop->se.on_rq)
                return stop;
 
        return NULL;
index c33a1edb799fda6db2e16fdf9d1d0401a9f78278..5abfa151855493735a91fd45a255a45727c8ba97 100644 (file)
@@ -702,6 +702,15 @@ static struct ctl_table kern_table[] = {
                .extra1         = &zero,
                .extra2         = &ten_thousand,
        },
+       {
+               .procname       = "dmesg_restrict",
+               .data           = &dmesg_restrict,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
 #endif
        {
                .procname       = "ngroups_max",
index e04b8bcdef88dc92a3c52c9c53808528b0266b09..ea37e2ff416429d04cea3829e835ced7f0f35fc0 100644 (file)
@@ -126,7 +126,7 @@ if FTRACE
 config FUNCTION_TRACER
        bool "Kernel Function Tracer"
        depends on HAVE_FUNCTION_TRACER
-       select FRAME_POINTER if (!ARM_UNWIND)
+       select FRAME_POINTER if !ARM_UNWIND && !S390
        select KALLSYMS
        select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
index bc251ed667248fb8c72a0dd59ddf3a9a42e1c23d..7b8ec02815482773bc0eccb3918e207934f46419 100644 (file)
@@ -168,7 +168,6 @@ static int act_log_check(struct blk_trace *bt, u32 what, sector_t sector,
 static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ),
                                 BLK_TC_ACT(BLK_TC_WRITE) };
 
-#define BLK_TC_HARDBARRIER     BLK_TC_BARRIER
 #define BLK_TC_RAHEAD          BLK_TC_AHEAD
 
 /* The ilog2() calls fall out because they're constant */
@@ -196,7 +195,6 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
                return;
 
        what |= ddir_act[rw & WRITE];
-       what |= MASK_TC_BIT(rw, HARDBARRIER);
        what |= MASK_TC_BIT(rw, SYNC);
        what |= MASK_TC_BIT(rw, RAHEAD);
        what |= MASK_TC_BIT(rw, META);
@@ -1807,8 +1805,6 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
 
        if (rw & REQ_RAHEAD)
                rwbs[i++] = 'A';
-       if (rw & REQ_HARDBARRIER)
-               rwbs[i++] = 'B';
        if (rw & REQ_SYNC)
                rwbs[i++] = 'S';
        if (rw & REQ_META)
index 82d9b8106cd078970ea0c7343e12ad2b6a6eed36..0420841579806ce14b3fc86b9fe13df649dac711 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/writeback.h>
 #include <linux/kallsyms.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/irqflags.h>
 #include <linux/debugfs.h>
index bafba687a6d849a11f0201acd3d7ae5e63e9301e..6e3c41a4024c1cc66be01218e2c37498498f2469 100644 (file)
@@ -43,7 +43,7 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int __initdata no_watchdog;
+static int no_watchdog;
 
 
 /* boot commands */
index 6f412ab4c24f812fc8b7290c4a1e06cc0250ea62..5086bb962b4dd9ca6471afb76f0698facb914816 100644 (file)
@@ -82,6 +82,16 @@ struct radix_tree_preload {
 };
 static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
 
+static inline void *ptr_to_indirect(void *ptr)
+{
+       return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR);
+}
+
+static inline void *indirect_to_ptr(void *ptr)
+{
+       return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR);
+}
+
 static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
 {
        return root->gfp_mask & __GFP_BITS_MASK;
@@ -265,7 +275,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                        return -ENOMEM;
 
                /* Increase the height.  */
-               node->slots[0] = radix_tree_indirect_to_ptr(root->rnode);
+               node->slots[0] = indirect_to_ptr(root->rnode);
 
                /* Propagate the aggregated tag info into the new root */
                for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
@@ -276,7 +286,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                newheight = root->height+1;
                node->height = newheight;
                node->count = 1;
-               node = radix_tree_ptr_to_indirect(node);
+               node = ptr_to_indirect(node);
                rcu_assign_pointer(root->rnode, node);
                root->height = newheight;
        } while (height > root->height);
@@ -309,7 +319,7 @@ int radix_tree_insert(struct radix_tree_root *root,
                        return error;
        }
 
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
 
        height = root->height;
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
@@ -325,8 +335,7 @@ int radix_tree_insert(struct radix_tree_root *root,
                                rcu_assign_pointer(node->slots[offset], slot);
                                node->count++;
                        } else
-                               rcu_assign_pointer(root->rnode,
-                                       radix_tree_ptr_to_indirect(slot));
+                               rcu_assign_pointer(root->rnode, ptr_to_indirect(slot));
                }
 
                /* Go a level down */
@@ -374,7 +383,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
                        return NULL;
                return is_slot ? (void *)&root->rnode : node;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        height = node->height;
        if (index > radix_tree_maxindex(height))
@@ -393,7 +402,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
                height--;
        } while (height > 0);
 
-       return is_slot ? (void *)slot:node;
+       return is_slot ? (void *)slot : indirect_to_ptr(node);
 }
 
 /**
@@ -455,7 +464,7 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
        height = root->height;
        BUG_ON(index > radix_tree_maxindex(height));
 
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
 
        while (height > 0) {
@@ -509,7 +518,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        pathp->node = NULL;
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
 
        while (height > 0) {
                int offset;
@@ -579,7 +588,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
 
        if (!radix_tree_is_indirect_ptr(node))
                return (index == 0);
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        height = node->height;
        if (index > radix_tree_maxindex(height))
@@ -666,7 +675,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
        }
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
 
        /*
         * we fill the path from (root->height - 2) to 0, leaving the index at
@@ -897,7 +906,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
                results[0] = node;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -916,7 +925,8 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
                        slot = *(((void ***)results)[ret + i]);
                        if (!slot)
                                continue;
-                       results[ret + nr_found] = rcu_dereference_raw(slot);
+                       results[ret + nr_found] =
+                               indirect_to_ptr(rcu_dereference_raw(slot));
                        nr_found++;
                }
                ret += nr_found;
@@ -965,7 +975,7 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
                results[0] = (void **)&root->rnode;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -1090,7 +1100,7 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
                results[0] = node;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -1109,7 +1119,8 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
                        slot = *(((void ***)results)[ret + i]);
                        if (!slot)
                                continue;
-                       results[ret + nr_found] = rcu_dereference_raw(slot);
+                       results[ret + nr_found] =
+                               indirect_to_ptr(rcu_dereference_raw(slot));
                        nr_found++;
                }
                ret += nr_found;
@@ -1159,7 +1170,7 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
                results[0] = (void **)&root->rnode;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -1195,7 +1206,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
                void *newptr;
 
                BUG_ON(!radix_tree_is_indirect_ptr(to_free));
-               to_free = radix_tree_indirect_to_ptr(to_free);
+               to_free = indirect_to_ptr(to_free);
 
                /*
                 * The candidate node has more than one child, or its child
@@ -1208,16 +1219,39 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
 
                /*
                 * We don't need rcu_assign_pointer(), since we are simply
-                * moving the node from one part of the tree to another. If
-                * it was safe to dereference the old pointer to it
+                * moving the node from one part of the tree to another: if it
+                * was safe to dereference the old pointer to it
                 * (to_free->slots[0]), it will be safe to dereference the new
-                * one (root->rnode).
+                * one (root->rnode) as far as dependent read barriers go.
                 */
                newptr = to_free->slots[0];
                if (root->height > 1)
-                       newptr = radix_tree_ptr_to_indirect(newptr);
+                       newptr = ptr_to_indirect(newptr);
                root->rnode = newptr;
                root->height--;
+
+               /*
+                * We have a dilemma here. The node's slot[0] must not be
+                * NULLed in case there are concurrent lookups expecting to
+                * find the item. However if this was a bottom-level node,
+                * then it may be subject to the slot pointer being visible
+                * to callers dereferencing it. If item corresponding to
+                * slot[0] is subsequently deleted, these callers would expect
+                * their slot to become empty sooner or later.
+                *
+                * For example, lockless pagecache will look up a slot, deref
+                * the page pointer, and if the page is 0 refcount it means it
+                * was concurrently deleted from pagecache so try the deref
+                * again. Fortunately there is already a requirement for logic
+                * to retry the entire slot lookup -- the indirect pointer
+                * problem (replacing direct root node with an indirect pointer
+                * also results in a stale slot). So tag the slot as indirect
+                * to force callers to retry.
+                */
+               if (root->height == 0)
+                       *((unsigned long *)&to_free->slots[0]) |=
+                                               RADIX_TREE_INDIRECT_PTR;
+
                radix_tree_node_free(to_free);
        }
 }
@@ -1254,7 +1288,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                root->rnode = NULL;
                goto out;
        }
-       slot = radix_tree_indirect_to_ptr(slot);
+       slot = indirect_to_ptr(slot);
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        pathp->node = NULL;
@@ -1296,8 +1330,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                        radix_tree_node_free(to_free);
 
                if (pathp->node->count) {
-                       if (pathp->node ==
-                                       radix_tree_indirect_to_ptr(root->rnode))
+                       if (pathp->node == indirect_to_ptr(root->rnode))
                                radix_tree_shrink(root);
                        goto out;
                }
index 75572b5f23746a4b47a42920980a22e6a5251fe7..ea89840fc65fa2b499ce3c19c657e9e8a680b240 100644 (file)
@@ -644,7 +644,9 @@ repeat:
        pagep = radix_tree_lookup_slot(&mapping->page_tree, offset);
        if (pagep) {
                page = radix_tree_deref_slot(pagep);
-               if (unlikely(!page || page == RADIX_TREE_RETRY))
+               if (unlikely(!page))
+                       goto out;
+               if (radix_tree_deref_retry(page))
                        goto repeat;
 
                if (!page_cache_get_speculative(page))
@@ -660,6 +662,7 @@ repeat:
                        goto repeat;
                }
        }
+out:
        rcu_read_unlock();
 
        return page;
@@ -777,12 +780,11 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
-               /*
-                * this can only trigger if nr_found == 1, making livelock
-                * a non issue.
-                */
-               if (unlikely(page == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(page)) {
+                       if (ret)
+                               start = pages[ret-1]->index;
                        goto restart;
+               }
 
                if (!page_cache_get_speculative(page))
                        goto repeat;
@@ -830,11 +832,7 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
-               /*
-                * this can only trigger if nr_found == 1, making livelock
-                * a non issue.
-                */
-               if (unlikely(page == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(page))
                        goto restart;
 
                if (page->mapping == NULL || page->index != index)
@@ -887,11 +885,7 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
-               /*
-                * this can only trigger if nr_found == 1, making livelock
-                * a non issue.
-                */
-               if (unlikely(page == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(page))
                        goto restart;
 
                if (!page_cache_get_speculative(page))
@@ -1029,6 +1023,9 @@ find_page:
                                goto page_not_up_to_date;
                        if (!trylock_page(page))
                                goto page_not_up_to_date;
+                       /* Did it get truncated before we got the lock? */
+                       if (!page->mapping)
+                               goto page_not_up_to_date_locked;
                        if (!mapping->a_ops->is_partially_uptodate(page,
                                                                desc, offset))
                                goto page_not_up_to_date_locked;
@@ -1563,8 +1560,10 @@ retry_find:
                        goto no_cached_page;
        }
 
-       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags))
+       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) {
+               page_cache_release(page);
                return ret | VM_FAULT_RETRY;
+       }
 
        /* Did it get truncated? */
        if (unlikely(page->mapping != mapping)) {
index 9a99cfaf0a19025f6020c106d56e1ce28d6499b4..2efa8ea07ff7d931577da964c190f5524088da3d 100644 (file)
@@ -4208,15 +4208,17 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
 
        memset(mem, 0, size);
        mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
-       if (!mem->stat) {
-               if (size < PAGE_SIZE)
-                       kfree(mem);
-               else
-                       vfree(mem);
-               mem = NULL;
-       }
+       if (!mem->stat)
+               goto out_free;
        spin_lock_init(&mem->pcp_counter_lock);
        return mem;
+
+out_free:
+       if (size < PAGE_SIZE)
+               kfree(mem);
+       else
+               vfree(mem);
+       return NULL;
 }
 
 /*
index 2d1bf7cf885179af5144f41998d95dc2d2b72981..4c51338730977604266bab4e67ef0251aba69638 100644 (file)
@@ -211,6 +211,7 @@ success:
        mmu_notifier_invalidate_range_end(mm, start, end);
        vm_stat_account(mm, oldflags, vma->vm_file, -nrpages);
        vm_stat_account(mm, newflags, vma->vm_file, nrpages);
+       perf_event_mmap(vma);
        return 0;
 
 fail:
@@ -299,7 +300,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
                error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);
                if (error)
                        goto out;
-               perf_event_mmap(vma);
                nstart = tmp;
 
                if (nstart < prev->vm_end)
index 8fd5401bb0717f3cfc73141bdad1c901e92764a7..981fb730aa04d82ef7b739497beb22d10fe9f98c 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3273,9 +3273,9 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                kfree(n);
                kfree(s);
        }
+err:
        up_write(&slub_lock);
 
-err:
        if (flags & SLAB_PANIC)
                panic("Cannot create slabcache %s\n", name);
        else
@@ -3862,6 +3862,7 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                        x += sprintf(buf + x, " N%d=%lu",
                                        node, nodes[node]);
 #endif
+       up_read(&slub_lock);
        kfree(nodes);
        return x + sprintf(buf + x, "\n");
 }
index b8a6fdc2131258db15321021375117cae27cec0d..d31d7ce52c0ea2dbbf85b26019c9fdd70fab624a 100644 (file)
@@ -913,7 +913,7 @@ keep_lumpy:
         * back off and wait for congestion to clear because further reclaim
         * will encounter the same problem
         */
-       if (nr_dirty == nr_congested)
+       if (nr_dirty == nr_congested && nr_dirty != 0)
                zone_set_flag(zone, ZONE_CONGESTED);
 
        free_page_list(&free_pages);
index cd2e42be7b68f73dc60f40631f2b9f87708d3b47..42eac4d33216b81c307a87016e821051bc86146e 100644 (file)
@@ -949,7 +949,7 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
        v[PGPGIN] /= 2;         /* sectors -> kbytes */
        v[PGPGOUT] /= 2;
 #endif
-       return m->private + *pos;
+       return (unsigned long *)m->private + *pos;
 }
 
 static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
index 26eaebf4aaa9b11c3b9d8820b835ae07c50219e2..bb86d2932394aa9b1176ccfbba7a13102c0a3d20 100644 (file)
@@ -1392,6 +1392,7 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
        ax25_cb *ax25;
        int err = 0;
 
+       memset(fsa, 0, sizeof(fsa));
        lock_sock(sk);
        ax25 = ax25_sk(sk);
 
@@ -1403,7 +1404,6 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
 
                fsa->fsa_ax25.sax25_family = AF_AX25;
                fsa->fsa_ax25.sax25_call   = ax25->dest_addr;
-               fsa->fsa_ax25.sax25_ndigis = 0;
 
                if (ax25->digipeat != NULL) {
                        ndigi = ax25->digipeat->ndigi;
index bfef5bae0b3a83487c8894e171cf7fe6f447e651..84093b0000b9e0eb0107d22dd0503e699d36eff8 100644 (file)
@@ -1175,6 +1175,12 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
                                hci_send_cmd(hdev,
                                        HCI_OP_READ_REMOTE_EXT_FEATURES,
                                                        sizeof(cp), &cp);
+                       } else if (!ev->status && conn->out &&
+                                       conn->sec_level == BT_SECURITY_HIGH) {
+                               struct hci_cp_auth_requested cp;
+                               cp.handle = ev->handle;
+                               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
+                                                       sizeof(cp), &cp);
                        } else {
                                conn->state = BT_CONNECTED;
                                hci_proto_connect_cfm(conn, ev->status);
index 98fdfa1fbddda7054b84e67d3e10bda033e80a4b..86a91543172a7e1ddcd88538d13c4750599bfdbb 100644 (file)
@@ -1,6 +1,6 @@
 config BT_HIDP
        tristate "HIDP protocol support"
-       depends on BT && BT_L2CAP && INPUT
+       depends on BT && BT_L2CAP && INPUT && HID_SUPPORT
        select HID
        help
          HIDP (Human Interface Device Protocol) is a transport layer
index daa7a988d9a6b4de7c7767748f1f18e1524cb78f..cd8f6ea038414ce21794f05f219f37716eea43e0 100644 (file)
@@ -2421,11 +2421,11 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned
                break;
 
        case 2:
-               *val = __le16_to_cpu(*((__le16 *) opt->val));
+               *val = get_unaligned_le16(opt->val);
                break;
 
        case 4:
-               *val = __le32_to_cpu(*((__le32 *) opt->val));
+               *val = get_unaligned_le32(opt->val);
                break;
 
        default:
@@ -2452,11 +2452,11 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
                break;
 
        case 2:
-               *((__le16 *) opt->val) = cpu_to_le16(val);
+               put_unaligned_le16(val, opt->val);
                break;
 
        case 4:
-               *((__le32 *) opt->val) = cpu_to_le32(val);
+               put_unaligned_le32(val, opt->val);
                break;
 
        default:
index 39a5d87e33b4221b7657933da0a1e2e1b5fe1784..fa642aa652bdba0d4b0b3f47c77dc9e55571c19f 100644 (file)
@@ -79,7 +79,10 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
 
 static void rfcomm_process_connect(struct rfcomm_session *s);
 
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
+static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
+                                                       bdaddr_t *dst,
+                                                       u8 sec_level,
+                                                       int *err);
 static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
 static void rfcomm_session_del(struct rfcomm_session *s);
 
@@ -401,7 +404,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
 
        s = rfcomm_session_get(src, dst);
        if (!s) {
-               s = rfcomm_session_create(src, dst, &err);
+               s = rfcomm_session_create(src, dst, d->sec_level, &err);
                if (!s)
                        return err;
        }
@@ -679,7 +682,10 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
        rfcomm_session_put(s);
 }
 
-static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
+static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
+                                                       bdaddr_t *dst,
+                                                       u8 sec_level,
+                                                       int *err)
 {
        struct rfcomm_session *s = NULL;
        struct sockaddr_l2 addr;
@@ -704,6 +710,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
        sk = sock->sk;
        lock_sock(sk);
        l2cap_pi(sk)->imtu = l2cap_mtu;
+       l2cap_pi(sk)->sec_level = sec_level;
        if (l2cap_ertm)
                l2cap_pi(sk)->mode = L2CAP_MODE_ERTM;
        release_sock(sk);
index 76ae68303d3a3675265e61eccc213a0c4526d4e1..d522d8c1703e761eb27b4e2375eff9851b06690e 100644 (file)
@@ -16,11 +16,18 @@ int connect_req_to_link_param(struct cfcnfg *cnfg,
 {
        struct dev_info *dev_info;
        enum cfcnfg_phy_preference pref;
+       int res;
+
        memset(l, 0, sizeof(*l));
-       l->priority = s->priority;
+       /* In caif protocol low value is high priority */
+       l->priority = CAIF_PRIO_MAX - s->priority + 1;
 
-       if (s->link_name[0] != '\0')
-               l->phyid = cfcnfg_get_named(cnfg, s->link_name);
+       if (s->ifindex != 0){
+               res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
+               if (res < 0)
+                       return res;
+               l->phyid = res;
+       }
        else {
                switch (s->link_selector) {
                case CAIF_LINK_HIGH_BANDW:
index b99369a055d13df6414421a28cfaee5d000c6c72..a42a408306e4a1c038aa6ad0d8fb3d0e2f923aa9 100644 (file)
@@ -307,6 +307,8 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
 
        case NETDEV_UNREGISTER:
                caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
                netdev_info(dev, "unregister\n");
                atomic_set(&caifd->state, what);
                caif_device_destroy(dev);
index 2eca2dd0000fd7dce7fc614ed5e476f0ca886874..1bf0cf503796f27668d8dc8c1e9a733fd6e76bdd 100644 (file)
@@ -716,8 +716,7 @@ static int setsockopt(struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
-       int prio, linksel;
-       struct ifreq ifreq;
+       int linksel;
 
        if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED)
                return -ENOPROTOOPT;
@@ -735,33 +734,6 @@ static int setsockopt(struct socket *sock,
                release_sock(&cf_sk->sk);
                return 0;
 
-       case SO_PRIORITY:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(int))
-                       return -EINVAL;
-               if (copy_from_user(&prio, ov, sizeof(int)))
-                       return -EINVAL;
-               lock_sock(&(cf_sk->sk));
-               cf_sk->conn_req.priority = prio;
-               release_sock(&cf_sk->sk);
-               return 0;
-
-       case SO_BINDTODEVICE:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(struct ifreq))
-                       return -EINVAL;
-               if (copy_from_user(&ifreq, ov, sizeof(ifreq)))
-                       return -EFAULT;
-               lock_sock(&(cf_sk->sk));
-               strncpy(cf_sk->conn_req.link_name, ifreq.ifr_name,
-                       sizeof(cf_sk->conn_req.link_name));
-               cf_sk->conn_req.link_name
-                       [sizeof(cf_sk->conn_req.link_name)-1] = 0;
-               release_sock(&cf_sk->sk);
-               return 0;
-
        case CAIFSO_REQ_PARAM:
                if (lvl != SOL_CAIF)
                        goto bad_sol;
@@ -880,6 +852,18 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        sock->state = SS_CONNECTING;
        sk->sk_state = CAIF_CONNECTING;
 
+       /* Check priority value comming from socket */
+       /* if priority value is out of range it will be ajusted */
+       if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX)
+               cf_sk->conn_req.priority = CAIF_PRIO_MAX;
+       else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN)
+               cf_sk->conn_req.priority = CAIF_PRIO_MIN;
+       else
+               cf_sk->conn_req.priority = cf_sk->sk.sk_priority;
+
+       /*ifindex = id of the interface.*/
+       cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if;
+
        dbfs_atomic_inc(&cnt.num_connect_req);
        cf_sk->layer.receive = caif_sktrecv_cb;
        err = caif_connect_client(&cf_sk->conn_req,
@@ -905,6 +889,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        cf_sk->maxframe = mtu - (headroom + tailroom);
        if (cf_sk->maxframe < 1) {
                pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
+               err = -ENODEV;
                goto out;
        }
 
@@ -1142,7 +1127,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
        set_rx_flow_on(cf_sk);
 
        /* Set default options on configuration */
-       cf_sk->conn_req.priority = CAIF_PRIO_NORMAL;
+       cf_sk->sk.sk_priority= CAIF_PRIO_NORMAL;
        cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
        cf_sk->conn_req.protocol = protocol;
        /* Increase the number of sockets created. */
index 41adafd1891422ab1aa32a95a46aee7d9ae77b82..21ede141018abf698a58bcf946e0058d6d06c499 100644 (file)
@@ -173,18 +173,15 @@ static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
        return NULL;
 }
 
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
+
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
 {
        int i;
-
-       /* Try to match with specified name */
-       for (i = 0; i < MAX_PHY_LAYERS; i++) {
-               if (cnfg->phy_layers[i].frm_layer != NULL
-                   && strcmp(cnfg->phy_layers[i].phy_layer->name,
-                             name) == 0)
-                       return cnfg->phy_layers[i].frm_layer->id;
-       }
-       return 0;
+       for (i = 0; i < MAX_PHY_LAYERS; i++)
+               if (cnfg->phy_layers[i].frm_layer != NULL &&
+                               cnfg->phy_layers[i].ifindex == ifi)
+                       return i;
+       return -ENODEV;
 }
 
 int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
index 08f267a109aa3c677efc4a6795ccfea31fc8d581..3cd8f978e3098288d9d1e114347e1ba2c0e4936c 100644 (file)
@@ -361,11 +361,10 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
        struct cfctrl_request_info *p, *tmp;
        struct cfctrl *ctrl = container_obj(layr);
        spin_lock(&ctrl->info_list_lock);
-       pr_warn("enter\n");
 
        list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
                if (p->client_layer == adap_layer) {
-                       pr_warn("cancel req :%d\n", p->sequence_no);
+                       pr_debug("cancel req :%d\n", p->sequence_no);
                        list_del(&p->list);
                        kfree(p);
                }
index 496fda9ac66f56bee42568e8c0386566c3208be4..11a2af4c162ab6a8324ebaf6b8063ced01b1aea6 100644 (file)
@@ -12,6 +12,8 @@
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
 
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
 static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt);
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt);
 
@@ -38,5 +40,17 @@ static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt)
 
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
 {
+       struct cfsrvl *service = container_obj(layr);
+       struct caif_payload_info *info;
+       int ret;
+
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       /* Add info for MUX-layer to route the packet out */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       info->dev_info = &service->dev_info;
+
        return layr->dn->transmit(layr->dn, pkt);
 }
index bde8481e8d2574dd939f84595f8e4354370aa5a7..e2fb5fa757951a46e8d6be9326ffc1659f943232 100644 (file)
@@ -193,7 +193,7 @@ out:
 
 static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
 {
-       caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size);
+       caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size);
 
        /* Add info for MUX-layer to route the packet out. */
        cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
index 08ffe9e4be20aa49ab2bba82c36c5e988a4880fd..6faa8256e10ca22d6fb0b2005d74c5c5580a404d 100644 (file)
@@ -125,7 +125,7 @@ struct bcm_sock {
        struct list_head tx_ops;
        unsigned long dropped_usr_msgs;
        struct proc_dir_entry *bcm_proc_read;
-       char procname [9]; /* pointer printed in ASCII with \0 */
+       char procname [20]; /* pointer printed in ASCII with \0 */
 };
 
 static inline struct bcm_sock *bcm_sk(const struct sock *sk)
index 53d8abfa25d5ede4b487c88a5341b376c4921c26..bf3e6a13c215cd61cd7372e85ba19e7fc7974e9a 100644 (file)
@@ -19,7 +19,7 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
        if (b->vec.iov_base) {
                b->is_vmalloc = false;
        } else {
-               b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
+               b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL);
                if (!b->vec.iov_base) {
                        kfree(b);
                        return NULL;
index 0e8157ee5d4382a32992f34c2b1cf0d78f2868b4..1c7a2ec4f3cc81ee608821ddf589fc0b27db4dcc 100644 (file)
@@ -540,8 +540,7 @@ static void prepare_write_message(struct ceph_connection *con)
                /* initialize page iterator */
                con->out_msg_pos.page = 0;
                if (m->pages)
-                       con->out_msg_pos.page_pos =
-                               le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK;
+                       con->out_msg_pos.page_pos = m->page_alignment;
                else
                        con->out_msg_pos.page_pos = 0;
                con->out_msg_pos.data_pos = 0;
@@ -1491,7 +1490,7 @@ static int read_partial_message(struct ceph_connection *con)
        struct ceph_msg *m = con->in_msg;
        int ret;
        int to, left;
-       unsigned front_len, middle_len, data_len, data_off;
+       unsigned front_len, middle_len, data_len;
        int datacrc = con->msgr->nocrc;
        int skip;
        u64 seq;
@@ -1527,19 +1526,17 @@ static int read_partial_message(struct ceph_connection *con)
        data_len = le32_to_cpu(con->in_hdr.data_len);
        if (data_len > CEPH_MSG_MAX_DATA_LEN)
                return -EIO;
-       data_off = le16_to_cpu(con->in_hdr.data_off);
 
        /* verify seq# */
        seq = le64_to_cpu(con->in_hdr.seq);
        if ((s64)seq - (s64)con->in_seq < 1) {
-               pr_info("skipping %s%lld %s seq %lld, expected %lld\n",
+               pr_info("skipping %s%lld %s seq %lld expected %lld\n",
                        ENTITY_NAME(con->peer_name),
                        ceph_pr_addr(&con->peer_addr.in_addr),
                        seq, con->in_seq + 1);
                con->in_base_pos = -front_len - middle_len - data_len -
                        sizeof(m->footer);
                con->in_tag = CEPH_MSGR_TAG_READY;
-               con->in_seq++;
                return 0;
        } else if ((s64)seq - (s64)con->in_seq > 1) {
                pr_err("read_partial_message bad seq %lld expected %lld\n",
@@ -1576,7 +1573,7 @@ static int read_partial_message(struct ceph_connection *con)
 
                con->in_msg_pos.page = 0;
                if (m->pages)
-                       con->in_msg_pos.page_pos = data_off & ~PAGE_MASK;
+                       con->in_msg_pos.page_pos = m->page_alignment;
                else
                        con->in_msg_pos.page_pos = 0;
                con->in_msg_pos.data_pos = 0;
@@ -2301,6 +2298,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags)
 
        /* data */
        m->nr_pages = 0;
+       m->page_alignment = 0;
        m->pages = NULL;
        m->pagelist = NULL;
        m->bio = NULL;
@@ -2370,6 +2368,7 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
                               type, front_len);
                        return NULL;
                }
+               msg->page_alignment = le16_to_cpu(hdr->data_off);
        }
        memcpy(&msg->hdr, &con->in_hdr, sizeof(con->in_hdr));
 
index 79391994b3edee7d531b823c0720262090db6618..3e20a122ffa2f2bf40a91596fe12bb93e6874b64 100644 (file)
@@ -71,6 +71,7 @@ void ceph_calc_raw_layout(struct ceph_osd_client *osdc,
                op->extent.length = objlen;
        }
        req->r_num_pages = calc_pages_for(off, *plen);
+       req->r_page_alignment = off & ~PAGE_MASK;
        if (op->op == CEPH_OSD_OP_WRITE)
                op->payload_len = *plen;
 
@@ -390,6 +391,8 @@ void ceph_osdc_build_request(struct ceph_osd_request *req,
                req->r_request->hdr.data_len = cpu_to_le32(data_len);
        }
 
+       req->r_request->page_alignment = req->r_page_alignment;
+
        BUG_ON(p > msg->front.iov_base + msg->front.iov_len);
        msg_size = p - msg->front.iov_base;
        msg->front.iov_len = msg_size;
@@ -419,7 +422,8 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                                               u32 truncate_seq,
                                               u64 truncate_size,
                                               struct timespec *mtime,
-                                              bool use_mempool, int num_reply)
+                                              bool use_mempool, int num_reply,
+                                              int page_align)
 {
        struct ceph_osd_req_op ops[3];
        struct ceph_osd_request *req;
@@ -447,6 +451,10 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        calc_layout(osdc, vino, layout, off, plen, req, ops);
        req->r_file_layout = *layout;  /* keep a copy */
 
+       /* in case it differs from natural alignment that calc_layout
+          filled in for us */
+       req->r_page_alignment = page_align;
+
        ceph_osdc_build_request(req, off, plen, ops,
                                snapc,
                                mtime,
@@ -1489,7 +1497,7 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc,
                        struct ceph_vino vino, struct ceph_file_layout *layout,
                        u64 off, u64 *plen,
                        u32 truncate_seq, u64 truncate_size,
-                       struct page **pages, int num_pages)
+                       struct page **pages, int num_pages, int page_align)
 {
        struct ceph_osd_request *req;
        int rc = 0;
@@ -1499,15 +1507,15 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc,
        req = ceph_osdc_new_request(osdc, layout, vino, off, plen,
                                    CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ,
                                    NULL, 0, truncate_seq, truncate_size, NULL,
-                                   false, 1);
+                                   false, 1, page_align);
        if (!req)
                return -ENOMEM;
 
        /* it may be a short read due to an object boundary */
        req->r_pages = pages;
 
-       dout("readpages  final extent is %llu~%llu (%d pages)\n",
-            off, *plen, req->r_num_pages);
+       dout("readpages  final extent is %llu~%llu (%d pages align %d)\n",
+            off, *plen, req->r_num_pages, page_align);
 
        rc = ceph_osdc_start_request(osdc, req, false);
        if (!rc)
@@ -1533,6 +1541,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
 {
        struct ceph_osd_request *req;
        int rc = 0;
+       int page_align = off & ~PAGE_MASK;
 
        BUG_ON(vino.snap != CEPH_NOSNAP);
        req = ceph_osdc_new_request(osdc, layout, vino, off, &len,
@@ -1541,7 +1550,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
                                            CEPH_OSD_FLAG_WRITE,
                                    snapc, do_sync,
                                    truncate_seq, truncate_size, mtime,
-                                   nofail, 1);
+                                   nofail, 1, page_align);
        if (!req)
                return -ENOMEM;
 
@@ -1638,8 +1647,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
        m = ceph_msg_get(req->r_reply);
 
        if (data_len > 0) {
-               unsigned data_off = le16_to_cpu(hdr->data_off);
-               int want = calc_pages_for(data_off & ~PAGE_MASK, data_len);
+               int want = calc_pages_for(req->r_page_alignment, data_len);
 
                if (unlikely(req->r_num_pages < want)) {
                        pr_warning("tid %lld reply %d > expected %d pages\n",
@@ -1651,6 +1659,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
                }
                m->pages = req->r_pages;
                m->nr_pages = req->r_num_pages;
+               m->page_alignment = req->r_page_alignment;
 #ifdef CONFIG_BLOCK
                m->bio = req->r_bio;
 #endif
index 54caf06871559adb490018023cea7163f2451706..ac34feeb2b3ab2202e02aeab2a0367f29ac6a2b2 100644 (file)
@@ -13,8 +13,7 @@
  * build a vector of user pages
  */
 struct page **ceph_get_direct_page_vector(const char __user *data,
-                                                int num_pages,
-                                                loff_t off, size_t len)
+                                         int num_pages)
 {
        struct page **pages;
        int rc;
index 35dfb83184833302e616dca6b0985faeb533897d..0dd54a69dace255fcdf54732d982e8c521c574a5 100644 (file)
@@ -2131,7 +2131,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
        } else {
                struct sock *sk = skb->sk;
                queue_index = sk_tx_queue_get(sk);
-               if (queue_index < 0) {
+               if (queue_index < 0 || queue_index >= dev->real_num_tx_queues) {
 
                        queue_index = 0;
                        if (dev->real_num_tx_queues > 1)
index 8abe628b79f173f96fc9e2372f442c91dacc2984..b99c7c7ffce2b72b0089ba8c53d4de6e5b131059 100644 (file)
@@ -370,6 +370,7 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event,
 
 static struct notifier_block dst_dev_notifier = {
        .notifier_call  = dst_dev_event,
+       .priority = -10, /* must be called after other network notifiers */
 };
 
 void __init dst_init(void)
index 7beaec36b541274bcd1d62c9fe8376b368ab3386..c1ee800bc080c3faf33033e1659021a0a356f7ce 100644 (file)
@@ -112,39 +112,41 @@ EXPORT_SYMBOL(sk_filter);
  */
 unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
 {
-       struct sock_filter *fentry;     /* We walk down these */
        void *ptr;
        u32 A = 0;                      /* Accumulator */
        u32 X = 0;                      /* Index Register */
        u32 mem[BPF_MEMWORDS];          /* Scratch Memory Store */
+       unsigned long memvalid = 0;
        u32 tmp;
        int k;
        int pc;
 
+       BUILD_BUG_ON(BPF_MEMWORDS > BITS_PER_LONG);
        /*
         * Process array of filter instructions.
         */
        for (pc = 0; pc < flen; pc++) {
-               fentry = &filter[pc];
+               const struct sock_filter *fentry = &filter[pc];
+               u32 f_k = fentry->k;
 
                switch (fentry->code) {
                case BPF_S_ALU_ADD_X:
                        A += X;
                        continue;
                case BPF_S_ALU_ADD_K:
-                       A += fentry->k;
+                       A += f_k;
                        continue;
                case BPF_S_ALU_SUB_X:
                        A -= X;
                        continue;
                case BPF_S_ALU_SUB_K:
-                       A -= fentry->k;
+                       A -= f_k;
                        continue;
                case BPF_S_ALU_MUL_X:
                        A *= X;
                        continue;
                case BPF_S_ALU_MUL_K:
-                       A *= fentry->k;
+                       A *= f_k;
                        continue;
                case BPF_S_ALU_DIV_X:
                        if (X == 0)
@@ -152,49 +154,49 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int
                        A /= X;
                        continue;
                case BPF_S_ALU_DIV_K:
-                       A /= fentry->k;
+                       A /= f_k;
                        continue;
                case BPF_S_ALU_AND_X:
                        A &= X;
                        continue;
                case BPF_S_ALU_AND_K:
-                       A &= fentry->k;
+                       A &= f_k;
                        continue;
                case BPF_S_ALU_OR_X:
                        A |= X;
                        continue;
                case BPF_S_ALU_OR_K:
-                       A |= fentry->k;
+                       A |= f_k;
                        continue;
                case BPF_S_ALU_LSH_X:
                        A <<= X;
                        continue;
                case BPF_S_ALU_LSH_K:
-                       A <<= fentry->k;
+                       A <<= f_k;
                        continue;
                case BPF_S_ALU_RSH_X:
                        A >>= X;
                        continue;
                case BPF_S_ALU_RSH_K:
-                       A >>= fentry->k;
+                       A >>= f_k;
                        continue;
                case BPF_S_ALU_NEG:
                        A = -A;
                        continue;
                case BPF_S_JMP_JA:
-                       pc += fentry->k;
+                       pc += f_k;
                        continue;
                case BPF_S_JMP_JGT_K:
-                       pc += (A > fentry->k) ? fentry->jt : fentry->jf;
+                       pc += (A > f_k) ? fentry->jt : fentry->jf;
                        continue;
                case BPF_S_JMP_JGE_K:
-                       pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
+                       pc += (A >= f_k) ? fentry->jt : fentry->jf;
                        continue;
                case BPF_S_JMP_JEQ_K:
-                       pc += (A == fentry->k) ? fentry->jt : fentry->jf;
+                       pc += (A == f_k) ? fentry->jt : fentry->jf;
                        continue;
                case BPF_S_JMP_JSET_K:
-                       pc += (A & fentry->k) ? fentry->jt : fentry->jf;
+                       pc += (A & f_k) ? fentry->jt : fentry->jf;
                        continue;
                case BPF_S_JMP_JGT_X:
                        pc += (A > X) ? fentry->jt : fentry->jf;
@@ -209,7 +211,7 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int
                        pc += (A & X) ? fentry->jt : fentry->jf;
                        continue;
                case BPF_S_LD_W_ABS:
-                       k = fentry->k;
+                       k = f_k;
 load_w:
                        ptr = load_pointer(skb, k, 4, &tmp);
                        if (ptr != NULL) {
@@ -218,7 +220,7 @@ load_w:
                        }
                        break;
                case BPF_S_LD_H_ABS:
-                       k = fentry->k;
+                       k = f_k;
 load_h:
                        ptr = load_pointer(skb, k, 2, &tmp);
                        if (ptr != NULL) {
@@ -227,7 +229,7 @@ load_h:
                        }
                        break;
                case BPF_S_LD_B_ABS:
-                       k = fentry->k;
+                       k = f_k;
 load_b:
                        ptr = load_pointer(skb, k, 1, &tmp);
                        if (ptr != NULL) {
@@ -242,32 +244,34 @@ load_b:
                        X = skb->len;
                        continue;
                case BPF_S_LD_W_IND:
-                       k = X + fentry->k;
+                       k = X + f_k;
                        goto load_w;
                case BPF_S_LD_H_IND:
-                       k = X + fentry->k;
+                       k = X + f_k;
                        goto load_h;
                case BPF_S_LD_B_IND:
-                       k = X + fentry->k;
+                       k = X + f_k;
                        goto load_b;
                case BPF_S_LDX_B_MSH:
-                       ptr = load_pointer(skb, fentry->k, 1, &tmp);
+                       ptr = load_pointer(skb, f_k, 1, &tmp);
                        if (ptr != NULL) {
                                X = (*(u8 *)ptr & 0xf) << 2;
                                continue;
                        }
                        return 0;
                case BPF_S_LD_IMM:
-                       A = fentry->k;
+                       A = f_k;
                        continue;
                case BPF_S_LDX_IMM:
-                       X = fentry->k;
+                       X = f_k;
                        continue;
                case BPF_S_LD_MEM:
-                       A = mem[fentry->k];
+                       A = (memvalid & (1UL << f_k)) ?
+                               mem[f_k] : 0;
                        continue;
                case BPF_S_LDX_MEM:
-                       X = mem[fentry->k];
+                       X = (memvalid & (1UL << f_k)) ?
+                               mem[f_k] : 0;
                        continue;
                case BPF_S_MISC_TAX:
                        X = A;
@@ -276,14 +280,16 @@ load_b:
                        A = X;
                        continue;
                case BPF_S_RET_K:
-                       return fentry->k;
+                       return f_k;
                case BPF_S_RET_A:
                        return A;
                case BPF_S_ST:
-                       mem[fentry->k] = A;
+                       memvalid |= 1UL << f_k;
+                       mem[f_k] = A;
                        continue;
                case BPF_S_STX:
-                       mem[fentry->k] = X;
+                       memvalid |= 1UL << f_k;
+                       mem[f_k] = X;
                        continue;
                default:
                        WARN_ON(1);
@@ -583,7 +589,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
 EXPORT_SYMBOL(sk_chk_filter);
 
 /**
- *     sk_filter_rcu_release: Release a socket filter by rcu_head
+ *     sk_filter_rcu_release - Release a socket filter by rcu_head
  *     @rcu: rcu_head that contains the sk_filter to free
  */
 static void sk_filter_rcu_release(struct rcu_head *rcu)
index a5ff5a89f376bb1299dec78fa34abe9480ae01f1..7f902cad10f8b13d7096f53905e3a47bb3c12d25 100644 (file)
@@ -712,15 +712,21 @@ static void rx_queue_release(struct kobject *kobj)
 
 
        map = rcu_dereference_raw(queue->rps_map);
-       if (map)
+       if (map) {
+               RCU_INIT_POINTER(queue->rps_map, NULL);
                call_rcu(&map->rcu, rps_map_release);
+       }
 
        flow_table = rcu_dereference_raw(queue->rps_flow_table);
-       if (flow_table)
+       if (flow_table) {
+               RCU_INIT_POINTER(queue->rps_flow_table, NULL);
                call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
+       }
 
        if (atomic_dec_and_test(&first->count))
                kfree(first);
+       else
+               memset(kobj, 0, sizeof(*kobj));
 }
 
 static struct kobj_type rx_queue_ktype = {
index fbce4b05a53e79b502e37e7d768228dc6155b5d9..33bc3823ac6fce64b227fafe670f2b12e3816a86 100644 (file)
@@ -887,7 +887,7 @@ static ssize_t pktgen_if_write(struct file *file,
        i += len;
 
        if (debug) {
-               size_t copy = min(count, 1023);
+               size_t copy = min_t(size_t, count, 1023);
                char tb[copy + 1];
                if (copy_from_user(tb, user_buffer, copy))
                        return -EFAULT;
@@ -2612,8 +2612,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        /* Update any of the values, used when we're incrementing various
         * fields.
         */
-       queue_map = pkt_dev->cur_queue_map;
        mod_cur_headers(pkt_dev);
+       queue_map = pkt_dev->cur_queue_map;
 
        datalen = (odev->hard_header_len + 16) & ~0xf;
 
@@ -2976,8 +2976,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        /* Update any of the values, used when we're incrementing various
         * fields.
         */
-       queue_map = pkt_dev->cur_queue_map;
        mod_cur_headers(pkt_dev);
+       queue_map = pkt_dev->cur_queue_map;
 
        skb = __netdev_alloc_skb(odev,
                                 pkt_dev->cur_pkt_size + 64
index 7552495aff7aef090d99654312d5365afa421e95..fceeb37d7161697922dd46e00d62e3c1cd89eb4b 100644 (file)
@@ -45,9 +45,7 @@ int reqsk_queue_alloc(struct request_sock_queue *queue,
        nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);
        lopt_size += nr_table_entries * sizeof(struct request_sock *);
        if (lopt_size > PAGE_SIZE)
-               lopt = __vmalloc(lopt_size,
-                       GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
-                       PAGE_KERNEL);
+               lopt = vzalloc(lopt_size);
        else
                lopt = kzalloc(lopt_size, GFP_KERNEL);
        if (lopt == NULL)
index 8121268ddbddfcd2da9845c8254fe0406b031be9..841c287ef40a4706c3465425880f95abd608e954 100644 (file)
@@ -347,16 +347,17 @@ static size_t rtnl_link_get_size(const struct net_device *dev)
        if (!ops)
                return 0;
 
-       size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */
-              nlmsg_total_size(strlen(ops->kind) + 1);  /* IFLA_INFO_KIND */
+       size = nla_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */
+              nla_total_size(strlen(ops->kind) + 1);  /* IFLA_INFO_KIND */
 
        if (ops->get_size)
                /* IFLA_INFO_DATA + nested data */
-               size += nlmsg_total_size(sizeof(struct nlattr)) +
+               size += nla_total_size(sizeof(struct nlattr)) +
                        ops->get_size(dev);
 
        if (ops->get_xstats_size)
-               size += ops->get_xstats_size(dev);      /* IFLA_INFO_XSTATS */
+               /* IFLA_INFO_XSTATS */
+               size += nla_total_size(ops->get_xstats_size(dev));
 
        return size;
 }
index 3eed5424e659a1ab130324d16bfe3c0af4ab2feb..fb6080111461546953b34979db77f5e2d516e060 100644 (file)
@@ -1653,10 +1653,10 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)
 {
        struct proto *prot = sk->sk_prot;
        int amt = sk_mem_pages(size);
-       int allocated;
+       long allocated;
 
        sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
-       allocated = atomic_add_return(amt, prot->memory_allocated);
+       allocated = atomic_long_add_return(amt, prot->memory_allocated);
 
        /* Under limit. */
        if (allocated <= prot->sysctl_mem[0]) {
@@ -1714,7 +1714,7 @@ suppress_allocation:
 
        /* Alas. Undo changes. */
        sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM;
-       atomic_sub(amt, prot->memory_allocated);
+       atomic_long_sub(amt, prot->memory_allocated);
        return 0;
 }
 EXPORT_SYMBOL(__sk_mem_schedule);
@@ -1727,12 +1727,12 @@ void __sk_mem_reclaim(struct sock *sk)
 {
        struct proto *prot = sk->sk_prot;
 
-       atomic_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT,
+       atomic_long_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT,
                   prot->memory_allocated);
        sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1;
 
        if (prot->memory_pressure && *prot->memory_pressure &&
-           (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0]))
+           (atomic_long_read(prot->memory_allocated) < prot->sysctl_mem[0]))
                *prot->memory_pressure = 0;
 }
 EXPORT_SYMBOL(__sk_mem_reclaim);
@@ -2452,12 +2452,12 @@ static char proto_method_implemented(const void *method)
 
 static void proto_seq_printf(struct seq_file *seq, struct proto *proto)
 {
-       seq_printf(seq, "%-9s %4u %6d  %6d   %-3s %6u   %-3s  %-10s "
+       seq_printf(seq, "%-9s %4u %6d  %6ld   %-3s %6u   %-3s  %-10s "
                        "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n",
                   proto->name,
                   proto->obj_size,
                   sock_prot_inuse_get(seq_file_net(seq), proto),
-                  proto->memory_allocated != NULL ? atomic_read(proto->memory_allocated) : -1,
+                  proto->memory_allocated != NULL ? atomic_long_read(proto->memory_allocated) : -1L,
                   proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI",
                   proto->max_header,
                   proto->slab == NULL ? "no" : "yes",
index d6b93d19790f003b92935c1b1da7700e8d788787..a76b78de679fa7e928cfae7b62c0a7e73c2256dd 100644 (file)
@@ -155,7 +155,7 @@ static const struct proto_ops dn_proto_ops;
 static DEFINE_RWLOCK(dn_hash_lock);
 static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
 static struct hlist_head dn_wild_sk;
-static atomic_t decnet_memory_allocated;
+static atomic_long_t decnet_memory_allocated;
 
 static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen, int flags);
 static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags);
index be3eb8e23288ed078e947a3ef8e78d671666b9be..28f8b5e5f73b20fcee72b7aa536f1fdd04dc95c9 100644 (file)
@@ -38,7 +38,7 @@ int decnet_log_martians = 1;
 int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW;
 
 /* Reasonable defaults, I hope, based on tcp's defaults */
-int sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
+long sysctl_decnet_mem[3] = { 768 << 3, 1024 << 3, 1536 << 3 };
 int sysctl_decnet_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
 int sysctl_decnet_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
 
@@ -324,7 +324,7 @@ static ctl_table dn_table[] = {
                .data = &sysctl_decnet_mem,
                .maxlen = sizeof(sysctl_decnet_mem),
                .mode = 0644,
-               .proc_handler = proc_dointvec,
+               .proc_handler = proc_doulongvec_minmax
        },
        {
                .procname = "decnet_rmem",
index a29edf2219c8437b811bcce27fdd2cd9fca0a9fc..c079cc0ec6515fe212aecd27303c2b5671a5d60d 100644 (file)
@@ -47,11 +47,8 @@ extern int fib_detect_death(struct fib_info *fi, int order,
 static inline void fib_result_assign(struct fib_result *res,
                                     struct fib_info *fi)
 {
-       if (res->fi != NULL)
-               fib_info_put(res->fi);
+       /* we used to play games with refcounts, but we now use RCU */
        res->fi = fi;
-       if (fi != NULL)
-               atomic_inc(&fi->fib_clntref);
 }
 
 #endif /* _FIB_LOOKUP_H */
index 200eb538fbb3f77101fe9646893dddbd9e83117b..0f280348e0fdad70adb37f3b33bdbe6fedd99025 100644 (file)
@@ -365,7 +365,7 @@ static struct tnode *tnode_alloc(size_t size)
        if (size <= PAGE_SIZE)
                return kzalloc(size, GFP_KERNEL);
        else
-               return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               return vzalloc(size);
 }
 
 static void __tnode_vfree(struct work_struct *arg)
index 96bc7f9475a3f2f0124685cc1b7afb7b58c23d8d..e5d1a44bcbdf04b851d441ea5ebd8fbe44514704 100644 (file)
@@ -569,6 +569,9 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
                /* No need to clone since we're just using its address. */
                rt2 = rt;
 
+               if (!fl.nl_u.ip4_u.saddr)
+                       fl.nl_u.ip4_u.saddr = rt->rt_src;
+
                err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0);
                switch (err) {
                case 0:
index c8877c6c72164ccaee2af4def0025f8300bc7e80..3c53c2d89e3b47b3e42629bfe37086aeeeda7aa8 100644 (file)
@@ -2306,10 +2306,8 @@ void ip_mc_drop_socket(struct sock *sk)
 
                in_dev = inetdev_by_index(net, iml->multi.imr_ifindex);
                (void) ip_mc_leave_src(sk, iml, in_dev);
-               if (in_dev != NULL) {
+               if (in_dev != NULL)
                        ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
-                       in_dev_put(in_dev);
-               }
                /* decrease mem now to avoid the memleak warning */
                atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
                call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
index ba80426658498ba4082c54a19c5af2d2c00cdb10..2ada17129fce6ac9a7285f6033e30d0a9bc4b98a 100644 (file)
@@ -490,9 +490,11 @@ static int inet_csk_diag_dump(struct sock *sk,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
                struct inet_sock *inet = inet_sk(sk);
 
                entry.family = sk->sk_family;
@@ -512,7 +514,7 @@ static int inet_csk_diag_dump(struct sock *sk,
                entry.dport = ntohs(inet->inet_dport);
                entry.userlocks = sk->sk_userlocks;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -527,9 +529,11 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
 
                entry.family = tw->tw_family;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -548,7 +552,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
                entry.dport = ntohs(tw->tw_dport);
                entry.userlocks = 0;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -618,7 +622,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct listen_sock *lopt;
-       struct rtattr *bc = NULL;
+       const struct nlattr *bc = NULL;
        struct inet_sock *inet = inet_sk(sk);
        int j, s_j;
        int reqnum, s_reqnum;
@@ -638,8 +642,9 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        if (!lopt || !lopt->qlen)
                goto out;
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
-               bc = (struct rtattr *)(r + 1);
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
+               bc = nlmsg_find_attr(cb->nlh, sizeof(*r),
+                                    INET_DIAG_REQ_BYTECODE);
                entry.sport = inet->inet_num;
                entry.userlocks = sk->sk_userlocks;
        }
@@ -672,8 +677,8 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
                                        &ireq->rmt_addr;
                                entry.dport = ntohs(ireq->rmt_port);
 
-                               if (!inet_diag_bc_run(RTA_DATA(bc),
-                                                   RTA_PAYLOAD(bc), &entry))
+                               if (!inet_diag_bc_run(nla_data(bc),
+                                                     nla_len(bc), &entry))
                                        continue;
                        }
 
index 3cad2591ace0c15fdad446ab528b0f40c2624d09..3fac340a28d5394bd95bd649d5bcee3dcb3d24df 100644 (file)
@@ -927,6 +927,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index d31b007a6d80dcda45f7f7913ec72af7556b79bf..a846d633b3b6f04a3ed72be1d884e484d3efa030 100644 (file)
@@ -1124,6 +1124,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 295c97431e4358408dc45fc7c493536bb41434fc..c04787ce1a71203e1346830450b0a130e358defc 100644 (file)
@@ -47,26 +47,6 @@ __nf_nat_proto_find(u_int8_t protonum)
        return rcu_dereference(nf_nat_protos[protonum]);
 }
 
-static const struct nf_nat_protocol *
-nf_nat_proto_find_get(u_int8_t protonum)
-{
-       const struct nf_nat_protocol *p;
-
-       rcu_read_lock();
-       p = __nf_nat_proto_find(protonum);
-       if (!try_module_get(p->me))
-               p = &nf_nat_unknown_protocol;
-       rcu_read_unlock();
-
-       return p;
-}
-
-static void
-nf_nat_proto_put(const struct nf_nat_protocol *p)
-{
-       module_put(p->me);
-}
-
 /* We keep an extra hash for each conntrack, for fast searching. */
 static inline unsigned int
 hash_by_src(const struct net *net, u16 zone,
@@ -588,6 +568,26 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
 
+static const struct nf_nat_protocol *
+nf_nat_proto_find_get(u_int8_t protonum)
+{
+       const struct nf_nat_protocol *p;
+
+       rcu_read_lock();
+       p = __nf_nat_proto_find(protonum);
+       if (!try_module_get(p->me))
+               p = &nf_nat_unknown_protocol;
+       rcu_read_unlock();
+
+       return p;
+}
+
+static void
+nf_nat_proto_put(const struct nf_nat_protocol *p)
+{
+       module_put(p->me);
+}
+
 static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
        [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
        [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
index 4ae1f203f7cbb5daf7c07bea4a062c352c83700d..1b48eb1ed4531d3fd037e7ee9aa6367b6cb575f3 100644 (file)
@@ -59,13 +59,13 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
        local_bh_enable();
 
        socket_seq_show(seq);
-       seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
+       seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %ld\n",
                   sock_prot_inuse_get(net, &tcp_prot), orphans,
                   tcp_death_row.tw_count, sockets,
-                  atomic_read(&tcp_memory_allocated));
-       seq_printf(seq, "UDP: inuse %d mem %d\n",
+                  atomic_long_read(&tcp_memory_allocated));
+       seq_printf(seq, "UDP: inuse %d mem %ld\n",
                   sock_prot_inuse_get(net, &udp_prot),
-                  atomic_read(&udp_memory_allocated));
+                  atomic_long_read(&udp_memory_allocated));
        seq_printf(seq, "UDPLITE: inuse %d\n",
                   sock_prot_inuse_get(net, &udplite_prot));
        seq_printf(seq, "RAW: inuse %d\n",
index d96c1da4b17cf97790bb2a426abbe5eb4582356d..e91911d7aae26656f940a747a6d0ccb91739f39a 100644 (file)
@@ -398,7 +398,7 @@ static struct ctl_table ipv4_table[] = {
                .data           = &sysctl_tcp_mem,
                .maxlen         = sizeof(sysctl_tcp_mem),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_doulongvec_minmax
        },
        {
                .procname       = "tcp_wmem",
@@ -602,8 +602,7 @@ static struct ctl_table ipv4_table[] = {
                .data           = &sysctl_udp_mem,
                .maxlen         = sizeof(sysctl_udp_mem),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero
+               .proc_handler   = proc_doulongvec_minmax,
        },
        {
                .procname       = "udp_rmem_min",
index 1664a0590bb8f28fe5662e2cfdbc3a6d660d4549..0814199694854e534eb4ff12671e02313dced8e9 100644 (file)
@@ -282,7 +282,7 @@ int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
 struct percpu_counter tcp_orphan_count;
 EXPORT_SYMBOL_GPL(tcp_orphan_count);
 
-int sysctl_tcp_mem[3] __read_mostly;
+long sysctl_tcp_mem[3] __read_mostly;
 int sysctl_tcp_wmem[3] __read_mostly;
 int sysctl_tcp_rmem[3] __read_mostly;
 
@@ -290,7 +290,7 @@ EXPORT_SYMBOL(sysctl_tcp_mem);
 EXPORT_SYMBOL(sysctl_tcp_rmem);
 EXPORT_SYMBOL(sysctl_tcp_wmem);
 
-atomic_t tcp_memory_allocated; /* Current allocated memory. */
+atomic_long_t tcp_memory_allocated;    /* Current allocated memory. */
 EXPORT_SYMBOL(tcp_memory_allocated);
 
 /*
@@ -2246,7 +2246,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                /* Values greater than interface MTU won't take effect. However
                 * at the point when this call is done we typically don't yet
                 * know which interface is going to be used */
-               if (val < 8 || val > MAX_TCP_WINDOW) {
+               if (val < 64 || val > MAX_TCP_WINDOW) {
                        err = -EINVAL;
                        break;
                }
index 3357f69e353d445b51c3178899609245b6720404..6d8ab1c4efc3ea59c4848c74ae367f872cd6505e 100644 (file)
@@ -259,8 +259,11 @@ static void tcp_fixup_sndbuf(struct sock *sk)
        int sndmem = tcp_sk(sk)->rx_opt.mss_clamp + MAX_TCP_HEADER + 16 +
                     sizeof(struct sk_buff);
 
-       if (sk->sk_sndbuf < 3 * sndmem)
-               sk->sk_sndbuf = min(3 * sndmem, sysctl_tcp_wmem[2]);
+       if (sk->sk_sndbuf < 3 * sndmem) {
+               sk->sk_sndbuf = 3 * sndmem;
+               if (sk->sk_sndbuf > sysctl_tcp_wmem[2])
+                       sk->sk_sndbuf = sysctl_tcp_wmem[2];
+       }
 }
 
 /* 2. Tuning advertised window (window_clamp, rcv_ssthresh)
@@ -396,7 +399,7 @@ static void tcp_clamp_window(struct sock *sk)
        if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] &&
            !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) &&
            !tcp_memory_pressure &&
-           atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) {
+           atomic_long_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) {
                sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc),
                                    sysctl_tcp_rmem[2]);
        }
@@ -4861,7 +4864,7 @@ static int tcp_should_expand_sndbuf(struct sock *sk)
                return 0;
 
        /* If we are under soft global TCP memory pressure, do not expand.  */
-       if (atomic_read(&tcp_memory_allocated) >= sysctl_tcp_mem[0])
+       if (atomic_long_read(&tcp_memory_allocated) >= sysctl_tcp_mem[0])
                return 0;
 
        /* If we filled the congestion window, do not expand.  */
index 8f8527d4168225be9429766df1d1e2c085057868..69ccbc1dde9cdfed2719e243fd6091cc9781a876 100644 (file)
@@ -415,6 +415,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                    !icsk->icsk_backoff)
                        break;
 
+               if (sock_owned_by_user(sk))
+                       break;
+
                icsk->icsk_backoff--;
                inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) <<
                                         icsk->icsk_backoff;
@@ -429,11 +432,6 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                if (remaining) {
                        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                                                  remaining, TCP_RTO_MAX);
-               } else if (sock_owned_by_user(sk)) {
-                       /* RTO revert clocked out retransmission,
-                        * but socket is locked. Will defer. */
-                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-                                                 HZ/20, TCP_RTO_MAX);
                } else {
                        /* RTO revert clocked out retransmission.
                         * Will retransmit now */
index 28cb2d733a3cf6a9dd8e65a8dd2de0b44caae782..5e0a3a582a59a05466468b244371dc5675bedc67 100644 (file)
 struct udp_table udp_table __read_mostly;
 EXPORT_SYMBOL(udp_table);
 
-int sysctl_udp_mem[3] __read_mostly;
+long sysctl_udp_mem[3] __read_mostly;
 EXPORT_SYMBOL(sysctl_udp_mem);
 
 int sysctl_udp_rmem_min __read_mostly;
@@ -119,7 +119,7 @@ EXPORT_SYMBOL(sysctl_udp_rmem_min);
 int sysctl_udp_wmem_min __read_mostly;
 EXPORT_SYMBOL(sysctl_udp_wmem_min);
 
-atomic_t udp_memory_allocated;
+atomic_long_t udp_memory_allocated;
 EXPORT_SYMBOL(udp_memory_allocated);
 
 #define MAX_UDP_PORTS 65536
index e048ec62d109f8f2024c113c4aa3c52d984d084c..23cc8e1ce8d4995a551ca93d98434e9150ad1740 100644 (file)
 #endif
 
 #define        INFINITY_LIFE_TIME      0xFFFFFFFF
-#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
+
+static inline u32 cstamp_delta(unsigned long cstamp)
+{
+       return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
+}
 
 #define ADDRCONF_TIMER_FUZZ_MINUS      (HZ > 50 ? HZ/50 : 1)
 #define ADDRCONF_TIMER_FUZZ            (HZ / 4)
@@ -2740,10 +2744,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                        /* Flag it for later restoration when link comes up */
                        ifa->flags |= IFA_F_TENTATIVE;
                        ifa->state = INET6_IFADDR_STATE_DAD;
-
-                       write_unlock_bh(&idev->lock);
-
-                       in6_ifa_hold(ifa);
                } else {
                        list_del(&ifa->if_list);
 
@@ -2758,19 +2758,15 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                        ifa->state = INET6_IFADDR_STATE_DEAD;
                        spin_unlock_bh(&ifa->state_lock);
 
-                       if (state == INET6_IFADDR_STATE_DEAD)
-                               goto put_ifa;
-               }
-
-               __ipv6_ifa_notify(RTM_DELADDR, ifa);
-               if (ifa->state == INET6_IFADDR_STATE_DEAD)
-                       atomic_notifier_call_chain(&inet6addr_chain,
-                                                  NETDEV_DOWN, ifa);
-
-put_ifa:
-               in6_ifa_put(ifa);
+                       if (state != INET6_IFADDR_STATE_DEAD) {
+                               __ipv6_ifa_notify(RTM_DELADDR, ifa);
+                               atomic_notifier_call_chain(&inet6addr_chain,
+                                                          NETDEV_DOWN, ifa);
+                       }
 
-               write_lock_bh(&idev->lock);
+                       in6_ifa_put(ifa);
+                       write_lock_bh(&idev->lock);
+               }
        }
 
        list_splice(&keep_list, &idev->addr_list);
@@ -3452,10 +3448,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
 {
        struct ifa_cacheinfo ci;
 
-       ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100
-                       + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
-       ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100
-                       + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
+       ci.cstamp = cstamp_delta(cstamp);
+       ci.tstamp = cstamp_delta(tstamp);
        ci.ifa_prefered = preferred;
        ci.ifa_valid = valid;
 
@@ -3806,8 +3800,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_AUTOCONF] = cnf->autoconf;
        array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits;
        array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits;
-       array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval;
-       array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay;
+       array[DEVCONF_RTR_SOLICIT_INTERVAL] =
+               jiffies_to_msecs(cnf->rtr_solicit_interval);
+       array[DEVCONF_RTR_SOLICIT_DELAY] =
+               jiffies_to_msecs(cnf->rtr_solicit_delay);
        array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version;
 #ifdef CONFIG_IPV6_PRIVACY
        array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr;
@@ -3821,7 +3817,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
 #ifdef CONFIG_IPV6_ROUTER_PREF
        array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
-       array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
+       array[DEVCONF_RTR_PROBE_INTERVAL] =
+               jiffies_to_msecs(cnf->rtr_probe_interval);
 #ifdef CONFIG_IPV6_ROUTE_INFO
        array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
 #endif
@@ -3937,10 +3934,9 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
        NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
 
        ci.max_reasm_len = IPV6_MAXPLEN;
-       ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100
-                   + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
-       ci.reachable_time = idev->nd_parms->reachable_time;
-       ci.retrans_time = idev->nd_parms->retrans_time;
+       ci.tstamp = cstamp_delta(idev->tstamp);
+       ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
+       ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
        NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
 
        nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
index 51df035897e77dfa5b89e6328817cfcb638702cb..455582384eced0b9242a40ea523ac31c8d6e08f4 100644 (file)
@@ -1137,6 +1137,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 3a3f129a44cb3561dd3e135164626f8352c565b7..79d43aa8fa8da80b405689bf7c751d7a9cc89ad4 100644 (file)
@@ -286,7 +286,7 @@ found:
 
        /* Check for overlap with preceding fragment. */
        if (prev &&
-           (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0)
+           (NFCT_FRAG6_CB(prev)->offset + prev->len) > offset)
                goto discard_fq;
 
        /* Look for overlap with succeeding segment. */
index c7ba3149633fcf79160849498d87ae5e53f695b1..0f276645375969054b36aea6c8fcb7a80666921c 100644 (file)
@@ -349,7 +349,7 @@ found:
 
        /* Check for overlap with preceding fragment. */
        if (prev &&
-           (FRAG6_CB(prev)->offset + prev->len) - offset > 0)
+           (FRAG6_CB(prev)->offset + prev->len) > offset)
                goto discard_fq;
 
        /* Look for overlap with succeeding segment. */
index 25661f968f3fb2c2976575f4233fd03c42edb863..96455ffb76fb8b92aa90c3a711aa6635d45b91fa 100644 (file)
@@ -1945,8 +1945,12 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
        struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops);
        struct neighbour *neigh;
 
-       if (rt == NULL)
+       if (rt == NULL) {
+               if (net_ratelimit())
+                       pr_warning("IPv6:  Maximum number of routes reached,"
+                                  " consider increasing route/max_size.\n");
                return ERR_PTR(-ENOMEM);
+       }
 
        dev_hold(net->loopback_dev);
        in6_dev_hold(idev);
@@ -2741,6 +2745,7 @@ static void __net_exit ip6_route_net_exit(struct net *net)
        kfree(net->ipv6.ip6_prohibit_entry);
        kfree(net->ipv6.ip6_blk_hole_entry);
 #endif
+       dst_entries_destroy(&net->ipv6.ip6_dst_ops);
 }
 
 static struct pernet_operations ip6_route_net_ops = {
@@ -2832,5 +2837,6 @@ void ip6_route_cleanup(void)
        xfrm6_fini();
        fib6_gc_cleanup();
        unregister_pernet_subsys(&ip6_route_net_ops);
+       dst_entries_destroy(&ip6_dst_blackhole_ops);
        kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
 }
index 7f097989cde2149714eab1ea7b1de02280531ed2..a6de3059746ddd3f3039d564f20acf394225e3ad 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/slab.h>
index 7fa86373de414a810be41e6973027d0b31c12168..7c567b8aa89a9e938dc442487b70d5e099bc2ade 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include "irnet_ppp.h"         /* Private header */
 /* Please put other headers in irnet.h - Thanks */
 
index 285761e77d90f98ee15c6b47b34c8ead10692e33..f6054f9ccbe33c2fbd9aef8c88551c84bb5fbf62 100644 (file)
@@ -550,22 +550,30 @@ EXPORT_SYMBOL(irttp_close_tsap);
  */
 int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
 {
+       int ret;
+
        IRDA_ASSERT(self != NULL, return -1;);
        IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
        IRDA_ASSERT(skb != NULL, return -1;);
 
        IRDA_DEBUG(4, "%s()\n", __func__);
 
+       /* Take shortcut on zero byte packets */
+       if (skb->len == 0) {
+               ret = 0;
+               goto err;
+       }
+
        /* Check that nothing bad happens */
-       if ((skb->len == 0) || (!self->connected)) {
-               IRDA_DEBUG(1, "%s(), No data, or not connected\n",
-                          __func__);
+       if (!self->connected) {
+               IRDA_WARNING("%s(), Not connected\n", __func__);
+               ret = -ENOTCONN;
                goto err;
        }
 
        if (skb->len > self->max_seg_size) {
-               IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n",
-                          __func__);
+               IRDA_ERROR("%s(), UData is too large for IrLAP!\n", __func__);
+               ret = -EMSGSIZE;
                goto err;
        }
 
@@ -576,7 +584,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
 
 err:
        dev_kfree_skb(skb);
-       return -1;
+       return ret;
 }
 EXPORT_SYMBOL(irttp_udata_request);
 
@@ -599,9 +607,15 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
        IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
                   skb_queue_len(&self->tx_queue));
 
+       /* Take shortcut on zero byte packets */
+       if (skb->len == 0) {
+               ret = 0;
+               goto err;
+       }
+
        /* Check that nothing bad happens */
-       if ((skb->len == 0) || (!self->connected)) {
-               IRDA_WARNING("%s: No data, or not connected\n", __func__);
+       if (!self->connected) {
+               IRDA_WARNING("%s: Not connected\n", __func__);
                ret = -ENOTCONN;
                goto err;
        }
index 104ec3b283d4159f610ef61548beb512d053dcd3..b8dbae82fab8612974d603c42b4cbac3b0509165 100644 (file)
@@ -249,7 +249,7 @@ static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
        struct seq_file *seq;
        int rc = -ENOMEM;
 
-       pd = kzalloc(GFP_KERNEL, sizeof(*pd));
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
        if (pd == NULL)
                goto out;
 
index f9163b12c7f17aca87970366d3069f563b8a6655..7aa85591dbe764ca8b485759a94922ab4b58520b 100644 (file)
@@ -391,6 +391,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        u32 hw_reconf_flags = 0;
        int i;
 
+       if (local->scan_sdata == sdata)
+               ieee80211_scan_cancel(local);
+
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
        /*
@@ -523,9 +526,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                synchronize_rcu();
                skb_queue_purge(&sdata->skb_queue);
 
-               if (local->scan_sdata == sdata)
-                       ieee80211_scan_cancel(local);
-
                /*
                 * Disable beaconing here for mesh only, AP and IBSS
                 * are already taken care of.
index a22dac227055e7499bfd9d8dd509ee5fba3e1c9b..70bd1d0774c6bdb6b1f9d4d1f07284cfe43500dd 100644 (file)
@@ -4,6 +4,7 @@
 menuconfig IP_VS
        tristate "IP virtual server support"
        depends on NET && INET && NETFILTER
+       depends on (NF_CONNTRACK || NF_CONNTRACK=n)
        ---help---
          IP Virtual Server support will let you build a high-performance
          virtual server based on cluster of two or more real servers. This
index 1eacf8d9966aa292f7f051964f822a00c0ab6605..27a5ea6b6a0ff1a644205ca705f717c78b4dcc84 100644 (file)
@@ -1312,7 +1312,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls)
        if (!hash) {
                *vmalloced = 1;
                printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
-               hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               hash = __vmalloc(sz, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+                                PAGE_KERNEL);
        }
 
        if (hash && nulls)
index ed6d929580236c1b4aa77a42db959c9e522f2fc5..dc7bb74110df22818b42222450f0141068b79b6d 100644 (file)
@@ -292,6 +292,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 
                for (i = 0; i < MAX_NF_CT_PROTO; i++)
                        proto_array[i] = &nf_conntrack_l4proto_generic;
+
+               /* Before making proto_array visible to lockless readers,
+                * we must make sure its content is committed to memory.
+                */
+               smp_wmb();
+
                nf_ct_protos[l4proto->l3proto] = proto_array;
        } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] !=
                                        &nf_conntrack_l4proto_generic) {
index 3616f27b9d46c08e0f750b47865cc17c3130c5f2..8298e676f5a015f58d1b6005cf85938f8c8e142a 100644 (file)
@@ -1610,9 +1610,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
 
                err = -EINVAL;
                vnet_hdr_len = sizeof(vnet_hdr);
-               if ((len -= vnet_hdr_len) < 0)
+               if (len < vnet_hdr_len)
                        goto out_free;
 
+               len -= vnet_hdr_len;
+
                if (skb_is_gso(skb)) {
                        struct skb_shared_info *sinfo = skb_shinfo(skb);
 
@@ -1719,7 +1721,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,
        rcu_read_lock();
        dev = dev_get_by_index_rcu(sock_net(sk), pkt_sk(sk)->ifindex);
        if (dev)
-               strlcpy(uaddr->sa_data, dev->name, 15);
+               strncpy(uaddr->sa_data, dev->name, 14);
        else
                memset(uaddr->sa_data, 0, 14);
        rcu_read_unlock();
@@ -1742,6 +1744,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
        sll->sll_family = AF_PACKET;
        sll->sll_ifindex = po->ifindex;
        sll->sll_protocol = po->num;
+       sll->sll_pkttype = 0;
        rcu_read_lock();
        dev = dev_get_by_index_rcu(sock_net(sk), po->ifindex);
        if (dev) {
index c390156b426fc936c6b05fd607f4c32ddb1e3a81..aeec1d483b17e6f65c858e1510c7752965e35260 100644 (file)
@@ -134,8 +134,12 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_loop_conn_free(void *arg)
 {
        struct rds_loop_connection *lc = arg;
+       unsigned long flags;
+
        rdsdebug("lc %p\n", lc);
+       spin_lock_irqsave(&loop_conns_lock, flags);
        list_del(&lc->loop_node);
+       spin_unlock_irqrestore(&loop_conns_lock, flags);
        kfree(lc);
 }
 
index 848cff45183bb3ef9fc52864c952cba3903b17c3..1fd3d29023d7684d524cff00a2da35b2eb03b2b4 100644 (file)
@@ -249,8 +249,10 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
        rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
        rm->data.op_nents = ceil(total_len, PAGE_SIZE);
        rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
-       if (!rm->data.op_sg)
+       if (!rm->data.op_sg) {
+               rds_message_put(rm);
                return ERR_PTR(-ENOMEM);
+       }
 
        for (i = 0; i < rm->data.op_nents; ++i) {
                sg_set_page(&rm->data.op_sg[i],
index 8920f2a83327a42f10d20acdfb651f9c1b9620a3..4e37c1cbe8b2faf5928af6be551f3f5551684411 100644 (file)
@@ -567,7 +567,7 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
                goto out;
        }
 
-       if (args->nr_local > (u64)UINT_MAX) {
+       if (args->nr_local > UIO_MAXIOV) {
                ret = -EMSGSIZE;
                goto out;
        }
index 08a8c6cf2d100f8f05a6c932d8190326277747e9..8e0a32001c90c531a2ad8361dc4bb0c399b812fe 100644 (file)
@@ -221,7 +221,13 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_tcp_conn_free(void *arg)
 {
        struct rds_tcp_connection *tc = arg;
+       unsigned long flags;
        rdsdebug("freeing tc %p\n", tc);
+
+       spin_lock_irqsave(&rds_tcp_conn_lock, flags);
+       list_del(&tc->t_tcp_node);
+       spin_unlock_irqrestore(&rds_tcp_conn_lock, flags);
+
        kmem_cache_free(rds_tcp_conn_slab, tc);
 }
 
index efd4f95fd0507d1d114db3683805cf08a61762f7..f23d9155b1efc94cdf7a2d2a65b7abcfc6ec0a77 100644 (file)
@@ -268,6 +268,10 @@ static int basic_dump(struct tcf_proto *tp, unsigned long fh,
                goto nla_put_failure;
 
        nla_nest_end(skb, nest);
+
+       if (tcf_exts_dump_stats(skb, &f->exts, &basic_ext_map) < 0)
+               goto nla_put_failure;
+
        return skb->len;
 
 nla_put_failure:
index 37dff78e9cb17c6fcf35e5302d57b84dd5e9f5f9..d49c40fb7e0960daa905353e714e9317dd38088b 100644 (file)
@@ -34,8 +34,6 @@ struct cgroup_subsys net_cls_subsys = {
        .populate       = cgrp_populate,
 #ifdef CONFIG_NET_CLS_CGROUP
        .subsys_id      = net_cls_subsys_id,
-#else
-#define net_cls_subsys_id net_cls_subsys.subsys_id
 #endif
        .module         = THIS_MODULE,
 };
index 763253257411af1db91b3e25a78af8e687523342..ea8f566e720c7bd9ed508647c080c5c554edba2b 100644 (file)
@@ -103,7 +103,8 @@ retry:
 
 static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
 {
-       textsearch_destroy(EM_TEXT_PRIV(m)->config);
+       if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config)
+               textsearch_destroy(EM_TEXT_PRIV(m)->config);
 }
 
 static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
index 1ef29c74d85ead34a6c0dd5cb03954e91677ae00..e58f9476f29c571cb516acd53516bdc46707a416 100644 (file)
@@ -92,7 +92,7 @@ static struct sctp_af *sctp_af_v6_specific;
 struct kmem_cache *sctp_chunk_cachep __read_mostly;
 struct kmem_cache *sctp_bucket_cachep __read_mostly;
 
-int sysctl_sctp_mem[3];
+long sysctl_sctp_mem[3];
 int sysctl_sctp_rmem[3];
 int sysctl_sctp_wmem[3];
 
index e34ca9cc11675e249cd703ea58ba4fe2e5feeb82..6bd554323a342d4db49be267766b87492bd2e584 100644 (file)
@@ -111,12 +111,12 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
 static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
 
 extern struct kmem_cache *sctp_bucket_cachep;
-extern int sysctl_sctp_mem[3];
+extern long sysctl_sctp_mem[3];
 extern int sysctl_sctp_rmem[3];
 extern int sysctl_sctp_wmem[3];
 
 static int sctp_memory_pressure;
-static atomic_t sctp_memory_allocated;
+static atomic_long_t sctp_memory_allocated;
 struct percpu_counter sctp_sockets_allocated;
 
 static void sctp_enter_memory_pressure(struct sock *sk)
index 832590bbe0c046ec83fcb58af7c98605fefec342..50cb57f0919e780bed02f6f963e62faf6d13144e 100644 (file)
@@ -54,7 +54,7 @@ static int sack_timer_max = 500;
 static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */
 static int rwnd_scale_max = 16;
 
-extern int sysctl_sctp_mem[3];
+extern long sysctl_sctp_mem[3];
 extern int sysctl_sctp_rmem[3];
 extern int sysctl_sctp_wmem[3];
 
@@ -203,7 +203,7 @@ static ctl_table sctp_table[] = {
                .data           = &sysctl_sctp_mem,
                .maxlen         = sizeof(sysctl_sctp_mem),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_doulongvec_minmax
        },
        {
                .procname       = "sctp_rmem",
index f71a73107ae94adeae35303f95f0b3409aee9e07..80df89d957ba02dce1b977ec19f96b51d2c657b0 100644 (file)
@@ -115,9 +115,7 @@ EXPORT_SYMBOL_GPL(svc_seq_show);
  */
 struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
 {
-       struct rpc_iostats *new;
-       new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
-       return new;
+       return kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
 
index c82fe739fbdcc685fae1e59f1fdb7c9e5afd30b0..ea2ff78dcf7b7ec4f2555210af82379017e6e291 100644 (file)
@@ -5,7 +5,6 @@
  */
 
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
index 33217fc3d697436cc5a82643a9d1fecb0986aac0..e9f0d500448341e0981fbb742b9fa098dc83a8ce 100644 (file)
@@ -396,6 +396,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
        struct tipc_sock *tsock = tipc_sk(sock->sk);
 
+       memset(addr, 0, sizeof(*addr));
        if (peer) {
                if ((sock->state != SS_CONNECTED) &&
                        ((peer != 2) || (sock->state != SS_DISCONNECTING)))
index d0c92dddb26bddb5b3d55a82ebf39fa8917e446c..17cd0c04d139045bbb0802a74d9628731d9428dc 100644 (file)
@@ -44,6 +44,38 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
        return chan;
 }
 
+static bool can_beacon_sec_chan(struct wiphy *wiphy,
+                               struct ieee80211_channel *chan,
+                               enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_channel *sec_chan;
+       int diff;
+
+       switch (channel_type) {
+       case NL80211_CHAN_HT40PLUS:
+               diff = 20;
+               break;
+       case NL80211_CHAN_HT40MINUS:
+               diff = -20;
+               break;
+       default:
+               return false;
+       }
+
+       sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
+       if (!sec_chan)
+               return false;
+
+       /* we'll need a DFS capability later */
+       if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
+                              IEEE80211_CHAN_PASSIVE_SCAN |
+                              IEEE80211_CHAN_NO_IBSS |
+                              IEEE80211_CHAN_RADAR))
+               return false;
+
+       return true;
+}
+
 int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
                      struct wireless_dev *wdev, int freq,
                      enum nl80211_channel_type channel_type)
@@ -68,6 +100,28 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
        if (!chan)
                return -EINVAL;
 
+       /* Both channels should be able to initiate communication */
+       if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
+                    wdev->iftype == NL80211_IFTYPE_AP ||
+                    wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
+                    wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+                    wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
+               switch (channel_type) {
+               case NL80211_CHAN_HT40PLUS:
+               case NL80211_CHAN_HT40MINUS:
+                       if (!can_beacon_sec_chan(&rdev->wiphy, chan,
+                                                channel_type)) {
+                               printk(KERN_DEBUG
+                                      "cfg80211: Secondary channel not "
+                                      "allowed to initiate communication\n");
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
        result = rdev->ops->set_channel(&rdev->wiphy,
                                        wdev ? wdev->netdev : NULL,
                                        chan, channel_type);
index c506241f863706426e76d66736d0258eda34d769..4e78e3f26798378bad69630679565b1909bfb370 100644 (file)
@@ -224,8 +224,8 @@ static int nl80211_prepare_netdev_dump(struct sk_buff *skb,
        }
 
        *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
+       if (IS_ERR(*rdev)) {
+               err = PTR_ERR(*rdev);
                goto out_rtnl;
        }
 
index 771bab00754b0baff1a5c7a95892028857c8b84d..55187c8f64209c8c096fac54c88e7771834cbe3f 100644 (file)
@@ -61,6 +61,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
        while (len > 0) {
                switch (*p & X25_FAC_CLASS_MASK) {
                case X25_FAC_CLASS_A:
+                       if (len < 2)
+                               return 0;
                        switch (*p) {
                        case X25_FAC_REVERSE:
                                if((p[1] & 0x81) == 0x81) {
@@ -104,6 +106,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        len -= 2;
                        break;
                case X25_FAC_CLASS_B:
+                       if (len < 3)
+                               return 0;
                        switch (*p) {
                        case X25_FAC_PACKET_SIZE:
                                facilities->pacsize_in  = p[1];
@@ -125,6 +129,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        len -= 3;
                        break;
                case X25_FAC_CLASS_C:
+                       if (len < 4)
+                               return 0;
                        printk(KERN_DEBUG "X.25: unknown facility %02X, "
                               "values %02X, %02X, %02X\n",
                               p[0], p[1], p[2], p[3]);
@@ -132,26 +138,26 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        len -= 4;
                        break;
                case X25_FAC_CLASS_D:
+                       if (len < p[1] + 2)
+                               return 0;
                        switch (*p) {
                        case X25_FAC_CALLING_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->calling_len = p[2];
                                memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLING_AE;
                                break;
                        case X25_FAC_CALLED_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->called_len = p[2];
                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLED_AE;
                                break;
                        default:
                                printk(KERN_DEBUG "X.25: unknown facility %02X,"
-                                       "length %d, values %02X, %02X, "
-                                       "%02X, %02X\n",
-                                       p[0], p[1], p[2], p[3], p[4], p[5]);
+                                       "length %d\n", p[0], p[1]);
                                break;
                        }
                        len -= p[1] + 2;
index 63178961efac00488d36e7c8fc3d21f00e036e2e..f729f022be69bc8c32b1008e8943c92cf36c1e28 100644 (file)
@@ -119,6 +119,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                                &x25->vc_facil_mask);
                        if (len > 0)
                                skb_pull(skb, len);
+                       else
+                               return -1;
                        /*
                         *      Copy any Call User Data.
                         */
index a2023ec52329ef66b95e14dc94f7086e5683e534..1e98bc0fe0a54bbca2a7fc1f94ab9344af0fbded 100644 (file)
@@ -19,7 +19,7 @@ struct hlist_head *xfrm_hash_alloc(unsigned int sz)
        if (sz <= PAGE_SIZE)
                n = kzalloc(sz, GFP_KERNEL);
        else if (hashdist)
-               n = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               n = vzalloc(sz);
        else
                n = (struct hlist_head *)
                        __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
index c0efe102d655c40547afe92014cec1c74b70b3c2..af6e9f3de9503b033a69a3eba7c2ecd212fef747 100644 (file)
@@ -875,7 +875,7 @@ const char *sym_expand_string_value(const char *in)
                        symval = sym_get_string_value(sym);
                }
 
-               newlen = strlen(res) + strlen(symval) + strlen(src);
+               newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
                if (newlen > reslen) {
                        reslen = newlen;
                        res = realloc(res, reslen);
index cdb6dc1f6458ba4634c0f8584ae3da615ce10696..39580a5dc5df6083a5766ae8853c6610e417474f 100755 (executable)
@@ -5,7 +5,7 @@ use strict;
 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
 ## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
 ## Copyright (C) 2001  Simon Huggins                             ##
-## Copyright (C) 2005-2009  Randy Dunlap                         ##
+## Copyright (C) 2005-2010  Randy Dunlap                         ##
 ##                                                              ##
 ## #define enhancements by Armin Kuster <akuster@mvista.com>    ##
 ## Copyright (c) 2000 MontaVista Software, Inc.                         ##
@@ -453,7 +453,7 @@ sub output_highlight {
     if ($output_mode eq "html" || $output_mode eq "xml") {
        $contents = local_unescape($contents);
        # convert data read & converted thru xml_escape() into &xyz; format:
-       $contents =~ s/\\\\\\/&/g;
+       $contents =~ s/\\\\\\/\&/g;
     }
 #   print STDERR "contents b4:$contents\n";
     eval $dohighlight;
@@ -770,7 +770,11 @@ sub output_struct_xml(%) {
     print $args{'type'} . " " . $args{'struct'} . " {\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
        if ($parameter =~ /^#/) {
-           print "$parameter\n";
+           my $prm = $parameter;
+           # convert data read & converted thru xml_escape() into &xyz; format:
+           # This allows us to have #define macros interspersed in a struct.
+           $prm =~ s/\\\\\\/\&/g;
+           print "$prm\n";
            next;
        }
 
@@ -1701,6 +1705,8 @@ sub push_parameter($$$) {
        }
        }
 
+       $param = xml_escape($param);
+
        # strip spaces from $param so that it is one continous string
        # on @parameterlist;
        # this fixes a problem where check_sections() cannot find
index bd72ae6234947e424885f3808dbec54bddad244c..e80da955e6876aeb550bec75d3d99643020034eb 100644 (file)
@@ -39,6 +39,18 @@ config KEYS_DEBUG_PROC_KEYS
 
          If you are unsure as to whether this is required, answer N.
 
+config SECURITY_DMESG_RESTRICT
+       bool "Restrict unprivileged access to the kernel syslog"
+       default n
+       help
+         This enforces restrictions on unprivileged users reading the kernel
+         syslog via dmesg(8).
+
+         If this option is not selected, no restrictions will be enforced
+         unless the dmesg_restrict sysctl is explicitly set to (1).
+
+         If you are unsure how to answer this question, answer N.
+
 config SECURITY
        bool "Enable different security models"
        depends on SYSFS
index cf1de4462ccd3fb297f48bf351dd3494804f22c1..b7106f192b75d5d382e806d303a9b2f6bb879747 100644 (file)
@@ -922,7 +922,7 @@ static int __init apparmor_init(void)
        error = register_security(&apparmor_ops);
        if (error) {
                AA_ERROR("Unable to register AppArmor\n");
-               goto register_security_out;
+               goto set_init_cxt_out;
        }
 
        /* Report that AppArmor successfully initialized */
@@ -936,6 +936,9 @@ static int __init apparmor_init(void)
 
        return error;
 
+set_init_cxt_out:
+       aa_free_task_context(current->real_cred->security);
+
 register_security_out:
        aa_free_root_ns();
 
@@ -944,7 +947,6 @@ alloc_out:
 
        apparmor_enabled = 0;
        return error;
-
 }
 
 security_initcall(apparmor_init);
index 52cc865f1464574e696fd28eca6a6e0eed326d68..4f0eadee78b8d9295f0da93c32a7321a70055392 100644 (file)
@@ -306,7 +306,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix,
        return ns;
 
 fail_unconfined:
-       kzfree(ns->base.name);
+       kzfree(ns->base.hname);
 fail_ns:
        kzfree(ns);
        return NULL;
index 30ae00fbecd591591acb55c1431d62a1bbbac427..c773635ca3a0e1b6de3e03d46fe38dd928a62a45 100644 (file)
@@ -17,6 +17,11 @@ static int cap_sysctl(ctl_table *table, int op)
        return 0;
 }
 
+static int cap_syslog(int type)
+{
+       return 0;
+}
+
 static int cap_quotactl(int cmds, int type, int id, struct super_block *sb)
 {
        return 0;
index 5e632b4857e443d8031eaa17c0e2bd7e877b3d14..64c2ed9c90158d1b7df59eff08595566d3dc1927 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/sched.h>
 #include <linux/prctl.h>
 #include <linux/securebits.h>
-#include <linux/syslog.h>
 
 /*
  * If a non-root user executes a setuid-root binary in
@@ -883,24 +882,6 @@ error:
        return error;
 }
 
-/**
- * cap_syslog - Determine whether syslog function is permitted
- * @type: Function requested
- * @from_file: Whether this request came from an open file (i.e. /proc)
- *
- * Determine whether the current process is permitted to use a particular
- * syslog function, returning 0 if permission is granted, -ve if not.
- */
-int cap_syslog(int type, bool from_file)
-{
-       if (type != SYSLOG_ACTION_OPEN && from_file)
-               return 0;
-       if ((type != SYSLOG_ACTION_READ_ALL &&
-            type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       return 0;
-}
-
 /**
  * cap_vm_enough_memory - Determine whether a new virtual mapping is permitted
  * @mm: The VM space in which the new mapping is to be made
index 3ef5e2a7a741aca4b13cd08b571e0a0ca0ee7d72..1b798d3df71057720d799f5d3e1382880fde8f78 100644 (file)
@@ -197,9 +197,9 @@ int security_quota_on(struct dentry *dentry)
        return security_ops->quota_on(dentry);
 }
 
-int security_syslog(int type, bool from_file)
+int security_syslog(int type)
 {
-       return security_ops->syslog(type, from_file);
+       return security_ops->syslog(type);
 }
 
 int security_settime(struct timespec *ts, struct timezone *tz)
index d9154cf90ae19cd4eb5f40d65882abb60781da3d..65fa8bf596f591d12c2e0c22bafe5824522c34ee 100644 (file)
@@ -1973,14 +1973,10 @@ static int selinux_quota_on(struct dentry *dentry)
        return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
 }
 
-static int selinux_syslog(int type, bool from_file)
+static int selinux_syslog(int type)
 {
        int rc;
 
-       rc = cap_syslog(type, from_file);
-       if (rc)
-               return rc;
-
        switch (type) {
        case SYSLOG_ACTION_READ_ALL:    /* Read last kernel messages */
        case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
index bc39f4067af668874312af4187ad6f21dbdbb113..489a85afa477bbd4d833fb167b3c6e71be049d86 100644 (file)
@@ -157,15 +157,11 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
  *
  * Returns 0 on success, error code otherwise.
  */
-static int smack_syslog(int type, bool from_file)
+static int smack_syslog(int typefrom_file)
 {
-       int rc;
+       int rc = 0;
        char *sp = current_security();
 
-       rc = cap_syslog(type, from_file);
-       if (rc != 0)
-               return rc;
-
        if (capable(CAP_MAC_OVERRIDE))
                return 0;
 
index f2f41c8542211143cc56e83328092d1bcb27a2bf..6e24091818950edc9c298241be2d28a751b39f83 100644 (file)
@@ -420,9 +420,9 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev)
                return PTR_ERR(pclk);
        }
        sample_clk = clk_get(&pdev->dev, "sample_clk");
-       if (IS_ERR(pclk)) {
+       if (IS_ERR(sample_clk)) {
                dev_dbg(&pdev->dev, "no sample clock\n");
-               retval = PTR_ERR(pclk);
+               retval = PTR_ERR(sample_clk);
                goto out_put_pclk;
        }
        clk_enable(pclk);
index b70564ed8b37821aa0f336d3585acf58da5854e3..7077f601da5a66a279bed9be77159f2ec80dfc78 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <sound/core.h>
 #include <sound/minors.h>
index a1707cca9c6635c8b4cd7e79b5cebe21bffc2d9e..b75db8e9cc0f36fff03d0ecf1884b23b3bad724b 100644 (file)
@@ -223,7 +223,7 @@ static void xrun_log(struct snd_pcm_substream *substream,
        entry->jiffies = jiffies;
        entry->pos = pos;
        entry->period_size = runtime->period_size;
-       entry->buffer_size = runtime->buffer_size;;
+       entry->buffer_size = runtime->buffer_size;
        entry->old_hw_ptr = runtime->status->hw_ptr;
        entry->hw_ptr_base = runtime->hw_ptr_base;
        log->idx = (log->idx + 1) % XRUN_LOG_CNT;
index 8bc7cb3db33056abce9a03cec36a4266305aa12c..e82c1f97d99e9736b20523f7bf6eca63498f2587 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/pm_qos_params.h>
 #include <linux/uio.h>
index 62a093efb453cc5d9657e4a3ce822ce42ca07748..66691fe437e63315fad4a1af8c073e9fbba058e5 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
index 727bdb9ba2dc1bc9b0cc62fd8abde19403ca292d..d8cf3e58dc76aa1017ef5b9424e862e95498ee6d 100644 (file)
@@ -71,7 +71,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
        if (sound_nblocks >= MAX_MEM_BLOCKS)
                sound_nblocks = MAX_MEM_BLOCKS - 1;
 
-       op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
+       op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations)));
        sound_nblocks++;
        if (sound_nblocks >= MAX_MEM_BLOCKS)
                sound_nblocks = MAX_MEM_BLOCKS - 1;
@@ -81,7 +81,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
                sound_unload_audiodev(num);
                return -(ENOMEM);
        }
-       memset((char *) op, 0, sizeof(struct audio_operations));
        init_waitqueue_head(&op->in_sleeper);
        init_waitqueue_head(&op->out_sleeper);  
        init_waitqueue_head(&op->poll_sleeper);
@@ -128,7 +127,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
        /* FIXME: This leaks a mixer_operations struct every time its called
           until you unload sound! */
           
-       op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
+       op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations)));
        sound_nblocks++;
        if (sound_nblocks >= MAX_MEM_BLOCKS)
                sound_nblocks = MAX_MEM_BLOCKS - 1;
@@ -137,7 +136,6 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
                printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
                return -ENOMEM;
        }
-       memset((char *) op, 0, sizeof(struct mixer_operations));
        memcpy((char *) op, (char *) driver, driver_size);
 
        strlcpy(op->name, name, sizeof(op->name));
index 782b3b84dac68ccd036c52ee3533336f243ac15b..ceedb1eff203812e85049f7cdb46b92a588fc557 100644 (file)
@@ -178,7 +178,7 @@ int MIDIbuf_open(int dev, struct file *file)
                return err;
 
        parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
-       midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
+       midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
 
        if (midi_in_buf[dev] == NULL)
        {
@@ -188,7 +188,7 @@ int MIDIbuf_open(int dev, struct file *file)
        }
        midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
 
-       midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
+       midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
 
        if (midi_out_buf[dev] == NULL)
        {
index e19dd5dcc2debd9e3b4a7fa9ec481849f8442a30..9b800ce5100ef286864234b308fb646c7d5dc9a1 100644 (file)
@@ -859,7 +859,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
                        return 0;
 
                case SNDCTL_COPR_LOAD:
-                       buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+                       buf = vmalloc(sizeof(copr_buffer));
                        if (buf == NULL)
                                return -ENOSPC;
                        if (copy_from_user(buf, arg, sizeof(copr_buffer))) {
@@ -871,7 +871,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
                        return err;
                
                case SNDCTL_COPR_SENDMSG:
-                       mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+                       mbuf = vmalloc(sizeof(copr_msg));
                        if (mbuf == NULL)
                                return -ENOSPC;
                        if (copy_from_user(mbuf, arg, sizeof(copr_msg))) {
@@ -895,7 +895,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
 
                case SNDCTL_COPR_RCVMSG:
                        err = 0;
-                       mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+                       mbuf = vmalloc(sizeof(copr_msg));
                        if (mbuf == NULL)
                                return -ENOSPC;
                        data = (unsigned short *)mbuf->data;
index e85789e53816640f8e7e7224fdd0199787e5f4de..5ea1098ac427a5546bdf9f211587bbe8030d1821 100644 (file)
@@ -1646,13 +1646,13 @@ void sequencer_init(void)
 {
        if (sequencer_ok)
                return;
-       queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
+       queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ);
        if (queue == NULL)
        {
                printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
                return;
        }
-       iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
+       iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
        if (iqueue == NULL)
        {
                printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n");
index f7e374ec44144763feb215890c73714b32a17a22..1b9bf9395cfe820f87b34fa14d57d5a667a67217 100644 (file)
@@ -625,6 +625,8 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
                        control_cache_size, (struct hpi_control_cache_info *)
                        &phw->control_cache[0]
                        );
+               if (!phw->p_cache)
+                       pao->has_control_cache = 0;
        } else
                pao->has_control_cache = 0;
 
index 22c5fc6255335ac94aca5ac297432f16b0950c4e..2672f6591ceb7246b9a0a24ecbfa8f4cf2c46288 100644 (file)
@@ -644,6 +644,8 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                                interface->control_cache.size_in_bytes,
                                (struct hpi_control_cache_info *)
                                p_control_cache_virtual);
+                       if (!phw->p_cache)
+                               err = HPI_ERROR_MEMORY_ALLOC;
                }
                if (!err) {
                        err = hpios_locked_mem_get_phys_addr(&phw->
index dda4f1c6f65847504a71016b1064d0039c65e8a3..d67f4d3db911dd9685d24e08f29d6b6bc23f16f9 100644 (file)
@@ -571,14 +571,20 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32
 {
        struct hpi_control_cache *p_cache =
                kmalloc(sizeof(*p_cache), GFP_KERNEL);
+       if (!p_cache)
+               return NULL;
+       p_cache->p_info =
+               kmalloc(sizeof(*p_cache->p_info) * number_of_controls,
+                       GFP_KERNEL);
+       if (!p_cache->p_info) {
+               kfree(p_cache);
+               return NULL;
+       }
        p_cache->cache_size_in_bytes = size_in_bytes;
        p_cache->control_count = number_of_controls;
        p_cache->p_cache =
                (struct hpi_control_cache_single *)pDSP_control_buffer;
        p_cache->init = 0;
-       p_cache->p_info =
-               kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count,
-               GFP_KERNEL);
        return p_cache;
 }
 
index 62895a719fcbcce841b05f44fce0a90813d70477..22dbd91811a4e61398a9b9077c5cbe26c0139119 100644 (file)
@@ -435,7 +435,7 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
        struct hpi_message hm;
        struct hpi_response hr;
        struct hpi_adapter *pa;
-       pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev);
+       pa = pci_get_drvdata(pci_dev);
 
        hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
                HPI_SUBSYS_DELETE_ADAPTER);
index 4679ed83a43b8687402b7efca98ed47a0518ac98..2f3cacbd5528da80cccca5791147d6f516dcdf82 100644 (file)
@@ -1129,10 +1129,11 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
 
                count_areas = size/2;
                addr_area2 = addr+count_areas;
-               count_areas--; /* max. index */
                snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
                                addr, count_areas, addr_area2, count_areas);
 
+               count_areas--; /* max. index */
+
                /* build combined I/O buffer length word */
                lengths = (count_areas << 16) | (count_areas);
                spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1740,11 +1741,15 @@ static const struct snd_pcm_hardware snd_azf3328_hardware =
        .rate_max =             AZF_FREQ_66200,
        .channels_min =         1,
        .channels_max =         2,
-       .buffer_bytes_max =     65536,
-       .period_bytes_min =     64,
-       .period_bytes_max =     65536,
-       .periods_min =          1,
-       .periods_max =          1024,
+       .buffer_bytes_max =     (64*1024),
+       .period_bytes_min =     1024,
+       .period_bytes_max =     (32*1024),
+       /* We simply have two DMA areas (instead of a list of descriptors
+          such as other cards); I believe that this is a fixed hardware
+          attribute and there isn't much driver magic to be done to expand it.
+          Thus indicate that we have at least and at most 2 periods. */
+       .periods_min =          2,
+       .periods_max =          2,
        /* FIXME: maybe that card actually has a FIFO?
         * Hmm, it seems newer revisions do have one, but we still don't know
         * its size... */
@@ -1980,8 +1985,13 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
        chip = snd_timer_chip(timer);
        spin_lock_irqsave(&chip->reg_lock, flags);
        /* disable timer countdown and interrupt */
-       /* FIXME: should we write TIMER_IRQ_ACK here? */
-       snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);
+       /* Hmm, should we write TIMER_IRQ_ACK here?
+          YES indeed, otherwise a rogue timer operation - which prompts
+          ALSA(?) to call repeated stop() in vain, but NOT start() -
+          will never end (value 0x03 is kept shown in control byte).
+          Simply manually poking 0x04 _once_ immediately successfully stops
+          the hardware/ALSA interrupt activity. */
+       snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        snd_azf3328_dbgcallleave();
        return 0;
index 3e5ca8fb519ff1ae5d2c03cf7f2beb8700b1745d..e377287192aae954aa42d153cb9931f0934f67b4 100644 (file)
@@ -225,39 +225,25 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 {
        struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL);
 
-       if (ins == NULL) 
+       if (ins == NULL)
                return NULL;
 
        /* better to use vmalloc for this big table */
-       ins->symbol_table.nsymbols = 0;
        ins->symbol_table.symbols = vmalloc(sizeof(struct dsp_symbol_entry) *
                                            DSP_MAX_SYMBOLS);
-       ins->symbol_table.highest_frag_index = 0;
-
-       if (ins->symbol_table.symbols == NULL) {
+       ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
+       ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL);
+       if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) {
                cs46xx_dsp_spos_destroy(chip);
                goto error;
        }
-
+       ins->symbol_table.nsymbols = 0;
+       ins->symbol_table.highest_frag_index = 0;
        ins->code.offset = 0;
        ins->code.size = 0;
-       ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
-
-       if (ins->code.data == NULL) {
-               cs46xx_dsp_spos_destroy(chip);
-               goto error;
-       }
-
        ins->nscb = 0;
        ins->ntask = 0;
-
        ins->nmodules = 0;
-       ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL);
-
-       if (ins->modules == NULL) {
-               cs46xx_dsp_spos_destroy(chip);
-               goto error;
-       }
 
        /* default SPDIF input sample rate
           to 48000 khz */
@@ -271,8 +257,8 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 
        /* set left and right validity bits and
           default channel status */
-       ins->spdif_csuv_default = 
-               ins->spdif_csuv_stream =  
+       ins->spdif_csuv_default =
+               ins->spdif_csuv_stream =
         /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
         /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
         /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
@@ -281,6 +267,9 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
        return ins;
 
 error:
+       kfree(ins->modules);
+       kfree(ins->code.data);
+       vfree(ins->symbol_table.symbols);
        kfree(ins);
        return NULL;
 }
index 85ab43e89212c6724c1e70f3cad3de33e9816935..457d21189b0db1fc5b2fcd2af22e30d20089dcb1 100644 (file)
@@ -129,8 +129,6 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
 
        apcm->substream = substream;
        apcm->interrupt = ct_atc_pcm_interrupt;
-       runtime->private_data = apcm;
-       runtime->private_free = ct_atc_pcm_free_substream;
        if (IEC958 == substream->pcm->device) {
                runtime->hw = ct_spdif_passthru_playback_hw;
                atc->spdif_out_passthru(atc, 1);
@@ -155,8 +153,12 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
        }
 
        apcm->timer = ct_timer_instance_new(atc->timer, apcm);
-       if (!apcm->timer)
+       if (!apcm->timer) {
+               kfree(apcm);
                return -ENOMEM;
+       }
+       runtime->private_data = apcm;
+       runtime->private_free = ct_atc_pcm_free_substream;
 
        return 0;
 }
@@ -278,8 +280,6 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
        apcm->started = 0;
        apcm->substream = substream;
        apcm->interrupt = ct_atc_pcm_interrupt;
-       runtime->private_data = apcm;
-       runtime->private_free = ct_atc_pcm_free_substream;
        runtime->hw = ct_pcm_capture_hw;
        runtime->hw.rate_max = atc->rsr * atc->msr;
 
@@ -298,8 +298,12 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
        }
 
        apcm->timer = ct_timer_instance_new(atc->timer, apcm);
-       if (!apcm->timer)
+       if (!apcm->timer) {
+               kfree(apcm);
                return -ENOMEM;
+       }
+       runtime->private_data = apcm;
+       runtime->private_free = ct_atc_pcm_free_substream;
 
        return 0;
 }
index 460fb2ef7e394614a4045a51d4306c429e818d6a..18af38ebf7579f5507fca391f66ba9280844ccf4 100644 (file)
@@ -1166,6 +1166,7 @@ static const char *cs420x_models[CS420X_MODELS] = {
 
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
+       SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
        SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
index 6361f752b5f35cfddff7f8423f0d5d185a9003d8..846d1ead47fdf1c184fb92f37ae1faf099ec45af 100644 (file)
@@ -3100,6 +3100,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
+       SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
@@ -3110,6 +3111,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD),
index 5f00589cb791aebed2d7aa1f0bd908819b9123b8..886d7c72936e9e2959042306c79d24383a8176a3 100644 (file)
@@ -1614,6 +1614,7 @@ do_sku:
                spec->init_amp = ALC_INIT_GPIO3;
                break;
        case 5:
+       default:
                spec->init_amp = ALC_INIT_DEFAULT;
                break;
        }
@@ -2013,6 +2014,36 @@ static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
        { }
 };
 
+/*
+ *ALC888 Acer Aspire 7730G model
+ */
+
+static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+/* Bias voltage on for external mic port */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Enable speaker output */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/* Enable headphone output */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/*Enable internal subwoofer */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
 /*
  * ALC889 Acer Aspire 8930G model
  */
@@ -2200,6 +2231,16 @@ static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[2] = 0x17;
 }
 
+static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->autocfg.hp_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x14;
+       spec->autocfg.speaker_pins[1] = 0x16;
+       spec->autocfg.speaker_pins[2] = 0x17;
+}
+
 static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -9524,13 +9565,6 @@ static struct hda_verb alc883_acer_eapd_verbs[] = {
        { }
 };
 
-static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
 static void alc888_6st_dell_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -10328,7 +10362,7 @@ static struct alc_config_preset alc882_presets[] = {
                .const_channel_count = 6,
                .input_mux = &alc883_capture_source,
                .unsol_event = alc_automute_amp_unsol_event,
-               .setup = alc888_acer_aspire_6530g_setup,
+               .setup = alc888_acer_aspire_7730g_setup,
                .init_hook = alc_automute_amp,
        },
        [ALC883_MEDION] = {
@@ -14623,7 +14657,10 @@ static int alc275_setup_dual_adc(struct hda_codec *codec)
 /* different alc269-variants */
 enum {
        ALC269_TYPE_NORMAL,
+       ALC269_TYPE_ALC258,
        ALC269_TYPE_ALC259,
+       ALC269_TYPE_ALC269VB,
+       ALC269_TYPE_ALC270,
        ALC269_TYPE_ALC271X,
 };
 
@@ -15023,7 +15060,7 @@ static int alc269_fill_coef(struct hda_codec *codec)
 static int patch_alc269(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int board_config;
+       int board_config, coef;
        int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -15034,14 +15071,23 @@ static int patch_alc269(struct hda_codec *codec)
 
        alc_auto_parse_customize_define(codec);
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
+       coef = alc_read_coef_idx(codec, 0);
+       if ((coef & 0x00f0) == 0x0010) {
                if (codec->bus->pci->subsystem_vendor == 0x1025 &&
                    spec->cdefine.platform_type == 1) {
                        alc_codec_rename(codec, "ALC271X");
                        spec->codec_variant = ALC269_TYPE_ALC271X;
-               } else {
+               } else if ((coef & 0xf000) == 0x1000) {
+                       spec->codec_variant = ALC269_TYPE_ALC270;
+               } else if ((coef & 0xf000) == 0x2000) {
                        alc_codec_rename(codec, "ALC259");
                        spec->codec_variant = ALC269_TYPE_ALC259;
+               } else if ((coef & 0xf000) == 0x3000) {
+                       alc_codec_rename(codec, "ALC258");
+                       spec->codec_variant = ALC269_TYPE_ALC258;
+               } else {
+                       alc_codec_rename(codec, "ALC269VB");
+                       spec->codec_variant = ALC269_TYPE_ALC269VB;
                }
        } else
                alc_fix_pll_init(codec, 0x20, 0x04, 15);
@@ -15104,7 +15150,7 @@ static int patch_alc269(struct hda_codec *codec)
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
        if (!spec->adc_nids) { /* wasn't filled automatically? use default */
-               if (spec->codec_variant != ALC269_TYPE_NORMAL) {
+               if (spec->codec_variant == ALC269_TYPE_NORMAL) {
                        spec->adc_nids = alc269_adc_nids;
                        spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
                        spec->capsrc_nids = alc269_capsrc_nids;
@@ -16898,7 +16944,7 @@ static struct alc_config_preset alc861vd_presets[] = {
 static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
+       return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
 }
 
 
@@ -18952,6 +18998,8 @@ static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
                return 0x02;
        else if (nid >= 0x0c && nid <= 0x0e)
                return nid - 0x0c + 0x02;
+       else if (nid == 0x26) /* ALC887-VD has this DAC too */
+               return 0x25;
        else
                return 0;
 }
@@ -18960,7 +19008,7 @@ static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
 static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
                                   hda_nid_t dac)
 {
-       hda_nid_t mix[4];
+       hda_nid_t mix[5];
        int i, num;
 
        num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
@@ -19298,6 +19346,7 @@ static const struct alc_fixup alc662_fixups[] = {
 
 static struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
        {}
@@ -19419,7 +19468,10 @@ static int patch_alc888(struct hda_codec *codec)
 {
        if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
                kfree(codec->chip_name);
-               codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
+               if (codec->vendor_id == 0x10ec0887)
+                       codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
+               else
+                       codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
                if (!codec->chip_name) {
                        alc_free(codec);
                        return -ENOMEM;
@@ -19909,7 +19961,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
          .patch = patch_alc882 },
        { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
-       { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
+       { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
        { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
          .patch = patch_alc882 },
        { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
index 93fa59cc60ef9ba0f5b2315c6461d3966608994c..5c710807dfe588decaf764c29a618cd83711d3d8 100644 (file)
@@ -389,6 +389,11 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
        0x11, 0x20, 0
 };
 
+#define STAC92HD87B_NUM_DMICS   1
+static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
+       0x11, 0
+};
+
 #define STAC92HD83XXX_NUM_CAPS 2
 static unsigned long stac92hd83xxx_capvols[] = {
        HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -3486,10 +3491,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                                return err;
                }
 
-               if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
+               if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
                        snd_hda_add_imux_item(imux, label, index, NULL);
-                       spec->num_analog_muxes++;
-               }
        }
 
        return 0;
@@ -5452,12 +5455,17 @@ again:
                                stac92hd83xxx_brd_tbl[spec->board_config]);
 
        switch (codec->vendor_id) {
+       case 0x111d76d1:
+       case 0x111d76d9:
+               spec->dmic_nids = stac92hd87b_dmic_nids;
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd87b_dmic_nids,
+                               STAC92HD87B_NUM_DMICS);
+               /* Fall through */
        case 0x111d7666:
        case 0x111d7667:
        case 0x111d7668:
        case 0x111d7669:
-       case 0x111d76d1:
-       case 0x111d76d9:
                spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
                spec->pin_nids = stac92hd88xxx_pin_nids;
                spec->mono_nid = 0;
index 400f9ebd243e84ebf595cb4cba69f6a3cb3552b7..629a5494347a021600ed6f2dbf82feb5971d10ac 100644 (file)
@@ -1864,6 +1864,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .name = "Dell Inspiron 8600",   /* STAC9750/51 */
                .type = AC97_TUNE_HP_ONLY
        },
+       {
+               .subvendor = 0x1028,
+               .subdevice = 0x0182,
+               .name = "Dell Latitude D610",   /* STAC9750/51 */
+               .type = AC97_TUNE_HP_ONLY
+       },
        {
                .subvendor = 0x1028,
                .subdevice = 0x0186,
index ef9af3f4ace2f6fda837a89e4ea46ff8821fd86c..1bd7a540fd49dfa64918e4d533a3d80cbb8fb4af 100644 (file)
@@ -425,7 +425,7 @@ exit:
 static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 {
        struct snd_pcm_substream *substream = lx_stream->stream;
-       const int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
 
        int err;
 
@@ -473,7 +473,7 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 
 static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
 {
-       const int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
        int err;
 
        snd_printd(LXP "stopping: stopping stream\n");
index 51afc048961d9855c39e321e523f9f526bd8acd3..aea621eafbb56799385e0e2188a5b3e1130f21d2 100644 (file)
@@ -60,7 +60,7 @@ struct lx_stream {
        snd_pcm_uframes_t          frame_pos;
        enum lx_stream_status      status; /* free, open, running, draining
                                            * pause */
-       int                        is_capture:1;
+       unsigned int               is_capture:1;
 };
 
 
index 3086b751da4a59271b497e1a8605c3664d15a2ff..617f98b0cbae47ce9c76265f50590f88a83c187d 100644 (file)
@@ -1152,7 +1152,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
                                           struct lx_stream *lx_stream)
 {
        struct snd_pcm_substream *substream = lx_stream->stream;
-       int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
        int err;
        unsigned long flags;
 
index a46f5083db99229c88797895b9de5170bede8245..812e288ef2e76eb58de27118a7522700f0f21a38 100644 (file)
 
 #include <sound/hwdep.h>
 
+#ifndef readl_be
 #define readl_be(x) be32_to_cpu(__raw_readl(x))
+#endif
+
+#ifndef writel_be
 #define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
+#endif
 
+#ifndef readl_le
 #define readl_le(x) le32_to_cpu(__raw_readl(x))
+#endif
+
+#ifndef writel_le
 #define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
+#endif
 
 #define MIXART_MEM(mgr,x)      ((mgr)->mem[0].virt + (x))
 #define MIXART_REG(mgr,x)      ((mgr)->mem[1].virt + (x))
index 85081172403f25ec056a99eb58a341fbd5d57370..b47cfd45b3b98f04b2c6d89135de310fb3b264ef 100644 (file)
@@ -1228,10 +1228,8 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
                                               chip->rsrc[i].start + 1,
                                               rnames[i]) == NULL) {
                                printk(KERN_ERR "snd: can't request rsrc "
-                                      " %d (%s: 0x%016llx:%016llx)\n",
-                                      i, rnames[i],
-                                      (unsigned long long)chip->rsrc[i].start,
-                                      (unsigned long long)chip->rsrc[i].end);
+                                      " %d (%s: %pR)\n",
+                                      i, rnames[i], &chip->rsrc[i]);
                                err = -ENODEV;
                                goto __error;
                        }
@@ -1256,10 +1254,8 @@ int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
                                               chip->rsrc[i].start + 1,
                                               rnames[i]) == NULL) {
                                printk(KERN_ERR "snd: can't request rsrc "
-                                      " %d (%s: 0x%016llx:%016llx)\n",
-                                      i, rnames[i],
-                                      (unsigned long long)chip->rsrc[i].start,
-                                      (unsigned long long)chip->rsrc[i].end);
+                                      " %d (%s: %pR)\n",
+                                      i, rnames[i], &chip->rsrc[i]);
                                err = -ENODEV;
                                goto __error;
                        }
index c03bbaefdbc36c623e3f5b76cea86f6ad59e46cc..5580aced87308202e00d181194a6d4aa6689b920 100644 (file)
@@ -104,7 +104,6 @@ module_exit(cleanup_soundcore);
 
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sound.h>
index 1bc56b2b94e29f9143baa9911f72fa962202d17a..337a00241a1f3a406506c4baad93e0f10a8ac7d8 100644 (file)
@@ -155,7 +155,7 @@ static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
        if (max_tries < 1)
                max_tries = 1;
 
-       /* ssc_div must be a power of 2. */
+       /* ssc_div must be even. */
        ssc_div = (ssc_div + 1) & ~1UL;
 
        if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) {
index 7dae05d8783e4274266bb5c867e534b342e18614..782f741cd00a4e3bb97317d05827f8c3134299bc 100644 (file)
@@ -60,7 +60,7 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
-       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi */
+       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
@@ -183,7 +183,13 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        if (value > 1)
                return -EINVAL;
        changed = value != mixer->audigy2nx_leds[index];
-       err = snd_usb_ctl_msg(mixer->chip->dev,
+       if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
+               err = snd_usb_ctl_msg(mixer->chip->dev,
+                             usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             !value, 0, NULL, 0, 100);
+       else
+               err = snd_usb_ctl_msg(mixer->chip->dev,
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
                              value, index + 2, NULL, 0, 100);
@@ -225,8 +231,12 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
        int i, err;
 
        for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+               /* USB X-Fi S51 doesn't have a CMSS LED */
+               if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
+                       continue;
                if (i > 1 && /* Live24ext has 2 LEDs only */
                        (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                        mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
                         mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
                        break; 
                err = snd_ctl_add(mixer->chip->card,
@@ -365,6 +375,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
                        return err;
index cff3a3c465d736f17d73a4cf6c01c54c936469c3..4132522ac90f8c88da831b68f9cbdf777131de8e 100644 (file)
@@ -676,8 +676,10 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
        if (!needs_knot)
                return 0;
 
-       subs->rate_list.count = count;
        subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+       if (!subs->rate_list.list)
+               return -ENOMEM;
+       subs->rate_list.count = count;
        subs->rate_list.mask = 0;
        count = 0;
        list_for_each_entry(fp, &subs->fmt_list, list) {
index 122ec9dc4853d079903d566a219a9e48d8a6a465..26aff6bf9e500d0d6699e968a789db651deb9722 100644 (file)
@@ -8,7 +8,11 @@ perf-trace - Read perf.data (created by perf record) and display trace output
 SYNOPSIS
 --------
 [verse]
-'perf trace' {record <script> | report <script> [args] }
+'perf trace' [<options>]
+'perf trace' [<options>] record <script> [<record-options>] <command>
+'perf trace' [<options>] report <script> [script-args]
+'perf trace' [<options>] <script> <required-script-args> [<record-options>] <command>
+'perf trace' [<options>] <top-script> [script-args]
 
 DESCRIPTION
 -----------
@@ -24,23 +28,53 @@ There are several variants of perf trace:
   available via 'perf trace -l').  The following variants allow you to
   record and run those scripts:
 
-  'perf trace record <script>' to record the events required for 'perf
-  trace report'.  <script> is the name displayed in the output of
-  'perf trace --list' i.e. the actual script name minus any language
-  extension.
+  'perf trace record <script> <command>' to record the events required
+  for 'perf trace report'.  <script> is the name displayed in the
+  output of 'perf trace --list' i.e. the actual script name minus any
+  language extension.  If <command> is not specified, the events are
+  recorded using the -a (system-wide) 'perf record' option.
 
-  'perf trace report <script>' to run and display the results of
-  <script>.  <script> is the name displayed in the output of 'perf
+  'perf trace report <script> [args]' to run and display the results
+  of <script>.  <script> is the name displayed in the output of 'perf
   trace --list' i.e. the actual script name minus any language
   extension.  The perf.data output from a previous run of 'perf trace
   record <script>' is used and should be present for this command to
-  succeed.
+  succeed.  [args] refers to the (mainly optional) args expected by
+  the script.
+
+  'perf trace <script> <required-script-args> <command>' to both
+  record the events required for <script> and to run the <script>
+  using 'live-mode' i.e. without writing anything to disk.  <script>
+  is the name displayed in the output of 'perf trace --list' i.e. the
+  actual script name minus any language extension.  If <command> is
+  not specified, the events are recorded using the -a (system-wide)
+  'perf record' option.  If <script> has any required args, they
+  should be specified before <command>.  This mode doesn't allow for
+  optional script args to be specified; if optional script args are
+  desired, they can be specified using separate 'perf trace record'
+  and 'perf trace report' commands, with the stdout of the record step
+  piped to the stdin of the report script, using the '-o -' and '-i -'
+  options of the corresponding commands.
+
+  'perf trace <top-script>' to both record the events required for
+  <top-script> and to run the <top-script> using 'live-mode'
+  i.e. without writing anything to disk.  <top-script> is the name
+  displayed in the output of 'perf trace --list' i.e. the actual
+  script name minus any language extension; a <top-script> is defined
+  as any script name ending with the string 'top'.
+
+  [<record-options>] can be passed to the record steps of 'perf trace
+  record' and 'live-mode' variants; this isn't possible however for
+  <top-script> 'live-mode' or 'perf trace report' variants.
 
   See the 'SEE ALSO' section for links to language-specific
   information on how to write and run your own trace scripts.
 
 OPTIONS
 -------
+<command>...::
+       Any command you can specify in a shell.
+
 -D::
 --dump-raw-trace=::
         Display verbose dump of the trace data.
@@ -64,6 +98,13 @@ OPTIONS
         Generate perf-trace.[ext] starter script for given language,
         using current perf.data.
 
+-a::
+        Force system-wide collection.  Scripts run without a <command>
+        normally use -a by default, while scripts run with a <command>
+        normally don't - this option allows the latter to be run in
+        system-wide mode.
+
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-trace-perl[1],
index 4e75583ddd6d9605b96256264c4e5ca900670d3e..93bd2ff001fb113ff11159e419269942ac4e3743 100644 (file)
@@ -790,7 +790,7 @@ static const char * const record_usage[] = {
 
 static bool force, append_file;
 
-static const struct option options[] = {
+const struct option record_options[] = {
        OPT_CALLBACK('e', "event", NULL, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events),
@@ -839,16 +839,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int i, j, err = -ENOMEM;
 
-       argc = parse_options(argc, argv, options, record_usage,
+       argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && target_tid == -1 &&
                !system_wide && !cpu_list)
-               usage_with_options(record_usage, options);
+               usage_with_options(record_usage, record_options);
 
        if (force && append_file) {
                fprintf(stderr, "Can't overwrite and append at the same time."
                                " You need to choose between -f and -A");
-               usage_with_options(record_usage, options);
+               usage_with_options(record_usage, record_options);
        } else if (append_file) {
                write_mode = WRITE_APPEND;
        } else {
@@ -871,7 +871,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                if (thread_num <= 0) {
                        fprintf(stderr, "Can't find all threads of pid %d\n",
                                        target_pid);
-                       usage_with_options(record_usage, options);
+                       usage_with_options(record_usage, record_options);
                }
        } else {
                all_tids=malloc(sizeof(pid_t));
index b513e40974f46bf45f816d658d78d574762f5b17..dd625808c2a5332c4f733a59acfb1ee881faae3f 100644 (file)
@@ -69,7 +69,6 @@ static int                    target_tid                      =     -1;
 static pid_t                   *all_tids                       =      NULL;
 static int                     thread_num                      =      0;
 static bool                    inherit                         =  false;
-static int                     profile_cpu                     =     -1;
 static int                     nr_cpus                         =      0;
 static int                     realtime_prio                   =      0;
 static bool                    group                           =  false;
@@ -558,13 +557,13 @@ static void print_sym_table(void)
        else
                printf(" (all");
 
-       if (profile_cpu != -1)
-               printf(", cpu: %d)\n", profile_cpu);
+       if (cpu_list)
+               printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list);
        else {
                if (target_tid != -1)
                        printf(")\n");
                else
-                       printf(", %d CPUs)\n", nr_cpus);
+                       printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : "");
        }
 
        printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
@@ -1187,11 +1186,10 @@ int group_fd;
 static void start_counter(int i, int counter)
 {
        struct perf_event_attr *attr;
-       int cpu;
+       int cpu = -1;
        int thread_index;
 
-       cpu = profile_cpu;
-       if (target_tid == -1 && profile_cpu == -1)
+       if (target_tid == -1)
                cpu = cpumap[i];
 
        attr = attrs + counter;
index 2f8df45c4dcbfe306080354dbfcfb073ac3ed0a0..86cfe3800e6bf5580718fd3df3c3788f9edbda31 100644 (file)
@@ -10,6 +10,7 @@
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/trace-event.h"
+#include "util/parse-options.h"
 #include "util/util.h"
 
 static char const              *script_name;
@@ -17,6 +18,7 @@ static char const             *generate_script_lang;
 static bool                    debug_mode;
 static u64                     last_timestamp;
 static u64                     nr_unordered;
+extern const struct option     record_options[];
 
 static int default_start_script(const char *script __unused,
                                int argc __unused,
@@ -328,7 +330,7 @@ static struct script_desc *script_desc__new(const char *name)
 {
        struct script_desc *s = zalloc(sizeof(*s));
 
-       if (s != NULL)
+       if (s != NULL && name)
                s->name = strdup(name);
 
        return s;
@@ -337,6 +339,8 @@ static struct script_desc *script_desc__new(const char *name)
 static void script_desc__delete(struct script_desc *s)
 {
        free(s->name);
+       free(s->half_liner);
+       free(s->args);
        free(s);
 }
 
@@ -537,8 +541,40 @@ static char *get_script_path(const char *script_root, const char *suffix)
        return path;
 }
 
+static bool is_top_script(const char *script_path)
+{
+       return ends_with((char *)script_path, "top") == NULL ? false : true;
+}
+
+static int has_required_arg(char *script_path)
+{
+       struct script_desc *desc;
+       int n_args = 0;
+       char *p;
+
+       desc = script_desc__new(NULL);
+
+       if (read_script_info(desc, script_path))
+               goto out;
+
+       if (!desc->args)
+               goto out;
+
+       for (p = desc->args; *p; p++)
+               if (*p == '<')
+                       n_args++;
+out:
+       script_desc__delete(desc);
+
+       return n_args;
+}
+
 static const char * const trace_usage[] = {
-       "perf trace [<options>] <command>",
+       "perf trace [<options>]",
+       "perf trace [<options>] record <script> [<record-options>] <command>",
+       "perf trace [<options>] report <script> [script-args]",
+       "perf trace [<options>] <script> [<record-options>] <command>",
+       "perf trace [<options>] <top-script> [script-args]",
        NULL
 };
 
@@ -564,50 +600,81 @@ static const struct option options[] = {
        OPT_END()
 };
 
+static bool have_cmd(int argc, const char **argv)
+{
+       char **__argv = malloc(sizeof(const char *) * argc);
+
+       if (!__argv)
+               die("malloc");
+       memcpy(__argv, argv, sizeof(const char *) * argc);
+       argc = parse_options(argc, (const char **)__argv, record_options,
+                            NULL, PARSE_OPT_STOP_AT_NON_OPTION);
+       free(__argv);
+
+       return argc != 0;
+}
+
 int cmd_trace(int argc, const char **argv, const char *prefix __used)
 {
+       char *rec_script_path = NULL;
+       char *rep_script_path = NULL;
        struct perf_session *session;
-       const char *suffix = NULL;
+       char *script_path = NULL;
        const char **__argv;
-       char *script_path;
-       int i, err;
+       bool system_wide;
+       int i, j, err;
 
-       if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
-               if (argc < 3) {
-                       fprintf(stderr,
-                               "Please specify a record script\n");
-                       return -1;
-               }
-               suffix = RECORD_SUFFIX;
+       setup_scripting();
+
+       argc = parse_options(argc, argv, options, trace_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
+               rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
+               if (!rec_script_path)
+                       return cmd_record(argc, argv, NULL);
        }
 
-       if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
-               if (argc < 3) {
+       if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
+               rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
+               if (!rep_script_path) {
                        fprintf(stderr,
-                               "Please specify a report script\n");
+                               "Please specify a valid report script"
+                               "(see 'perf trace -l' for listing)\n");
                        return -1;
                }
-               suffix = REPORT_SUFFIX;
        }
 
        /* make sure PERF_EXEC_PATH is set for scripts */
        perf_set_argv_exec_path(perf_exec_path());
 
-       if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) {
-               char *record_script_path, *report_script_path;
+       if (argc && !script_name && !rec_script_path && !rep_script_path) {
                int live_pipe[2];
+               int rep_args;
                pid_t pid;
 
-               record_script_path = get_script_path(argv[1], RECORD_SUFFIX);
-               if (!record_script_path) {
-                       fprintf(stderr, "record script not found\n");
-                       return -1;
+               rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
+               rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
+
+               if (!rec_script_path && !rep_script_path) {
+                       fprintf(stderr, " Couldn't find script %s\n\n See perf"
+                               " trace -l for available scripts.\n", argv[0]);
+                       usage_with_options(trace_usage, options);
                }
 
-               report_script_path = get_script_path(argv[1], REPORT_SUFFIX);
-               if (!report_script_path) {
-                       fprintf(stderr, "report script not found\n");
-                       return -1;
+               if (is_top_script(argv[0])) {
+                       rep_args = argc - 1;
+               } else {
+                       int rec_args;
+
+                       rep_args = has_required_arg(rep_script_path);
+                       rec_args = (argc - 1) - rep_args;
+                       if (rec_args < 0) {
+                               fprintf(stderr, " %s script requires options."
+                                       "\n\n See perf trace -l for available "
+                                       "scripts and options.\n", argv[0]);
+                               usage_with_options(trace_usage, options);
+                       }
                }
 
                if (pipe(live_pipe) < 0) {
@@ -622,60 +689,84 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
                }
 
                if (!pid) {
+                       system_wide = true;
+                       j = 0;
+
                        dup2(live_pipe[1], 1);
                        close(live_pipe[0]);
 
-                       __argv = malloc(6 * sizeof(const char *));
-                       __argv[0] = "/bin/sh";
-                       __argv[1] = record_script_path;
-                       __argv[2] = "-q";
-                       __argv[3] = "-o";
-                       __argv[4] = "-";
-                       __argv[5] = NULL;
+                       if (!is_top_script(argv[0]))
+                               system_wide = !have_cmd(argc - rep_args,
+                                                       &argv[rep_args]);
+
+                       __argv = malloc((argc + 6) * sizeof(const char *));
+                       if (!__argv)
+                               die("malloc");
+
+                       __argv[j++] = "/bin/sh";
+                       __argv[j++] = rec_script_path;
+                       if (system_wide)
+                               __argv[j++] = "-a";
+                       __argv[j++] = "-q";
+                       __argv[j++] = "-o";
+                       __argv[j++] = "-";
+                       for (i = rep_args + 1; i < argc; i++)
+                               __argv[j++] = argv[i];
+                       __argv[j++] = NULL;
 
                        execvp("/bin/sh", (char **)__argv);
+                       free(__argv);
                        exit(-1);
                }
 
                dup2(live_pipe[0], 0);
                close(live_pipe[1]);
 
-               __argv = malloc((argc + 3) * sizeof(const char *));
-               __argv[0] = "/bin/sh";
-               __argv[1] = report_script_path;
-               for (i = 2; i < argc; i++)
-                       __argv[i] = argv[i];
-               __argv[i++] = "-i";
-               __argv[i++] = "-";
-               __argv[i++] = NULL;
+               __argv = malloc((argc + 4) * sizeof(const char *));
+               if (!__argv)
+                       die("malloc");
+               j = 0;
+               __argv[j++] = "/bin/sh";
+               __argv[j++] = rep_script_path;
+               for (i = 1; i < rep_args + 1; i++)
+                       __argv[j++] = argv[i];
+               __argv[j++] = "-i";
+               __argv[j++] = "-";
+               __argv[j++] = NULL;
 
                execvp("/bin/sh", (char **)__argv);
+               free(__argv);
                exit(-1);
        }
 
-       if (suffix) {
-               script_path = get_script_path(argv[2], suffix);
-               if (!script_path) {
-                       fprintf(stderr, "script not found\n");
-                       return -1;
-               }
-
-               __argv = malloc((argc + 1) * sizeof(const char *));
-               __argv[0] = "/bin/sh";
-               __argv[1] = script_path;
-               for (i = 3; i < argc; i++)
-                       __argv[i - 1] = argv[i];
-               __argv[argc - 1] = NULL;
+       if (rec_script_path)
+               script_path = rec_script_path;
+       if (rep_script_path)
+               script_path = rep_script_path;
+
+       if (script_path) {
+               system_wide = false;
+               j = 0;
+
+               if (rec_script_path)
+                       system_wide = !have_cmd(argc - 1, &argv[1]);
+
+               __argv = malloc((argc + 2) * sizeof(const char *));
+               if (!__argv)
+                       die("malloc");
+               __argv[j++] = "/bin/sh";
+               __argv[j++] = script_path;
+               if (system_wide)
+                       __argv[j++] = "-a";
+               for (i = 2; i < argc; i++)
+                       __argv[j++] = argv[i];
+               __argv[j++] = NULL;
 
                execvp("/bin/sh", (char **)__argv);
+               free(__argv);
                exit(-1);
        }
 
-       setup_scripting();
-
-       argc = parse_options(argc, argv, options, trace_usage,
-                            PARSE_OPT_STOP_AT_NON_OPTION);
-
        if (symbol__init() < 0)
                return -1;
        if (!script_name)
index eb5846bcb565fe3c53599adf4fbe5d1bdb9bed8d..8104895a7b67d8b5324fa975a98f72cb0ccd2bd8 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e raw_syscalls:sys_exit $@
+perf record -e raw_syscalls:sys_exit $@
index 5bfaae5a6cbae1b8a63283e9ba32f18269677dc7..33efc8673aae879daab6b97de3c1713ec09e3edd 100644 (file)
@@ -1,3 +1,3 @@
 #!/bin/bash
-perf record -a -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@
+perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@
 
index 6e0b2f7755ac218098479958150f06129cc60ec4..7cb9db2304483a69543f14fddc8883dc3d964480 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
+perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
index 6e0b2f7755ac218098479958150f06129cc60ec4..7cb9db2304483a69543f14fddc8883dc3d964480 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
+perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
index 9f2acaaae9f0538fbdea692bbadd015965b48ae2..464251a1bd7e6a235d59579b85ff80d646aead50 100644 (file)
@@ -1,5 +1,5 @@
 #!/bin/bash
-perf record -a -e sched:sched_switch -e sched:sched_wakeup $@
+perf record -e sched:sched_switch -e sched:sched_wakeup $@
 
 
 
index 85301f2471ff59b774573142a4d4c3db5e40604d..8edda9078d5d3a4711f4039e01be86438774dcdf 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
+perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
index eb5846bcb565fe3c53599adf4fbe5d1bdb9bed8d..8104895a7b67d8b5324fa975a98f72cb0ccd2bd8 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e raw_syscalls:sys_exit $@
+perf record -e raw_syscalls:sys_exit $@
index 5ecbb433caf499d4103ad9a5561ebfa7eea86471..b1495c9a9b20e14ca2ad1ae62eafc13b741d2ca5 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@
+perf record -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@
index d931a828126b75d843f40fc2ad3eb1cebc3b43fd..558754b840a98293e31aeb4a70864dd75f3b3b2f 100644 (file)
@@ -1,5 +1,5 @@
 #!/bin/bash
-perf record -a -e net:net_dev_xmit -e net:net_dev_queue                \
+perf record -e net:net_dev_xmit -e net:net_dev_queue           \
                -e net:netif_receive_skb -e net:netif_rx                \
                -e skb:consume_skb -e skb:kfree_skb                     \
                -e skb:skb_copy_datagram_iovec -e napi:napi_poll        \
index 17a3e9bd9e8f0b6f34a2989e7a6d4cbd5ffe7090..7493fddbe99532db2b2c0c4ad3d7b469d29e1dda 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -m 16384 -a -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@
+perf record -m 16384 -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@
index 1fc5998b721d5f2a5f2a89e83ad90559f18439dd..4efbfaa7f6a5dc1deace4583c28f3e29fbf0c878 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e raw_syscalls:sys_enter $@
+perf record -e raw_syscalls:sys_enter $@
index 1fc5998b721d5f2a5f2a89e83ad90559f18439dd..4efbfaa7f6a5dc1deace4583c28f3e29fbf0c878 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e raw_syscalls:sys_enter $@
+perf record -e raw_syscalls:sys_enter $@
index 1fc5998b721d5f2a5f2a89e83ad90559f18439dd..4efbfaa7f6a5dc1deace4583c28f3e29fbf0c878 100644 (file)
@@ -1,2 +1,2 @@
 #!/bin/bash
-perf record -a -e raw_syscalls:sys_enter $@
+perf record -e raw_syscalls:sys_enter $@
index 9706d9d40279859321412b270c8ac3053141f4f9..056c69521a38098a8053d18f3e615d3a35390fd4 100644 (file)
@@ -104,9 +104,10 @@ out_destroy_form:
        return rc;
 }
 
+static const char yes[] = "Yes", no[] = "No";
+
 bool ui__dialog_yesno(const char *msg)
 {
        /* newtWinChoice should really be accepting const char pointers... */
-       char yes[] = "Yes", no[] = "No";
-       return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
+       return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
 }