]> Git Repo - linux.git/commitdiff
Merge tag 'tty-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <[email protected]>
Thu, 6 Aug 2020 21:56:11 +0000 (14:56 -0700)
committerLinus Torvalds <[email protected]>
Thu, 6 Aug 2020 21:56:11 +0000 (14:56 -0700)
Pull tty/serial updates from Greg KH:
 "Here is the large set of TTY and Serial driver patches for 5.9-rc1.

  Lots of bugfixes in here, thanks to syzbot fuzzing for serial and vt
  and console code.

  Other highlights include:

   - much needed vt/vc code cleanup from Jiri Slaby

   - 8250 driver fixes and additions

   - various serial driver updates and feature enhancements

   - locking cleanup for serial/console initializations

   - other minor cleanups

  All of these have been in linux-next with no reported issues"

* tag 'tty-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (90 commits)
  MAINTAINERS: enlist Greg formally for console stuff
  vgacon: Fix for missing check in scrollback handling
  Revert "serial: 8250: Let serial core initialise spin lock"
  serial: 8250: Let serial core initialise spin lock
  tty: keyboard, do not speculate on func_table index
  serial: stm32: Add RS485 RTS GPIO control
  serial: 8250_dw: Fix common clocks usage race condition
  serial: 8250_dw: Pass the same rate to the clk round and set rate methods
  serial: 8250_dw: Simplify the ref clock rate setting procedure
  serial: 8250: Add 8250 port clock update method
  tty: serial: imx: add imx earlycon driver
  tty: serial: imx: enable imx serial console port as module
  tty/synclink: remove leftover bits of non-PCI card support
  tty: Use the preferred form for passing the size of a structure type
  tty: Fix identation issues in struct serial_struct32
  tty: Avoid the use of one-element arrays
  serial: msm_serial: add sparse context annotation
  serial: pmac_zilog: add sparse context annotation
  newport_con: vc_color is now in state
  serial: imx: use hrtimers for rs485 delays
  ...

1  2 
MAINTAINERS
drivers/accessibility/speakup/main.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/vt/keyboard.c
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/video/console/newport_con.c
drivers/video/fbdev/core/fbcon.c

diff --combined MAINTAINERS
index 8b87d8a7c6d7a61e9340faf7f29ccf48ff28f272,8d6515b42916bcf43b90a2dea14b87b56faad38e..4e497d1e2ab530f7f1384d1c788fb9a9275e8f23
@@@ -147,7 -147,7 +147,7 @@@ Maintainers Lis
  M:    Steffen Klassert <[email protected]>
  L:    [email protected]
  S:    Odd Fixes
 -F:    Documentation/networking/device_drivers/3com/vortex.rst
 +F:    Documentation/networking/device_drivers/ethernet/3com/vortex.rst
  F:    drivers/net/ethernet/3com/3c59x.c
  
  3CR990 NETWORK DRIVER
@@@ -782,7 -782,7 +782,7 @@@ F: include/dt-bindings/reset/altr,rst-m
  F:    include/linux/mfd/altera-a10sr.h
  
  ALTERA TRIPLE SPEED ETHERNET DRIVER
 -M:    Thor Thayer <thor.thayer@linux.intel.com>
 +M:    Joyce Ooi <joyce.ooi@intel.com>
  L:    [email protected]
  S:    Maintained
  F:    drivers/net/ethernet/altera/
@@@ -816,7 -816,7 +816,7 @@@ R: Saeed Bishara <[email protected]
  R:    Zorik Machulsky <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/amazon/ena.rst
 +F:    Documentation/networking/device_drivers/ethernet/amazon/ena.rst
  F:    drivers/net/ethernet/amazon/
  
  AMAZON RDMA EFA DRIVER
@@@ -830,20 -830,11 +830,20 @@@ F:      include/uapi/rdma/efa-abi.
  
  AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER
  M:    Tom Lendacky <[email protected]>
 +M:    John Allen <[email protected]>
  L:    [email protected]
  S:    Supported
  F:    drivers/crypto/ccp/
  F:    include/linux/ccp.h
  
 +AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER - SEV SUPPORT
 +M:    Brijesh Singh <[email protected]>
 +M:    Tom Lendacky <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +F:    drivers/crypto/ccp/sev*
 +F:    include/uapi/linux/psp-sev.h
 +
  AMD DISPLAY CORE
  M:    Harry Wentland <[email protected]>
  M:    Leo Li <[email protected]>
@@@ -1082,7 -1073,6 +1082,7 @@@ L:      [email protected]
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
  F:    drivers/media/i2c/adv7180.c
 +F:    Documentation/devicetree/bindings/media/i2c/adv7180.yaml
  
  ANALOG DEVICES INC ADV748X DRIVER
  M:    Kieran Bingham <[email protected]>
@@@ -1180,8 -1170,6 +1180,8 @@@ M:      Todd Kjos <[email protected]
  M:    Martijn Coenen <[email protected]>
  M:    Joel Fernandes <[email protected]>
  M:    Christian Brauner <[email protected]>
 +M:    Hridya Valsaraju <[email protected]>
 +M:    Suren Baghdasaryan <[email protected]>
  L:    [email protected]
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
@@@ -1307,7 -1295,7 +1307,7 @@@ L:      [email protected]
  S:    Supported
  W:    https://www.marvell.com/
  Q:    http://patchwork.ozlabs.org/project/netdev/list/
 -F:    Documentation/networking/device_drivers/aquantia/atlantic.rst
 +F:    Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst
  F:    drivers/net/ethernet/aquantia/atlantic/
  
  AQUANTIA ETHERNET DRIVER PTP SUBSYSTEM
@@@ -1437,7 -1425,7 +1437,7 @@@ F:      arch/arm*/include/asm/perf_event.
  F:    arch/arm*/kernel/hw_breakpoint.c
  F:    arch/arm*/kernel/perf_*
  F:    arch/arm/oprofile/common.c
 -F:    drivers/perf/*
 +F:    drivers/perf/
  F:    include/linux/perf/arm_pmu.h
  
  ARM PORT
@@@ -1460,6 -1448,11 +1460,6 @@@ S:     Odd Fixe
  F:    drivers/amba/
  F:    include/linux/amba/bus.h
  
 -ARM PRIMECELL CLCD PL110 DRIVER
 -M:    Russell King <[email protected]>
 -S:    Odd Fixes
 -F:    drivers/video/fbdev/amba-clcd.*
 -
  ARM PRIMECELL KMI PL050 DRIVER
  M:    Russell King <[email protected]>
  S:    Odd Fixes
@@@ -1604,9 -1597,6 +1604,9 @@@ F:      sound/soc/meson
  
  ARM/Amlogic Meson SoC support
  M:    Kevin Hilman <[email protected]>
 +R:    Neil Armstrong <[email protected]>
 +R:    Jerome Brunet <[email protected]>
 +R:    Martin Blumenstingl <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
  L:    [email protected]
  S:    Maintained
@@@ -1627,7 -1617,7 +1627,7 @@@ L:      [email protected]
  S:    Maintained
  F:    arch/arm/boot/dts/alpine*
  F:    arch/arm/mach-alpine/
 -F:    arch/arm64/boot/dts/al/
 +F:    arch/arm64/boot/dts/amazon/
  F:    drivers/*/*alpine*
  
  ARM/ARTPEC MACHINE SUPPORT
@@@ -1964,14 -1954,6 +1964,14 @@@ F:    drivers/irqchip/irq-ixp4xx.
  F:    include/linux/irqchip/irq-ixp4xx.h
  F:    include/linux/platform_data/timer-ixp4xx.h
  
 +ARM/INTEL KEEMBAY ARCHITECTURE
 +M:    Paul J. Murphy <[email protected]>
 +M:    Daniele Alessandrelli <[email protected]>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/arm/intel,keembay.yaml
 +F:    arch/arm64/boot/dts/intel/keembay-evm.dts
 +F:    arch/arm64/boot/dts/intel/keembay-soc.dtsi
 +
  ARM/INTEL RESEARCH IMOTE/STARGATE 2 MACHINE SUPPORT
  M:    Jonathan Cameron <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
@@@ -2129,32 -2111,12 +2129,32 @@@ X:   drivers/net/wireless/atmel
  N:    at91
  N:    atmel
  
 +ARM/Microchip Sparx5 SoC support
 +M:    Lars Povlsen <[email protected]>
 +M:    Steen Hegelund <[email protected]>
 +M:    Microchip Linux Driver Support <[email protected]>
 +L:    [email protected] (moderated for non-subscribers)
 +S:    Supported
 +F:    arch/arm64/boot/dts/microchip/
 +N:    sparx5
 +
  ARM/MIOA701 MACHINE SUPPORT
  M:    Robert Jarzmik <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
  S:    Maintained
  F:    arch/arm/mach-pxa/mioa701.c
  
 +ARM/MStar/Sigmastar Armv7 SoC support
 +M:    Daniel Palmer <[email protected]>
 +L:    [email protected] (moderated for non-subscribers)
 +S:    Maintained
 +W:    http://linux-chenxing.org/
 +F:    Documentation/devicetree/bindings/arm/mstar/*
 +F:    arch/arm/boot/dts/infinity*.dtsi
 +F:    arch/arm/boot/dts/mercury*.dtsi
 +F:    arch/arm/boot/dts/mstar-v7.dtsi
 +F:    arch/arm/mach-mstar/
 +
  ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
  M:    Michael Petchkovsky <[email protected]>
  S:    Maintained
@@@ -2865,7 -2827,7 +2865,7 @@@ ASYMMETRIC KEY
  M:    David Howells <[email protected]>
  L:    [email protected]
  S:    Maintained
 -F:    Documentation/crypto/asymmetric-keys.txt
 +F:    Documentation/crypto/asymmetric-keys.rst
  F:    crypto/asymmetric_keys/
  F:    include/crypto/pkcs7.h
  F:    include/crypto/public_key.h
@@@ -2875,7 -2837,7 +2875,7 @@@ ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT
  R:    Dan Williams <[email protected]>
  S:    Odd fixes
  W:    http://sourceforge.net/projects/xscaleiop
 -F:    Documentation/crypto/async-tx-api.txt
 +F:    Documentation/crypto/async-tx-api.rst
  F:    crypto/async_tx/
  F:    drivers/dma/
  F:    include/linux/async_tx.h
@@@ -2919,7 -2881,7 +2919,7 @@@ S:      Supporte
  F:    drivers/net/wireless/ath/*
  
  ATHEROS ATH5K WIRELESS DRIVER
 -M:    Jiri Slaby <jirislaby@gmail.com>
 +M:    Jiri Slaby <jirislaby@kernel.org>
  M:    Nick Kossifidis <[email protected]>
  M:    Luis Chamberlain <[email protected]>
  L:    [email protected]
  S:    Maintained
  F:    drivers/connector/
  
+ CONSOLE SUBSYSTEM
+ M:    Greg Kroah-Hartman <[email protected]>
+ S:    Supported
+ F:    drivers/video/console/
+ F:    include/linux/console*
  CONTROL GROUP (CGROUP)
  M:    Tejun Heo <[email protected]>
  M:    Li Zefan <[email protected]>
@@@ -4439,12 -4407,6 +4445,12 @@@ S:    Maintaine
  F:    Documentation/hwmon/coretemp.rst
  F:    drivers/hwmon/coretemp.c
  
 +CORSAIR-CPRO HARDWARE MONITOR DRIVER
 +M:    Marius Zachmann <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/hwmon/corsair-cpro.c
 +
  COSA/SRP SYNC SERIAL DRIVER
  M:    Jan "Yenya" Kasprzak <[email protected]>
  S:    Maintained
@@@ -4798,7 -4760,7 +4804,7 @@@ F:      net/ax25/sysctl_net_ax25.
  DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
  L:    [email protected]
  S:    Orphan
 -F:    Documentation/networking/device_drivers/dec/dmfe.rst
 +F:    Documentation/networking/device_drivers/ethernet/dec/dmfe.rst
  F:    drivers/net/ethernet/dec/tulip/dmfe.c
  
  DC390/AM53C974 SCSI driver
@@@ -5138,7 -5100,6 +5144,7 @@@ F:      fs/dlm
  
  DMA BUFFER SHARING FRAMEWORK
  M:    Sumit Semwal <[email protected]>
 +M:    Christian König <[email protected]>
  L:    [email protected]
  L:    [email protected]
  L:    [email protected] (moderated for non-subscribers)
@@@ -5286,8 -5247,8 +5292,8 @@@ M:      Ioana Ciornei <[email protected]
  M:    Ioana Radulescu <[email protected]>
  L:    [email protected]
  S:    Maintained
 -F:    Documentation/networking/device_drivers/freescale/dpaa2/ethernet-driver.rst
 -F:    Documentation/networking/device_drivers/freescale/dpaa2/mac-phy-support.rst
 +F:    Documentation/networking/device_drivers/ethernet/freescale/dpaa2/ethernet-driver.rst
 +F:    Documentation/networking/device_drivers/ethernet/freescale/dpaa2/mac-phy-support.rst
  F:    drivers/net/ethernet/freescale/dpaa2/Kconfig
  F:    drivers/net/ethernet/freescale/dpaa2/Makefile
  F:    drivers/net/ethernet/freescale/dpaa2/dpaa2-eth*
@@@ -5864,7 -5825,7 +5870,7 @@@ M:      Eric Anholt <[email protected]
  S:    Supported
  T:    git git://github.com/anholt/linux
  T:    git git://anongit.freedesktop.org/drm/drm-misc
 -F:    Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
 +F:    Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
  F:    drivers/gpu/drm/vc4/
  F:    include/uapi/drm/vc4_drm.h
  
@@@ -5888,15 -5849,6 +5894,15 @@@ T:    git git://anongit.freedesktop.org/dr
  F:    Documentation/gpu/xen-front.rst
  F:    drivers/gpu/drm/xen/
  
 +DRM DRIVERS FOR XILINX
 +M:    Hyun Kwon <[email protected]>
 +M:    Laurent Pinchart <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +T:    git git://anongit.freedesktop.org/drm/drm-misc
 +F:    Documentation/devicetree/bindings/display/xlnx/
 +F:    drivers/gpu/drm/xlnx/
 +
  DRM DRIVERS FOR ZTE ZX
  M:    Shawn Guo <[email protected]>
  L:    [email protected]
  S:    Maintained
  F:    drivers/usb/gadget/udc/fsl*
  
 +FREESCALE USB PHY DRIVER
 +M:    Ran Wang <[email protected]>
 +L:    [email protected]
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/usb/phy/phy-fsl-usb*
 +
  FREEVXFS FILESYSTEM
  M:    Christoph Hellwig <[email protected]>
  S:    Maintained
@@@ -7168,7 -7113,7 +7174,7 @@@ F:      include/linux/futex.
  F:    include/uapi/linux/futex.h
  F:    kernel/futex.c
  F:    tools/perf/bench/futex*
 -F:    Documentation/locking/*futex*
 +F:    tools/testing/selftests/futex/
  
  GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER
  M:    Tim Harvey <[email protected]>
@@@ -7364,7 -7309,7 +7370,7 @@@ R:      Sagi Shahar <[email protected]
  R:    Jon Olson <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/google/gve.rst
 +F:    Documentation/networking/device_drivers/ethernet/google/gve.rst
  F:    drivers/net/ethernet/google
  
  GPD POCKET FAN DRIVER
@@@ -7975,7 -7920,7 +7981,7 @@@ HUAWEI ETHERNET DRIVE
  M:    Bin Luo <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/hinic.rst
 +F:    Documentation/networking/device_drivers/ethernet/huawei/hinic.rst
  F:    drivers/net/ethernet/huawei/hinic/
  
  HUGETLB FILESYSTEM
@@@ -8027,7 -7972,7 +8033,7 @@@ S:      Supporte
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
  F:    Documentation/ABI/stable/sysfs-bus-vmbus
  F:    Documentation/ABI/testing/debugfs-hyperv
 -F:    Documentation/networking/device_drivers/microsoft/netvsc.rst
 +F:    Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst
  F:    arch/x86/hyperv
  F:    arch/x86/include/asm/hyperv-tlfs.h
  F:    arch/x86/include/asm/mshyperv.h
  S:    Maintained
  F:    drivers/platform/x86/intel_atomisp2_pm.c
  
 +INTEL ATOMISP2 LED DRIVER
 +M:    Hans de Goede <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/platform/x86/intel_atomisp2_led.c
 +
  INTEL BROXTON PMC DRIVER
  M:    Mika Westerberg <[email protected]>
  M:    Zha Qipeng <[email protected]>
@@@ -8715,7 -8654,18 +8721,7 @@@ W:     http://e1000.sourceforge.net
  Q:    http://patchwork.ozlabs.org/project/intel-wired-lan/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
 -F:    Documentation/networking/device_drivers/intel/e100.rst
 -F:    Documentation/networking/device_drivers/intel/e1000.rst
 -F:    Documentation/networking/device_drivers/intel/e1000e.rst
 -F:    Documentation/networking/device_drivers/intel/fm10k.rst
 -F:    Documentation/networking/device_drivers/intel/i40e.rst
 -F:    Documentation/networking/device_drivers/intel/iavf.rst
 -F:    Documentation/networking/device_drivers/intel/ice.rst
 -F:    Documentation/networking/device_drivers/intel/igb.rst
 -F:    Documentation/networking/device_drivers/intel/igbvf.rst
 -F:    Documentation/networking/device_drivers/intel/ixgb.rst
 -F:    Documentation/networking/device_drivers/intel/ixgbe.rst
 -F:    Documentation/networking/device_drivers/intel/ixgbevf.rst
 +F:    Documentation/networking/device_drivers/ethernet/intel/
  F:    drivers/net/ethernet/intel/
  F:    drivers/net/ethernet/intel/*/
  F:    include/linux/avf/virtchnl.h
@@@ -8843,7 -8793,7 +8849,7 @@@ M:      Tomas Winkler <[email protected]
  L:    [email protected]
  S:    Supported
  F:    Documentation/driver-api/mei/*
 -F:    drivers/misc/mei/*
 +F:    drivers/misc/mei/
  F:    drivers/watchdog/mei_wdt.c
  F:    include/linux/mei_cl_bus.h
  F:    include/uapi/linux/mei.h
@@@ -8905,8 -8855,8 +8911,8 @@@ INTEL PRO/WIRELESS 2100, 2200BG, 2915AB
  M:    Stanislav Yakovlev <[email protected]>
  L:    [email protected]
  S:    Maintained
 -F:    Documentation/networking/device_drivers/intel/ipw2100.rst
 -F:    Documentation/networking/device_drivers/intel/ipw2200.rst
 +F:    Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
 +F:    Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
  F:    drivers/net/wireless/intel/ipw2x00/
  
  INTEL PSTATE DRIVER
@@@ -9036,14 -8986,6 +9042,14 @@@ F:    include/dt-bindings/interconnect
  F:    include/linux/interconnect-provider.h
  F:    include/linux/interconnect.h
  
 +INVENSENSE ICM-426xx IMU DRIVER
 +M:    Jean-Baptiste Maneyrol <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +W     https://invensense.tdk.com/
 +F:    Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
 +F:    drivers/iio/imu/inv_icm42600/
 +
  INVENSENSE MPU-3050 GYROSCOPE DRIVER
  M:    Linus Walleij <[email protected]>
  L:    [email protected]
@@@ -9517,11 -9459,9 +9523,11 @@@ F:    arch/arm64/kvm
  F:    include/kvm/arm_*
  
  KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
 +M:    Huacai Chen <[email protected]>
 +M:    Aleksandar Markovic <[email protected]>
  L:    [email protected]
  L:    [email protected]
 -S:    Orphan
 +S:    Maintained
  F:    arch/mips/include/asm/kvm*
  F:    arch/mips/include/uapi/asm/kvm*
  F:    arch/mips/kvm/
@@@ -9675,7 -9615,7 +9681,7 @@@ M:      Anil S Keshavamurthy <anil.s.keshava
  M:    "David S. Miller" <[email protected]>
  M:    Masami Hiramatsu <[email protected]>
  S:    Maintained
 -F:    Documentation/kprobes.txt
 +F:    Documentation/trace/kprobes.rst
  F:    include/asm-generic/kprobes.h
  F:    include/linux/kprobes.h
  F:    kernel/kprobes.c
@@@ -9747,10 -9687,12 +9753,10 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    scripts/leaking_addresses.pl
  
  LED SUBSYSTEM
 -M:    Jacek Anaszewski <[email protected]>
  M:    Pavel Machek <[email protected]>
  R:    Dan Murphy <[email protected]>
  L:    [email protected]
  S:    Maintained
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git
  F:    Documentation/devicetree/bindings/leds/
  F:    drivers/leds/
@@@ -10036,7 -9978,6 +10042,7 @@@ M:    Luc Maranget <[email protected]
  M:    "Paul E. McKenney" <[email protected]>
  R:    Akira Yokosawa <[email protected]>
  R:    Daniel Lustig <[email protected]>
 +R:    Joel Fernandes <[email protected]>
  L:    [email protected]
  L:    [email protected]
  S:    Supported
@@@ -10045,7 -9986,6 +10051,7 @@@ F:    Documentation/atomic_bitops.tx
  F:    Documentation/atomic_t.txt
  F:    Documentation/core-api/atomic_ops.rst
  F:    Documentation/core-api/refcount-vs-atomic.rst
 +F:    Documentation/litmus-tests/
  F:    Documentation/memory-barriers.txt
  F:    tools/memory-model/
  
@@@ -10440,7 -10380,7 +10446,7 @@@ M:   Geetha sowjanya <[email protected]
  M:    Jerin Jacob <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/marvell/octeontx2.rst
 +F:    Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
  F:    drivers/net/ethernet/marvell/octeontx2/af/
  
  MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
  S:    Supported
  W:    http://www.mellanox.com
  Q:    http://patchwork.ozlabs.org/project/netdev/list/
 -F:    Documentation/networking/device_drivers/mellanox/
 +F:    Documentation/networking/device_drivers/ethernet/mellanox/
  F:    drivers/net/ethernet/mellanox/mlx5/core/
  F:    include/linux/mlx5/
  
@@@ -11163,23 -11103,6 +11169,23 @@@ F: Documentation/core-api/boot-time-mm.
  F:    include/linux/memblock.h
  F:    mm/memblock.c
  
 +MEMORY CONTROLLER DRIVERS
 +M:    Krzysztof Kozlowski <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
 +F:    Documentation/devicetree/bindings/memory-controllers/
 +F:    drivers/memory/
 +
 +MEMORY FREQUENCY SCALING DRIVERS FOR NVIDIA TEGRA
 +M:    Dmitry Osipenko <[email protected]>
 +L:    [email protected]
 +L:    [email protected]
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 +S:    Maintained
 +F:    drivers/devfreq/tegra20-devfreq.c
 +F:    drivers/devfreq/tegra30-devfreq.c
 +
  MEMORY MANAGEMENT
  M:    Andrew Morton <[email protected]>
  L:    [email protected]
@@@ -11419,6 -11342,7 +11425,6 @@@ F:   Documentation/devicetree/bindings/pw
  F:    drivers/pwm/pwm-atmel.c
  
  MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER
 -M:    Ludovic Desroches <[email protected]>
  M:    Eugen Hristev <[email protected]>
  L:    [email protected]
  S:    Supported
  S:    Supported
  F:    drivers/usb/gadget/udc/atmel_usba_udc.*
  
 +MICROCHIP WILC1000 WIFI DRIVER
 +M:    Ajay Singh <[email protected]>
 +M:    Claudiu Beznea <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +F:    drivers/net/wireless/microchip/wilc1000/
 +
  MICROCHIP XDMA DRIVER
  M:    Ludovic Desroches <[email protected]>
  L:    [email protected]
@@@ -11525,17 -11442,6 +11531,17 @@@ F: arch/mips/configs/generic/board-bost
  F:    drivers/clk/imgtec/clk-boston.c
  F:    include/dt-bindings/clock/boston-clock.h
  
 +MIPS CORE DRIVERS
 +M:    Thomas Bogendoerfer <[email protected]>
 +M:    Serge Semin <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +F:    drivers/bus/mips_cdmm.c
 +F:    drivers/clocksource/mips-gic-timer.c
 +F:    drivers/cpuidle/cpuidle-cps.c
 +F:    drivers/irqchip/irq-mips-cpu.c
 +F:    drivers/irqchip/irq-mips-gic.c
 +
  MIPS GENERIC PLATFORM
  M:    Paul Burton <[email protected]>
  L:    [email protected]
@@@ -11664,7 -11570,7 +11670,7 @@@ F:   drivers/media/pci/meye
  F:    include/uapi/linux/meye.h
  
  MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
 -M:    Jiri Slaby <jirislaby@gmail.com>
 +M:    Jiri Slaby <jirislaby@kernel.org>
  S:    Maintained
  F:    Documentation/driver-api/serial/moxa-smartio.rst
  F:    drivers/tty/mxser.*
@@@ -11918,8 -11824,8 +11924,8 @@@ NETERION 10GbE DRIVERS (s2io/vxge
  M:    Jon Mason <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/neterion/s2io.rst
 -F:    Documentation/networking/device_drivers/neterion/vxge.rst
 +F:    Documentation/networking/device_drivers/ethernet/neterion/s2io.rst
 +F:    Documentation/networking/device_drivers/ethernet/neterion/vxge.rst
  F:    drivers/net/ethernet/neterion/
  
  NETFILTER
@@@ -12364,7 -12270,6 +12370,7 @@@ F:   drivers/nvme/target
  NVMEM FRAMEWORK
  M:    Srinivas Kandagatla <[email protected]>
  S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git
  F:    Documentation/ABI/stable/sysfs-bus-nvmem
  F:    Documentation/devicetree/bindings/nvmem/
  F:    drivers/nvmem/
@@@ -12810,7 -12715,6 +12816,7 @@@ OP-TEE DRIVE
  M:    Jens Wiklander <[email protected]>
  L:    [email protected]
  S:    Maintained
 +F:    Documentation/ABI/testing/sysfs-bus-optee-devices
  F:    drivers/tee/optee/
  
  OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
@@@ -13484,7 -13388,7 +13490,7 @@@ M:   Shannon Nelson <[email protected]
  M:    Pensando Drivers <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/pensando/ionic.rst
 +F:    Documentation/networking/device_drivers/ethernet/pensando/ionic.rst
  F:    drivers/net/ethernet/pensando/
  
  PER-CPU MEMORY ALLOCATOR
@@@ -13694,19 -13598,22 +13700,19 @@@ F:        drivers/block/pktcdvd.
  F:    include/linux/pktcdvd.h
  F:    include/uapi/linux/pktcdvd.h
  
 -PKUNITY SOC DRIVERS
 -M:    Guan Xuetao <[email protected]>
 -S:    Maintained
 -W:    http://mprc.pku.edu.cn/~guanxuetao/linux
 -T:    git git://github.com/gxt/linux.git
 -F:    drivers/i2c/busses/i2c-puv3.c
 -F:    drivers/input/serio/i8042-unicore32io.h
 -F:    drivers/rtc/rtc-puv3.c
 -F:    drivers/video/fbdev/fb-puv3.c
 -
  PLANTOWER PMS7003 AIR POLLUTION SENSOR DRIVER
  M:    Tomasz Duszynski <[email protected]>
  S:    Maintained
  F:    Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
  F:    drivers/iio/chemical/pms7003.c
  
 +PLDMFW LIBRARY
 +M:    Jacob Keller <[email protected]>
 +S:    Maintained
 +F:    Documentation/driver-api/pldmfw/
 +F:    include/linux/pldmfw.h
 +F:    lib/pldmfw/
 +
  PLX DMA DRIVER
  M:    Logan Gunthorpe <[email protected]>
  S:    Maintained
@@@ -14164,7 -14071,7 +14170,7 @@@ QLOGIC QLA3XXX NETWORK DRIVE
  M:    [email protected]
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/qlogic/LICENSE.qla3xxx
 +F:    Documentation/networking/device_drivers/ethernet/qlogic/LICENSE.qla3xxx
  F:    drivers/net/ethernet/qlogic/qla3xxx.*
  
  QLOGIC QLA4XXX iSCSI DRIVER
@@@ -14215,7 -14122,7 +14221,7 @@@ M:   Laurentiu Tudor <laurentiu.tudor@nxp
  L:    [email protected]
  S:    Maintained
  F:    Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
 -F:    Documentation/networking/device_drivers/freescale/dpaa2/overview.rst
 +F:    Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
  F:    drivers/bus/fsl-mc/
  
  QT1010 MEDIA DRIVER
@@@ -14287,8 -14194,7 +14293,8 @@@ F:   Documentation/devicetree/bindings/ne
  F:    drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
  
  QUALCOMM GENERIC INTERFACE I2C DRIVER
 -M:    Alok Chauhan <[email protected]>
 +M:    Akash Asthana <[email protected]>
 +M:    Mukesh Savaliya <[email protected]>
  L:    [email protected]
  L:    [email protected]
  S:    Supported
@@@ -14337,12 -14243,12 +14343,12 @@@ M:        Subash Abhinov Kasiviswanathan <suba
  M:    Sean Tranchetti <[email protected]>
  L:    [email protected]
  S:    Maintained
 -F:    Documentation/networking/device_drivers/qualcomm/rmnet.rst
 +F:    Documentation/networking/device_drivers/cellular/qualcomm/rmnet.rst
  F:    drivers/net/ethernet/qualcomm/rmnet/
  F:    include/linux/if_rmnet.h
  
  QUALCOMM TSENS THERMAL DRIVER
 -M:    Amit Kucheria <amit.kucheria@linaro.org>
 +M:    Amit Kucheria <amitk@kernel.org>
  L:    [email protected]
  L:    [email protected]
  S:    Maintained
@@@ -14549,7 -14455,7 +14555,7 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    Documentation/RCU/
  F:    include/linux/rcu*
  F:    kernel/rcu/
 -X:    Documentation/RCU/torture.txt
 +X:    Documentation/RCU/torture.rst
  X:    include/linux/srcu*.h
  X:    kernel/rcu/srcu*.c
  
@@@ -14625,7 -14531,7 +14631,7 @@@ S:   Maintaine
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rproc-next
  F:    Documentation/ABI/testing/sysfs-class-remoteproc
  F:    Documentation/devicetree/bindings/remoteproc/
 -F:    Documentation/remoteproc.txt
 +F:    Documentation/staging/remoteproc.rst
  F:    drivers/remoteproc/
  F:    include/linux/remoteproc.h
  F:    include/linux/remoteproc/
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git rpmsg-next
  F:    Documentation/ABI/testing/sysfs-bus-rpmsg
 -F:    Documentation/rpmsg.txt
 +F:    Documentation/staging/rpmsg.rst
  F:    drivers/rpmsg/
  F:    include/linux/rpmsg.h
  F:    include/linux/rpmsg/
@@@ -15409,7 -15315,7 +15415,7 @@@ F:   drivers/mmc/host/sdhci
  F:    include/linux/mmc/sdhci*
  
  SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
 -M:    Ludovic Desroches <ludovic.desroches@microchip.com>
 +M:    Eugen Hristev <eugen.hristev@microchip.com>
  L:    [email protected]
  S:    Supported
  F:    drivers/mmc/host/sdhci-of-at91.c
@@@ -15474,20 -15380,11 +15480,20 @@@ F:        scripts/selinux
  F:    security/selinux/
  
  SENSABLE PHANTOM
 -M:    Jiri Slaby <jirislaby@gmail.com>
 +M:    Jiri Slaby <jirislaby@kernel.org>
  S:    Maintained
  F:    drivers/misc/phantom.c
  F:    include/uapi/linux/phantom.h
  
 +SENSIRION SCD30 CARBON DIOXIDE SENSOR DRIVER
 +M:    Tomasz Duszynski <[email protected]>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/iio/chemical/sensirion,scd30.yaml
 +F:    drivers/iio/chemical/scd30.h
 +F:    drivers/iio/chemical/scd30_core.c
 +F:    drivers/iio/chemical/scd30_i2c.c
 +F:    drivers/iio/chemical/scd30_serial.c
 +
  SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
  M:    Tomasz Duszynski <[email protected]>
  S:    Maintained
@@@ -15539,7 -15436,7 +15545,7 @@@ F:   drivers/net/phy/phylink.
  F:    drivers/net/phy/sfp*
  F:    include/linux/phylink.h
  F:    include/linux/sfp.h
 -K:    phylink
 +K:    phylink\.h|struct\s+phylink|\.phylink|>phylink_|phylink_(autoneg|clear|connect|create|destroy|disconnect|ethtool|helper|mac|mii|of|set|start|stop|test|validate)
  
  SGI GRU DRIVER
  M:    Dimitri Sivanich <[email protected]>
@@@ -16134,9 -16031,8 +16140,9 @@@ F:   sound/soc/sof
  
  SOUNDWIRE SUBSYSTEM
  M:    Vinod Koul <[email protected]>
 -M:    Sanyog Kale <sanyog.r.kale@intel.com>
 +M:    Bard Liao <yung-chuan.liao@linux.intel.com>
  R:    Pierre-Louis Bossart <[email protected]>
 +R:    Sanyog Kale <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  F:    Documentation/driver-api/soundwire/
@@@ -16187,16 -16083,6 +16193,16 @@@ Q: https://patchwork.kernel.org/project
  B:    https://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools
  F:    include/linux/compiler.h
  
 +SPEAKUP CONSOLE SPEECH DRIVER
 +M:    William Hubbs <[email protected]>
 +M:    Chris Brannon <[email protected]>
 +M:    Kirk Reiser <[email protected]>
 +M:    Samuel Thibault <[email protected]>
 +L:    [email protected]
 +S:    Odd Fixes
 +W:    http://www.linux-speakup.org/
 +F:    drivers/accessibility/speakup/
 +
  SPEAR CLOCK FRAMEWORK SUPPORT
  M:    Viresh Kumar <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
@@@ -16241,7 -16127,7 +16247,7 @@@ SPIDERNET NETWORK DRIVER for CEL
  M:    Ishizaki Kou <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/networking/device_drivers/toshiba/spider_net.rst
 +F:    Documentation/networking/device_drivers/ethernet/toshiba/spider_net.rst
  F:    drivers/net/ethernet/toshiba/spider_net*
  
  SPMI SUBSYSTEM
@@@ -16384,11 -16270,28 +16390,11 @@@ L:        [email protected]
  S:    Maintained
  F:    drivers/staging/sm750fb/
  
 -STAGING - SPEAKUP CONSOLE SPEECH DRIVER
 -M:    William Hubbs <[email protected]>
 -M:    Chris Brannon <[email protected]>
 -M:    Kirk Reiser <[email protected]>
 -M:    Samuel Thibault <[email protected]>
 -L:    [email protected]
 -S:    Odd Fixes
 -W:    http://www.linux-speakup.org/
 -F:    drivers/staging/speakup/
 -
  STAGING - VIA VT665X DRIVERS
  M:    Forest Bond <[email protected]>
  S:    Odd Fixes
  F:    drivers/staging/vt665?/
  
 -STAGING - WILC1000 WIFI DRIVER
 -M:    Adham Abozaeid <[email protected]>
 -M:    Ajay Singh <[email protected]>
 -L:    [email protected]
 -S:    Supported
 -F:    drivers/staging/wilc1000/
 -
  STAGING SUBSYSTEM
  M:    Greg Kroah-Hartman <[email protected]>
  L:    [email protected]
@@@ -16451,7 -16354,7 +16457,7 @@@ M:   Jose Abreu <[email protected]
  L:    [email protected]
  S:    Supported
  W:    http://www.stlinux.com
 -F:    Documentation/networking/device_drivers/stmicro/
 +F:    Documentation/networking/device_drivers/ethernet/stmicro/
  F:    drivers/net/ethernet/stmicro/stmmac/
  
  SUN3/3X
@@@ -16892,7 -16795,7 +16898,7 @@@ TEE SUBSYSTE
  M:    Jens Wiklander <[email protected]>
  L:    [email protected]
  S:    Maintained
 -F:    Documentation/tee.txt
 +F:    Documentation/staging/tee.rst
  F:    drivers/tee/
  F:    include/linux/tee_drv.h
  F:    include/uapi/linux/tee.h
@@@ -17046,7 -16949,7 +17052,7 @@@ F:   drivers/media/radio/radio-raremono.
  THERMAL
  M:    Zhang Rui <[email protected]>
  M:    Daniel Lezcano <[email protected]>
 -R:    Amit Kucheria <amit[email protected]>
 +R:    Amit Kucheria <amit[email protected]>
  L:    [email protected]
  S:    Supported
  Q:    https://patchwork.kernel.org/project/linux-pm/list/
@@@ -17339,7 -17242,7 +17345,7 @@@ M:   Samuel Chessman <[email protected]
  L:    [email protected] (subscribers-only)
  S:    Maintained
  W:    http://sourceforge.net/projects/tlan/
 -F:    Documentation/networking/device_drivers/ti/tlan.rst
 +F:    Documentation/networking/device_drivers/ethernet/ti/tlan.rst
  F:    drivers/net/ethernet/ti/tlan.*
  
  TM6000 VIDEO4LINUX DRIVER
@@@ -17404,7 -17307,7 +17410,7 @@@ M:   Josh Triplett <[email protected]
  L:    [email protected]
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
 -F:    Documentation/RCU/torture.txt
 +F:    Documentation/RCU/torture.rst
  F:    kernel/locking/locktorture.c
  F:    kernel/rcu/rcuperf.c
  F:    kernel/rcu/rcutorture.c
@@@ -17496,7 -17399,7 +17502,7 @@@ K:   ^Subject:.*(?i)trivia
  
  TTY LAYER
  M:    Greg Kroah-Hartman <[email protected]>
 -M:    Jiri Slaby <j[email protected]>
 +M:    Jiri Slaby <j[email protected]>
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
  F:    Documentation/driver-api/serial/
  S:    Supported
  F:    fs/unicode/
  
 -UNICORE32 ARCHITECTURE
 -M:    Guan Xuetao <[email protected]>
 -S:    Maintained
 -W:    http://mprc.pku.edu.cn/~guanxuetao/linux
 -T:    git git://github.com/gxt/linux.git
 -F:    arch/unicore32/
 -
  UNIFDEF
  M:    Tony Finch <[email protected]>
  S:    Maintained
@@@ -18968,24 -18878,6 +18974,24 @@@ F: Documentation/devicetree/bindings/me
  F:    drivers/media/platform/xilinx/
  F:    include/uapi/linux/xilinx-v4l2-controls.h
  
 +XILINX ZYNQMP DPDMA DRIVER
 +M:    Hyun Kwon <[email protected]>
 +M:    Laurent Pinchart <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +F:    Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
 +F:    drivers/dma/xilinx/xilinx_dpdma.c
 +F:    include/dt-bindings/dma/xlnx-zynqmp-dpdma.h
 +
 +XILINX ZYNQMP PSGTR PHY DRIVER
 +M:    Anurag Kumar Vulisha <[email protected]>
 +M:    Laurent Pinchart <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +T:    git https://github.com/Xilinx/linux-xlnx.git
 +F:    Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
 +F:    drivers/phy/xilinx/phy-zynqmp.c
 +
  XILLYBUS DRIVER
  M:    Eli Billauer <[email protected]>
  L:    [email protected]
  S:    Maintained
  W:    http://yaina.de/jreuter/
  W:    http://www.qsl.net/dl1bke/
 -F:    Documentation/networking/z8530drv.rst
 +F:    Documentation/networking/device_drivers/hamradio/z8530drv.rst
  F:    drivers/net/hamradio/*scc.c
  F:    drivers/net/hamradio/z8530.h
  
index 02471d932d71f698bb596380f4cbceabef74bd12,0000000000000000000000000000000000000000..ddfd12afe3b9a6f1303ef39108a2f2ba7611ac95
mode 100644,000000..100644
--- /dev/null
@@@ -1,2460 -1,0 +1,2460 @@@
-       spk_x = spk_cx = vc->vc_x;
-       spk_y = spk_cy = vc->vc_y;
 +// SPDX-License-Identifier: GPL-2.0+
 +/* speakup.c
 + * review functions for the speakup screen review package.
 + * originally written by: Kirk Reiser and Andy Berdan.
 + *
 + * extensively modified by David Borowski.
 + *
 + ** Copyright (C) 1998  Kirk Reiser.
 + *  Copyright (C) 2003  David Borowski.
 + */
 +
 +#include <linux/kernel.h>
 +#include <linux/vt.h>
 +#include <linux/tty.h>
 +#include <linux/mm.h>         /* __get_free_page() and friends */
 +#include <linux/vt_kern.h>
 +#include <linux/ctype.h>
 +#include <linux/selection.h>
 +#include <linux/unistd.h>
 +#include <linux/jiffies.h>
 +#include <linux/kthread.h>
 +#include <linux/keyboard.h>   /* for KT_SHIFT */
 +#include <linux/kbd_kern.h>   /* for vc_kbd_* and friends */
 +#include <linux/input.h>
 +#include <linux/kmod.h>
 +
 +/* speakup_*_selection */
 +#include <linux/module.h>
 +#include <linux/sched.h>
 +#include <linux/slab.h>
 +#include <linux/types.h>
 +#include <linux/consolemap.h>
 +
 +#include <linux/spinlock.h>
 +#include <linux/notifier.h>
 +
 +#include <linux/uaccess.h>    /* copy_from|to|user() and others */
 +
 +#include "spk_priv.h"
 +#include "speakup.h"
 +
 +#define MAX_DELAY msecs_to_jiffies(500)
 +#define MINECHOCHAR SPACE
 +
 +MODULE_AUTHOR("Kirk Reiser <[email protected]>");
 +MODULE_AUTHOR("Daniel Drake <[email protected]>");
 +MODULE_DESCRIPTION("Speakup console speech");
 +MODULE_LICENSE("GPL");
 +MODULE_VERSION(SPEAKUP_VERSION);
 +
 +char *synth_name;
 +module_param_named(synth, synth_name, charp, 0444);
 +module_param_named(quiet, spk_quiet_boot, bool, 0444);
 +
 +MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
 +MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
 +
 +special_func spk_special_handler;
 +
 +short spk_pitch_shift, synth_flags;
 +static u16 buf[256];
 +int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
 +int spk_no_intr, spk_spell_delay;
 +int spk_key_echo, spk_say_word_ctl;
 +int spk_say_ctrl, spk_bell_pos;
 +short spk_punc_mask;
 +int spk_punc_level, spk_reading_punc;
 +char spk_str_caps_start[MAXVARLEN + 1] = "\0";
 +char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
 +char spk_str_pause[MAXVARLEN + 1] = "\0";
 +bool spk_paused;
 +const struct st_bits_data spk_punc_info[] = {
 +      {"none", "", 0},
 +      {"some", "/$%&@", SOME},
 +      {"most", "$%&#()=+*/@^<>|\\", MOST},
 +      {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
 +      {"delimiters", "", B_WDLM},
 +      {"repeats", "()", CH_RPT},
 +      {"extended numeric", "", B_EXNUM},
 +      {"symbols", "", B_SYM},
 +      {NULL, NULL}
 +};
 +
 +static char mark_cut_flag;
 +#define MAX_KEY 160
 +static u_char *spk_shift_table;
 +u_char *spk_our_keys[MAX_KEY];
 +u_char spk_key_buf[600];
 +const u_char spk_key_defaults[] = {
 +#include "speakupmap.h"
 +};
 +
 +/* Speakup Cursor Track Variables */
 +static int cursor_track = 1, prev_cursor_track = 1;
 +
 +/* cursor track modes, must be ordered same as cursor_msgs */
 +enum {
 +      CT_Off = 0,
 +      CT_On,
 +      CT_Highlight,
 +      CT_Window,
 +      CT_Max
 +};
 +
 +#define read_all_mode CT_Max
 +
 +static struct tty_struct *tty;
 +
 +static void spkup_write(const u16 *in_buf, int count);
 +
 +static char *phonetic[] = {
 +      "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
 +      "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
 +          "papa",
 +      "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
 +      "x ray", "yankee", "zulu"
 +};
 +
 +/* array of 256 char pointers (one for each character description)
 + * initialized to default_chars and user selectable via
 + * /proc/speakup/characters
 + */
 +char *spk_characters[256];
 +
 +char *spk_default_chars[256] = {
 +/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
 +/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
 +/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
 +/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
 +          "control",
 +/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
 +          "tick",
 +/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
 +          "dot",
 +      "slash",
 +/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
 +      "eight", "nine",
 +/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
 +/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
 +/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
 +/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
 +/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
 +          "caret",
 +      "line",
 +/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
 +/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
 +/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
 +/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
 +/*127*/ "del", "control", "control", "control", "control", "control",
 +          "control", "control", "control", "control", "control",
 +/*138*/ "control", "control", "control", "control", "control",
 +          "control", "control", "control", "control", "control",
 +          "control", "control",
 +/*150*/ "control", "control", "control", "control", "control",
 +          "control", "control", "control", "control", "control",
 +/*160*/ "nbsp", "inverted bang",
 +/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
 +/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
 +/*172*/ "not", "soft hyphen", "registered", "macron",
 +/*176*/ "degrees", "plus or minus", "super two", "super three",
 +/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
 +/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
 +/*188*/ "one quarter", "one half", "three quarters",
 +          "inverted question",
 +/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
 +          "A RING",
 +/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
 +          "E OOMLAUT",
 +/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
 +          "N TILDE",
 +/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
 +/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
 +          "U CIRCUMFLEX",
 +/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
 +/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
 +/*230*/ "ae", "c cidella", "e grave", "e acute",
 +/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
 +          "i circumflex",
 +/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
 +          "o circumflex",
 +/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
 +          "u acute",
 +/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
 +};
 +
 +/* array of 256 u_short (one for each character)
 + * initialized to default_chartab and user selectable via
 + * /sys/module/speakup/parameters/chartab
 + */
 +u_short spk_chartab[256];
 +
 +static u_short default_chartab[256] = {
 +      B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
 +      B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
 +      B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
 +      B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
 +      WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,     /*  !"#$%&' */
 +      PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,   /* ()*+, -./ */
 +      NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
 +      NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,       /* 89:;<=>? */
 +      PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,  /* @ABCDEFG */
 +      A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
 +      A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
 +      A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,      /* XYZ[\]^_ */
 +      PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,  /* `abcdefg */
 +      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
 +      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
 +      ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
 +      B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
 +      B_SYM,  /* 135 */
 +      B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
 +      B_CAPSYM,       /* 143 */
 +      B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
 +      B_SYM,  /* 151 */
 +      B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
 +      B_SYM,  /* 159 */
 +      WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
 +      B_SYM,  /* 167 */
 +      B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
 +      B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
 +      B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
 +      A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
 +      A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
 +      A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
 +      A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
 +      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
 +      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
 +      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
 +      ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA  /* 248-255 */
 +};
 +
 +struct task_struct *speakup_task;
 +struct bleep spk_unprocessed_sound;
 +static int spk_keydown;
 +static u16 spk_lastkey;
 +static u_char spk_close_press, keymap_flags;
 +static u_char last_keycode, this_speakup_key;
 +static u_long last_spk_jiffy;
 +
 +struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
 +
 +DEFINE_MUTEX(spk_mutex);
 +
 +static int keyboard_notifier_call(struct notifier_block *,
 +                                unsigned long code, void *param);
 +
 +static struct notifier_block keyboard_notifier_block = {
 +      .notifier_call = keyboard_notifier_call,
 +};
 +
 +static int vt_notifier_call(struct notifier_block *,
 +                          unsigned long code, void *param);
 +
 +static struct notifier_block vt_notifier_block = {
 +      .notifier_call = vt_notifier_call,
 +};
 +
 +static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
 +{
 +      pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
 +      return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
 +}
 +
 +static void speakup_date(struct vc_data *vc)
 +{
-       old_cursor_x = vc->vc_x;
-       old_cursor_y = vc->vc_y;
-       speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
++      spk_x = spk_cx = vc->state.x;
++      spk_y = spk_cy = vc->state.y;
 +      spk_pos = spk_cp = vc->vc_pos;
 +      spk_old_attr = spk_attr;
 +      spk_attr = get_attributes(vc, (u_short *)spk_pos);
 +}
 +
 +static void bleep(u_short val)
 +{
 +      static const short vals[] = {
 +              350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
 +      };
 +      short freq;
 +      int time = spk_bleep_time;
 +
 +      freq = vals[val % 12];
 +      if (val > 11)
 +              freq *= (1 << (val / 12));
 +      spk_unprocessed_sound.freq = freq;
 +      spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
 +      spk_unprocessed_sound.active = 1;
 +      /* We can only have 1 active sound at a time. */
 +}
 +
 +static void speakup_shut_up(struct vc_data *vc)
 +{
 +      if (spk_killed)
 +              return;
 +      spk_shut_up |= 0x01;
 +      spk_parked &= 0xfe;
 +      speakup_date(vc);
 +      if (synth)
 +              spk_do_flush();
 +}
 +
 +static void speech_kill(struct vc_data *vc)
 +{
 +      char val = synth->is_alive(synth);
 +
 +      if (val == 0)
 +              return;
 +
 +      /* re-enables synth, if disabled */
 +      if (val == 2 || spk_killed) {
 +              /* dead */
 +              spk_shut_up &= ~0x40;
 +              synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
 +      } else {
 +              synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
 +              spk_shut_up |= 0x40;
 +      }
 +}
 +
 +static void speakup_off(struct vc_data *vc)
 +{
 +      if (spk_shut_up & 0x80) {
 +              spk_shut_up &= 0x7f;
 +              synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
 +      } else {
 +              spk_shut_up |= 0x80;
 +              synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
 +      }
 +      speakup_date(vc);
 +}
 +
 +static void speakup_parked(struct vc_data *vc)
 +{
 +      if (spk_parked & 0x80) {
 +              spk_parked = 0;
 +              synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
 +      } else {
 +              spk_parked |= 0x80;
 +              synth_printf("%s\n", spk_msg_get(MSG_PARKED));
 +      }
 +}
 +
 +static void speakup_cut(struct vc_data *vc)
 +{
 +      static const char err_buf[] = "set selection failed";
 +      int ret;
 +
 +      if (!mark_cut_flag) {
 +              mark_cut_flag = 1;
 +              spk_xs = (u_short)spk_x;
 +              spk_ys = (u_short)spk_y;
 +              spk_sel_cons = vc;
 +              synth_printf("%s\n", spk_msg_get(MSG_MARK));
 +              return;
 +      }
 +      spk_xe = (u_short)spk_x;
 +      spk_ye = (u_short)spk_y;
 +      mark_cut_flag = 0;
 +      synth_printf("%s\n", spk_msg_get(MSG_CUT));
 +
 +      speakup_clear_selection();
 +      ret = speakup_set_selection(tty);
 +
 +      switch (ret) {
 +      case 0:
 +              break;          /* no error */
 +      case -EFAULT:
 +              pr_warn("%sEFAULT\n", err_buf);
 +              break;
 +      case -EINVAL:
 +              pr_warn("%sEINVAL\n", err_buf);
 +              break;
 +      case -ENOMEM:
 +              pr_warn("%sENOMEM\n", err_buf);
 +              break;
 +      }
 +}
 +
 +static void speakup_paste(struct vc_data *vc)
 +{
 +      if (mark_cut_flag) {
 +              mark_cut_flag = 0;
 +              synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
 +      } else {
 +              synth_printf("%s\n", spk_msg_get(MSG_PASTE));
 +              speakup_paste_selection(tty);
 +      }
 +}
 +
 +static void say_attributes(struct vc_data *vc)
 +{
 +      int fg = spk_attr & 0x0f;
 +      int bg = spk_attr >> 4;
 +
 +      if (fg > 8) {
 +              synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
 +              fg -= 8;
 +      }
 +      synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
 +      if (bg > 7) {
 +              synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
 +              bg -= 8;
 +      } else {
 +              synth_printf(" %s ", spk_msg_get(MSG_ON));
 +      }
 +      synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
 +}
 +
 +enum {
 +      edge_top = 1,
 +      edge_bottom,
 +      edge_left,
 +      edge_right,
 +      edge_quiet
 +};
 +
 +static void announce_edge(struct vc_data *vc, int msg_id)
 +{
 +      if (spk_bleeps & 1)
 +              bleep(spk_y);
 +      if ((spk_bleeps & 2) && (msg_id < edge_quiet))
 +              synth_printf("%s\n",
 +                           spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
 +}
 +
 +static void speak_char(u16 ch)
 +{
 +      char *cp;
 +      struct var_t *direct = spk_get_var(DIRECT);
 +
 +      if (ch >= 0x100 || (direct && direct->u.n.value)) {
 +              if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
 +                      spk_pitch_shift++;
 +                      synth_printf("%s", spk_str_caps_start);
 +              }
 +              synth_putwc_s(ch);
 +              if (ch < 0x100 && IS_CHAR(ch, B_CAP))
 +                      synth_printf("%s", spk_str_caps_stop);
 +              return;
 +      }
 +
 +      cp = spk_characters[ch];
 +      if (!cp) {
 +              pr_info("%s: cp == NULL!\n", __func__);
 +              return;
 +      }
 +      if (IS_CHAR(ch, B_CAP)) {
 +              spk_pitch_shift++;
 +              synth_printf("%s %s %s",
 +                           spk_str_caps_start, cp, spk_str_caps_stop);
 +      } else {
 +              if (*cp == '^') {
 +                      cp++;
 +                      synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
 +              } else {
 +                      synth_printf(" %s ", cp);
 +              }
 +      }
 +}
 +
 +static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
 +{
 +      u16 ch = ' ';
 +
 +      if (vc && pos) {
 +              u16 w;
 +              u16 c;
 +
 +              pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
 +              w = scr_readw(pos);
 +              c = w & 0xff;
 +
 +              if (w & vc->vc_hi_font_mask) {
 +                      w &= ~vc->vc_hi_font_mask;
 +                      c |= 0x100;
 +              }
 +
 +              ch = inverse_translate(vc, c, 1);
 +              *attribs = (w & 0xff00) >> 8;
 +      }
 +      return ch;
 +}
 +
 +static void say_char(struct vc_data *vc)
 +{
 +      u16 ch;
 +
 +      spk_old_attr = spk_attr;
 +      ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
 +      if (spk_attr != spk_old_attr) {
 +              if (spk_attrib_bleep & 1)
 +                      bleep(spk_y);
 +              if (spk_attrib_bleep & 2)
 +                      say_attributes(vc);
 +      }
 +      speak_char(ch);
 +}
 +
 +static void say_phonetic_char(struct vc_data *vc)
 +{
 +      u16 ch;
 +
 +      spk_old_attr = spk_attr;
 +      ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
 +      if (ch <= 0x7f && isalpha(ch)) {
 +              ch &= 0x1f;
 +              synth_printf("%s\n", phonetic[--ch]);
 +      } else {
 +              if (ch < 0x100 && IS_CHAR(ch, B_NUM))
 +                      synth_printf("%s ", spk_msg_get(MSG_NUMBER));
 +              speak_char(ch);
 +      }
 +}
 +
 +static void say_prev_char(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      if (spk_x == 0) {
 +              announce_edge(vc, edge_left);
 +              return;
 +      }
 +      spk_x--;
 +      spk_pos -= 2;
 +      say_char(vc);
 +}
 +
 +static void say_next_char(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      if (spk_x == vc->vc_cols - 1) {
 +              announce_edge(vc, edge_right);
 +              return;
 +      }
 +      spk_x++;
 +      spk_pos += 2;
 +      say_char(vc);
 +}
 +
 +/* get_word - will first check to see if the character under the
 + * reading cursor is a space and if spk_say_word_ctl is true it will
 + * return the word space.  If spk_say_word_ctl is not set it will check to
 + * see if there is a word starting on the next position to the right
 + * and return that word if it exists.  If it does not exist it will
 + * move left to the beginning of any previous word on the line or the
 + * beginning off the line whichever comes first..
 + */
 +
 +static u_long get_word(struct vc_data *vc)
 +{
 +      u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
 +      u16 ch;
 +      u16 attr_ch;
 +      u_char temp;
 +
 +      spk_old_attr = spk_attr;
 +      ch = get_char(vc, (u_short *)tmp_pos, &temp);
 +
 +/* decided to take out the sayword if on a space (mis-information */
 +      if (spk_say_word_ctl && ch == SPACE) {
 +              *buf = '\0';
 +              synth_printf("%s\n", spk_msg_get(MSG_SPACE));
 +              return 0;
 +      } else if (tmpx < vc->vc_cols - 2 &&
 +                 (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
 +                 get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
 +              tmp_pos += 2;
 +              tmpx++;
 +      } else {
 +              while (tmpx > 0) {
 +                      ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
 +                      if ((ch == SPACE || ch == 0 ||
 +                           (ch < 0x100 && IS_WDLM(ch))) &&
 +                          get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
 +                              break;
 +                      tmp_pos -= 2;
 +                      tmpx--;
 +              }
 +      }
 +      attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
 +      buf[cnt++] = attr_ch;
 +      while (tmpx < vc->vc_cols - 1) {
 +              tmp_pos += 2;
 +              tmpx++;
 +              ch = get_char(vc, (u_short *)tmp_pos, &temp);
 +              if (ch == SPACE || ch == 0 ||
 +                  (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
 +                   ch > SPACE))
 +                      break;
 +              buf[cnt++] = ch;
 +      }
 +      buf[cnt] = '\0';
 +      return cnt;
 +}
 +
 +static void say_word(struct vc_data *vc)
 +{
 +      u_long cnt = get_word(vc);
 +      u_short saved_punc_mask = spk_punc_mask;
 +
 +      if (cnt == 0)
 +              return;
 +      spk_punc_mask = PUNC;
 +      buf[cnt++] = SPACE;
 +      spkup_write(buf, cnt);
 +      spk_punc_mask = saved_punc_mask;
 +}
 +
 +static void say_prev_word(struct vc_data *vc)
 +{
 +      u_char temp;
 +      u16 ch;
 +      u_short edge_said = 0, last_state = 0, state = 0;
 +
 +      spk_parked |= 0x01;
 +
 +      if (spk_x == 0) {
 +              if (spk_y == 0) {
 +                      announce_edge(vc, edge_top);
 +                      return;
 +              }
 +              spk_y--;
 +              spk_x = vc->vc_cols;
 +              edge_said = edge_quiet;
 +      }
 +      while (1) {
 +              if (spk_x == 0) {
 +                      if (spk_y == 0) {
 +                              edge_said = edge_top;
 +                              break;
 +                      }
 +                      if (edge_said != edge_quiet)
 +                              edge_said = edge_left;
 +                      if (state > 0)
 +                              break;
 +                      spk_y--;
 +                      spk_x = vc->vc_cols - 1;
 +              } else {
 +                      spk_x--;
 +              }
 +              spk_pos -= 2;
 +              ch = get_char(vc, (u_short *)spk_pos, &temp);
 +              if (ch == SPACE || ch == 0)
 +                      state = 0;
 +              else if (ch < 0x100 && IS_WDLM(ch))
 +                      state = 1;
 +              else
 +                      state = 2;
 +              if (state < last_state) {
 +                      spk_pos += 2;
 +                      spk_x++;
 +                      break;
 +              }
 +              last_state = state;
 +      }
 +      if (spk_x == 0 && edge_said == edge_quiet)
 +              edge_said = edge_left;
 +      if (edge_said > 0 && edge_said < edge_quiet)
 +              announce_edge(vc, edge_said);
 +      say_word(vc);
 +}
 +
 +static void say_next_word(struct vc_data *vc)
 +{
 +      u_char temp;
 +      u16 ch;
 +      u_short edge_said = 0, last_state = 2, state = 0;
 +
 +      spk_parked |= 0x01;
 +      if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
 +              announce_edge(vc, edge_bottom);
 +              return;
 +      }
 +      while (1) {
 +              ch = get_char(vc, (u_short *)spk_pos, &temp);
 +              if (ch == SPACE || ch == 0)
 +                      state = 0;
 +              else if (ch < 0x100 && IS_WDLM(ch))
 +                      state = 1;
 +              else
 +                      state = 2;
 +              if (state > last_state)
 +                      break;
 +              if (spk_x >= vc->vc_cols - 1) {
 +                      if (spk_y == vc->vc_rows - 1) {
 +                              edge_said = edge_bottom;
 +                              break;
 +                      }
 +                      state = 0;
 +                      spk_y++;
 +                      spk_x = 0;
 +                      edge_said = edge_right;
 +              } else {
 +                      spk_x++;
 +              }
 +              spk_pos += 2;
 +              last_state = state;
 +      }
 +      if (edge_said > 0)
 +              announce_edge(vc, edge_said);
 +      say_word(vc);
 +}
 +
 +static void spell_word(struct vc_data *vc)
 +{
 +      static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
 +      u16 *cp = buf;
 +      char *cp1;
 +      char *str_cap = spk_str_caps_stop;
 +      char *last_cap = spk_str_caps_stop;
 +      struct var_t *direct = spk_get_var(DIRECT);
 +      u16 ch;
 +
 +      if (!get_word(vc))
 +              return;
 +      while ((ch = *cp)) {
 +              if (cp != buf)
 +                      synth_printf(" %s ", delay_str[spk_spell_delay]);
 +              /* FIXME: Non-latin1 considered as lower case */
 +              if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
 +                      str_cap = spk_str_caps_start;
 +                      if (*spk_str_caps_stop)
 +                              spk_pitch_shift++;
 +                      else    /* synth has no pitch */
 +                              last_cap = spk_str_caps_stop;
 +              } else {
 +                      str_cap = spk_str_caps_stop;
 +              }
 +              if (str_cap != last_cap) {
 +                      synth_printf("%s", str_cap);
 +                      last_cap = str_cap;
 +              }
 +              if (ch >= 0x100 || (direct && direct->u.n.value)) {
 +                      synth_putwc_s(ch);
 +              } else if (this_speakup_key == SPELL_PHONETIC &&
 +                  ch <= 0x7f && isalpha(ch)) {
 +                      ch &= 0x1f;
 +                      cp1 = phonetic[--ch];
 +                      synth_printf("%s", cp1);
 +              } else {
 +                      cp1 = spk_characters[ch];
 +                      if (*cp1 == '^') {
 +                              synth_printf("%s", spk_msg_get(MSG_CTRL));
 +                              cp1++;
 +                      }
 +                      synth_printf("%s", cp1);
 +              }
 +              cp++;
 +      }
 +      if (str_cap != spk_str_caps_stop)
 +              synth_printf("%s", spk_str_caps_stop);
 +}
 +
 +static int get_line(struct vc_data *vc)
 +{
 +      u_long tmp = spk_pos - (spk_x * 2);
 +      int i = 0;
 +      u_char tmp2;
 +
 +      spk_old_attr = spk_attr;
 +      spk_attr = get_attributes(vc, (u_short *)spk_pos);
 +      for (i = 0; i < vc->vc_cols; i++) {
 +              buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
 +              tmp += 2;
 +      }
 +      for (--i; i >= 0; i--)
 +              if (buf[i] != SPACE)
 +                      break;
 +      return ++i;
 +}
 +
 +static void say_line(struct vc_data *vc)
 +{
 +      int i = get_line(vc);
 +      u16 *cp;
 +      u_short saved_punc_mask = spk_punc_mask;
 +
 +      if (i == 0) {
 +              synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 +              return;
 +      }
 +      buf[i++] = '\n';
 +      if (this_speakup_key == SAY_LINE_INDENT) {
 +              cp = buf;
 +              while (*cp == SPACE)
 +                      cp++;
 +              synth_printf("%zd, ", (cp - buf) + 1);
 +      }
 +      spk_punc_mask = spk_punc_masks[spk_reading_punc];
 +      spkup_write(buf, i);
 +      spk_punc_mask = saved_punc_mask;
 +}
 +
 +static void say_prev_line(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      if (spk_y == 0) {
 +              announce_edge(vc, edge_top);
 +              return;
 +      }
 +      spk_y--;
 +      spk_pos -= vc->vc_size_row;
 +      say_line(vc);
 +}
 +
 +static void say_next_line(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      if (spk_y == vc->vc_rows - 1) {
 +              announce_edge(vc, edge_bottom);
 +              return;
 +      }
 +      spk_y++;
 +      spk_pos += vc->vc_size_row;
 +      say_line(vc);
 +}
 +
 +static int say_from_to(struct vc_data *vc, u_long from, u_long to,
 +                     int read_punc)
 +{
 +      int i = 0;
 +      u_char tmp;
 +      u_short saved_punc_mask = spk_punc_mask;
 +
 +      spk_old_attr = spk_attr;
 +      spk_attr = get_attributes(vc, (u_short *)from);
 +      while (from < to) {
 +              buf[i++] = get_char(vc, (u_short *)from, &tmp);
 +              from += 2;
 +              if (i >= vc->vc_size_row)
 +                      break;
 +      }
 +      for (--i; i >= 0; i--)
 +              if (buf[i] != SPACE)
 +                      break;
 +      buf[++i] = SPACE;
 +      buf[++i] = '\0';
 +      if (i < 1)
 +              return i;
 +      if (read_punc)
 +              spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
 +      spkup_write(buf, i);
 +      if (read_punc)
 +              spk_punc_mask = saved_punc_mask;
 +      return i - 1;
 +}
 +
 +static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
 +                           int read_punc)
 +{
 +      u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
 +      u_long end = start + (to * 2);
 +
 +      start += from * 2;
 +      if (say_from_to(vc, start, end, read_punc) <= 0)
 +              if (cursor_track != read_all_mode)
 +                      synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 +}
 +
 +/* Sentence Reading Commands */
 +
 +static int currsentence;
 +static int numsentences[2];
 +static u16 *sentbufend[2];
 +static u16 *sentmarks[2][10];
 +static int currbuf;
 +static int bn;
 +static u16 sentbuf[2][256];
 +
 +static int say_sentence_num(int num, int prev)
 +{
 +      bn = currbuf;
 +      currsentence = num + 1;
 +      if (prev && --bn == -1)
 +              bn = 1;
 +
 +      if (num > numsentences[bn])
 +              return 0;
 +
 +      spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
 +      return 1;
 +}
 +
 +static int get_sentence_buf(struct vc_data *vc, int read_punc)
 +{
 +      u_long start, end;
 +      int i, bn;
 +      u_char tmp;
 +
 +      currbuf++;
 +      if (currbuf == 2)
 +              currbuf = 0;
 +      bn = currbuf;
 +      start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
 +      end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
 +
 +      numsentences[bn] = 0;
 +      sentmarks[bn][0] = &sentbuf[bn][0];
 +      i = 0;
 +      spk_old_attr = spk_attr;
 +      spk_attr = get_attributes(vc, (u_short *)start);
 +
 +      while (start < end) {
 +              sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
 +              if (i > 0) {
 +                      if (sentbuf[bn][i] == SPACE &&
 +                          sentbuf[bn][i - 1] == '.' &&
 +                          numsentences[bn] < 9) {
 +                              /* Sentence Marker */
 +                              numsentences[bn]++;
 +                              sentmarks[bn][numsentences[bn]] =
 +                                  &sentbuf[bn][i];
 +                      }
 +              }
 +              i++;
 +              start += 2;
 +              if (i >= vc->vc_size_row)
 +                      break;
 +      }
 +
 +      for (--i; i >= 0; i--)
 +              if (sentbuf[bn][i] != SPACE)
 +                      break;
 +
 +      if (i < 1)
 +              return -1;
 +
 +      sentbuf[bn][++i] = SPACE;
 +      sentbuf[bn][++i] = '\0';
 +
 +      sentbufend[bn] = &sentbuf[bn][i];
 +      return numsentences[bn];
 +}
 +
 +static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
 +{
 +      u_long start = vc->vc_origin, end;
 +
 +      if (from > 0)
 +              start += from * vc->vc_size_row;
 +      if (to > vc->vc_rows)
 +              to = vc->vc_rows;
 +      end = vc->vc_origin + (to * vc->vc_size_row);
 +      for (from = start; from < end; from = to) {
 +              to = from + vc->vc_size_row;
 +              say_from_to(vc, from, to, 1);
 +      }
 +}
 +
 +static void say_screen(struct vc_data *vc)
 +{
 +      say_screen_from_to(vc, 0, vc->vc_rows);
 +}
 +
 +static void speakup_win_say(struct vc_data *vc)
 +{
 +      u_long start, end, from, to;
 +
 +      if (win_start < 2) {
 +              synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
 +              return;
 +      }
 +      start = vc->vc_origin + (win_top * vc->vc_size_row);
 +      end = vc->vc_origin + (win_bottom * vc->vc_size_row);
 +      while (start <= end) {
 +              from = start + (win_left * 2);
 +              to = start + (win_right * 2);
 +              say_from_to(vc, from, to, 1);
 +              start += vc->vc_size_row;
 +      }
 +}
 +
 +static void top_edge(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      spk_pos = vc->vc_origin + 2 * spk_x;
 +      spk_y = 0;
 +      say_line(vc);
 +}
 +
 +static void bottom_edge(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
 +      spk_y = vc->vc_rows - 1;
 +      say_line(vc);
 +}
 +
 +static void left_edge(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      spk_pos -= spk_x * 2;
 +      spk_x = 0;
 +      say_char(vc);
 +}
 +
 +static void right_edge(struct vc_data *vc)
 +{
 +      spk_parked |= 0x01;
 +      spk_pos += (vc->vc_cols - spk_x - 1) * 2;
 +      spk_x = vc->vc_cols - 1;
 +      say_char(vc);
 +}
 +
 +static void say_first_char(struct vc_data *vc)
 +{
 +      int i, len = get_line(vc);
 +      u16 ch;
 +
 +      spk_parked |= 0x01;
 +      if (len == 0) {
 +              synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 +              return;
 +      }
 +      for (i = 0; i < len; i++)
 +              if (buf[i] != SPACE)
 +                      break;
 +      ch = buf[i];
 +      spk_pos -= (spk_x - i) * 2;
 +      spk_x = i;
 +      synth_printf("%d, ", ++i);
 +      speak_char(ch);
 +}
 +
 +static void say_last_char(struct vc_data *vc)
 +{
 +      int len = get_line(vc);
 +      u16 ch;
 +
 +      spk_parked |= 0x01;
 +      if (len == 0) {
 +              synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 +              return;
 +      }
 +      ch = buf[--len];
 +      spk_pos -= (spk_x - len) * 2;
 +      spk_x = len;
 +      synth_printf("%d, ", ++len);
 +      speak_char(ch);
 +}
 +
 +static void say_position(struct vc_data *vc)
 +{
 +      synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
 +                   vc->vc_num + 1);
 +      synth_printf("\n");
 +}
 +
 +/* Added by brianb */
 +static void say_char_num(struct vc_data *vc)
 +{
 +      u_char tmp;
 +      u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
 +
 +      synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
 +}
 +
 +/* these are stub functions to keep keyboard.c happy. */
 +
 +static void say_from_top(struct vc_data *vc)
 +{
 +      say_screen_from_to(vc, 0, spk_y);
 +}
 +
 +static void say_to_bottom(struct vc_data *vc)
 +{
 +      say_screen_from_to(vc, spk_y, vc->vc_rows);
 +}
 +
 +static void say_from_left(struct vc_data *vc)
 +{
 +      say_line_from_to(vc, 0, spk_x, 1);
 +}
 +
 +static void say_to_right(struct vc_data *vc)
 +{
 +      say_line_from_to(vc, spk_x, vc->vc_cols, 1);
 +}
 +
 +/* end of stub functions. */
 +
 +static void spkup_write(const u16 *in_buf, int count)
 +{
 +      static int rep_count;
 +      static u16 ch = '\0', old_ch = '\0';
 +      static u_short char_type, last_type;
 +      int in_count = count;
 +
 +      spk_keydown = 0;
 +      while (count--) {
 +              if (cursor_track == read_all_mode) {
 +                      /* Insert Sentence Index */
 +                      if ((in_buf == sentmarks[bn][currsentence]) &&
 +                          (currsentence <= numsentences[bn]))
 +                              synth_insert_next_index(currsentence++);
 +              }
 +              ch = *in_buf++;
 +              if (ch < 0x100)
 +                      char_type = spk_chartab[ch];
 +              else
 +                      char_type = ALPHA;
 +              if (ch == old_ch && !(char_type & B_NUM)) {
 +                      if (++rep_count > 2)
 +                              continue;
 +              } else {
 +                      if ((last_type & CH_RPT) && rep_count > 2) {
 +                              synth_printf(" ");
 +                              synth_printf(spk_msg_get(MSG_REPEAT_DESC),
 +                                           ++rep_count);
 +                              synth_printf(" ");
 +                      }
 +                      rep_count = 0;
 +              }
 +              if (ch == spk_lastkey) {
 +                      rep_count = 0;
 +                      if (spk_key_echo == 1 && ch >= MINECHOCHAR)
 +                              speak_char(ch);
 +              } else if (char_type & B_ALPHA) {
 +                      if ((synth_flags & SF_DEC) && (last_type & PUNC))
 +                              synth_buffer_add(SPACE);
 +                      synth_putwc_s(ch);
 +              } else if (char_type & B_NUM) {
 +                      rep_count = 0;
 +                      synth_putwc_s(ch);
 +              } else if (char_type & spk_punc_mask) {
 +                      speak_char(ch);
 +                      char_type &= ~PUNC;     /* for dec nospell processing */
 +              } else if (char_type & SYNTH_OK) {
 +                      /* these are usually puncts like . and , which synth
 +                       * needs for expression.
 +                       * suppress multiple to get rid of long pauses and
 +                       * clear repeat count
 +                       * so if someone has
 +                       * repeats on you don't get nothing repeated count
 +                       */
 +                      if (ch != old_ch)
 +                              synth_putwc_s(ch);
 +                      else
 +                              rep_count = 0;
 +              } else {
 +/* send space and record position, if next is num overwrite space */
 +                      if (old_ch != ch)
 +                              synth_buffer_add(SPACE);
 +                      else
 +                              rep_count = 0;
 +              }
 +              old_ch = ch;
 +              last_type = char_type;
 +      }
 +      spk_lastkey = 0;
 +      if (in_count > 2 && rep_count > 2) {
 +              if (last_type & CH_RPT) {
 +                      synth_printf(" ");
 +                      synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
 +                                   ++rep_count);
 +                      synth_printf(" ");
 +              }
 +              rep_count = 0;
 +      }
 +}
 +
 +static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
 +
 +static void read_all_doc(struct vc_data *vc);
 +static void cursor_done(struct timer_list *unused);
 +static DEFINE_TIMER(cursor_timer, cursor_done);
 +
 +static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
 +{
 +      unsigned long flags;
 +
 +      if (!synth || up_flag || spk_killed)
 +              return;
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      if (cursor_track == read_all_mode) {
 +              switch (value) {
 +              case KVAL(K_SHIFT):
 +                      del_timer(&cursor_timer);
 +                      spk_shut_up &= 0xfe;
 +                      spk_do_flush();
 +                      read_all_doc(vc);
 +                      break;
 +              case KVAL(K_CTRL):
 +                      del_timer(&cursor_timer);
 +                      cursor_track = prev_cursor_track;
 +                      spk_shut_up &= 0xfe;
 +                      spk_do_flush();
 +                      break;
 +              }
 +      } else {
 +              spk_shut_up &= 0xfe;
 +              spk_do_flush();
 +      }
 +      if (spk_say_ctrl && value < NUM_CTL_LABELS)
 +              synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
 +{
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      if (up_flag) {
 +              spk_lastkey = 0;
 +              spk_keydown = 0;
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return;
 +      }
 +      if (!synth || spk_killed) {
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return;
 +      }
 +      spk_shut_up &= 0xfe;
 +      spk_lastkey = value;
 +      spk_keydown++;
 +      spk_parked &= 0xfe;
 +      if (spk_key_echo == 2 && value >= MINECHOCHAR)
 +              speak_char(value);
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
 +{
 +      int i = 0, states, key_data_len;
 +      const u_char *cp = key_info;
 +      u_char *cp1 = k_buffer;
 +      u_char ch, version, num_keys;
 +
 +      version = *cp++;
 +      if (version != KEY_MAP_VER) {
 +              pr_debug("version found %d should be %d\n",
 +                       version, KEY_MAP_VER);
 +              return -EINVAL;
 +      }
 +      num_keys = *cp;
 +      states = (int)cp[1];
 +      key_data_len = (states + 1) * (num_keys + 1);
 +      if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
 +              pr_debug("too many key_infos (%d over %u)\n",
 +                       key_data_len + SHIFT_TBL_SIZE + 4,
 +                       (unsigned int)(sizeof(spk_key_buf)));
 +              return -EINVAL;
 +      }
 +      memset(k_buffer, 0, SHIFT_TBL_SIZE);
 +      memset(spk_our_keys, 0, sizeof(spk_our_keys));
 +      spk_shift_table = k_buffer;
 +      spk_our_keys[0] = spk_shift_table;
 +      cp1 += SHIFT_TBL_SIZE;
 +      memcpy(cp1, cp, key_data_len + 3);
 +      /* get num_keys, states and data */
 +      cp1 += 2;               /* now pointing at shift states */
 +      for (i = 1; i <= states; i++) {
 +              ch = *cp1++;
 +              if (ch >= SHIFT_TBL_SIZE) {
 +                      pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
 +                               ch, SHIFT_TBL_SIZE);
 +                      return -EINVAL;
 +              }
 +              spk_shift_table[ch] = i;
 +      }
 +      keymap_flags = *cp1++;
 +      while ((ch = *cp1)) {
 +              if (ch >= MAX_KEY) {
 +                      pr_debug("(%d), not valid key, (max_allowed = %d)\n",
 +                               ch, MAX_KEY);
 +                      return -EINVAL;
 +              }
 +              spk_our_keys[ch] = cp1;
 +              cp1 += states + 1;
 +      }
 +      return 0;
 +}
 +
 +static struct var_t spk_vars[] = {
 +      /* bell must be first to set high limit */
 +      {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
 +      {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
 +      {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
 +      {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
 +      {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
 +      {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
 +      {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
 +      {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
 +      {SAY_CONTROL, TOGGLE_0},
 +      {SAY_WORD_CTL, TOGGLE_0},
 +      {NO_INTERRUPT, TOGGLE_0},
 +      {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
 +      V_LAST_VAR
 +};
 +
 +static void toggle_cursoring(struct vc_data *vc)
 +{
 +      if (cursor_track == read_all_mode)
 +              cursor_track = prev_cursor_track;
 +      if (++cursor_track >= CT_Max)
 +              cursor_track = 0;
 +      synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
 +}
 +
 +void spk_reset_default_chars(void)
 +{
 +      int i;
 +
 +      /* First, free any non-default */
 +      for (i = 0; i < 256; i++) {
 +              if (spk_characters[i] &&
 +                  (spk_characters[i] != spk_default_chars[i]))
 +                      kfree(spk_characters[i]);
 +      }
 +
 +      memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
 +}
 +
 +void spk_reset_default_chartab(void)
 +{
 +      memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
 +}
 +
 +static const struct st_bits_data *pb_edit;
 +
 +static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
 +{
 +      short mask = pb_edit->mask, ch_type = spk_chartab[ch];
 +
 +      if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
 +              return -1;
 +      if (ch == SPACE) {
 +              synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
 +              spk_special_handler = NULL;
 +              return 1;
 +      }
 +      if (mask < PUNC && !(ch_type & PUNC))
 +              return -1;
 +      spk_chartab[ch] ^= mask;
 +      speak_char(ch);
 +      synth_printf(" %s\n",
 +                   (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
 +                   spk_msg_get(MSG_OFF));
 +      return 1;
 +}
 +
 +/* Allocation concurrency is protected by the console semaphore */
 +static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
 +{
 +      int vc_num;
 +
 +      vc_num = vc->vc_num;
 +      if (!speakup_console[vc_num]) {
 +              speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
 +                                                gfp_flags);
 +              if (!speakup_console[vc_num])
 +                      return -ENOMEM;
 +              speakup_date(vc);
 +      } else if (!spk_parked) {
 +              speakup_date(vc);
 +      }
 +
 +      return 0;
 +}
 +
 +static void speakup_deallocate(struct vc_data *vc)
 +{
 +      int vc_num;
 +
 +      vc_num = vc->vc_num;
 +      kfree(speakup_console[vc_num]);
 +      speakup_console[vc_num] = NULL;
 +}
 +
 +static u_char is_cursor;
 +static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
 +static int cursor_con;
 +
 +static void reset_highlight_buffers(struct vc_data *);
 +
 +static int read_all_key;
 +
 +static int in_keyboard_notifier;
 +
 +static void start_read_all_timer(struct vc_data *vc, int command);
 +
 +enum {
 +      RA_NOTHING,
 +      RA_NEXT_SENT,
 +      RA_PREV_LINE,
 +      RA_NEXT_LINE,
 +      RA_PREV_SENT,
 +      RA_DOWN_ARROW,
 +      RA_TIMER,
 +      RA_FIND_NEXT_SENT,
 +      RA_FIND_PREV_SENT,
 +};
 +
 +static void kbd_fakekey2(struct vc_data *vc, int command)
 +{
 +      del_timer(&cursor_timer);
 +      speakup_fake_down_arrow();
 +      start_read_all_timer(vc, command);
 +}
 +
 +static void read_all_doc(struct vc_data *vc)
 +{
 +      if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
 +              return;
 +      if (!synth_supports_indexing())
 +              return;
 +      if (cursor_track != read_all_mode)
 +              prev_cursor_track = cursor_track;
 +      cursor_track = read_all_mode;
 +      spk_reset_index_count(0);
 +      if (get_sentence_buf(vc, 0) == -1) {
 +              del_timer(&cursor_timer);
 +              if (!in_keyboard_notifier)
 +                      speakup_fake_down_arrow();
 +              start_read_all_timer(vc, RA_DOWN_ARROW);
 +      } else {
 +              say_sentence_num(0, 0);
 +              synth_insert_next_index(0);
 +              start_read_all_timer(vc, RA_TIMER);
 +      }
 +}
 +
 +static void stop_read_all(struct vc_data *vc)
 +{
 +      del_timer(&cursor_timer);
 +      cursor_track = prev_cursor_track;
 +      spk_shut_up &= 0xfe;
 +      spk_do_flush();
 +}
 +
 +static void start_read_all_timer(struct vc_data *vc, int command)
 +{
 +      struct var_t *cursor_timeout;
 +
 +      cursor_con = vc->vc_num;
 +      read_all_key = command;
 +      cursor_timeout = spk_get_var(CURSOR_TIME);
 +      mod_timer(&cursor_timer,
 +                jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
 +}
 +
 +static void handle_cursor_read_all(struct vc_data *vc, int command)
 +{
 +      int indcount, sentcount, rv, sn;
 +
 +      switch (command) {
 +      case RA_NEXT_SENT:
 +              /* Get Current Sentence */
 +              spk_get_index_count(&indcount, &sentcount);
 +              /*printk("%d %d  ", indcount, sentcount); */
 +              spk_reset_index_count(sentcount + 1);
 +              if (indcount == 1) {
 +                      if (!say_sentence_num(sentcount + 1, 0)) {
 +                              kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
 +                              return;
 +                      }
 +                      synth_insert_next_index(0);
 +              } else {
 +                      sn = 0;
 +                      if (!say_sentence_num(sentcount + 1, 1)) {
 +                              sn = 1;
 +                              spk_reset_index_count(sn);
 +                      } else {
 +                              synth_insert_next_index(0);
 +                      }
 +                      if (!say_sentence_num(sn, 0)) {
 +                              kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
 +                              return;
 +                      }
 +                      synth_insert_next_index(0);
 +              }
 +              start_read_all_timer(vc, RA_TIMER);
 +              break;
 +      case RA_PREV_SENT:
 +              break;
 +      case RA_NEXT_LINE:
 +              read_all_doc(vc);
 +              break;
 +      case RA_PREV_LINE:
 +              break;
 +      case RA_DOWN_ARROW:
 +              if (get_sentence_buf(vc, 0) == -1) {
 +                      kbd_fakekey2(vc, RA_DOWN_ARROW);
 +              } else {
 +                      say_sentence_num(0, 0);
 +                      synth_insert_next_index(0);
 +                      start_read_all_timer(vc, RA_TIMER);
 +              }
 +              break;
 +      case RA_FIND_NEXT_SENT:
 +              rv = get_sentence_buf(vc, 0);
 +              if (rv == -1)
 +                      read_all_doc(vc);
 +              if (rv == 0) {
 +                      kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
 +              } else {
 +                      say_sentence_num(1, 0);
 +                      synth_insert_next_index(0);
 +                      start_read_all_timer(vc, RA_TIMER);
 +              }
 +              break;
 +      case RA_FIND_PREV_SENT:
 +              break;
 +      case RA_TIMER:
 +              spk_get_index_count(&indcount, &sentcount);
 +              if (indcount < 2)
 +                      kbd_fakekey2(vc, RA_DOWN_ARROW);
 +              else
 +                      start_read_all_timer(vc, RA_TIMER);
 +              break;
 +      }
 +}
 +
 +static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
 +{
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      if (cursor_track == read_all_mode) {
 +              spk_parked &= 0xfe;
 +              if (!synth || up_flag || spk_shut_up) {
 +                      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +                      return NOTIFY_STOP;
 +              }
 +              del_timer(&cursor_timer);
 +              spk_shut_up &= 0xfe;
 +              spk_do_flush();
 +              start_read_all_timer(vc, value + 1);
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return NOTIFY_STOP;
 +      }
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +      return NOTIFY_OK;
 +}
 +
 +static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
 +{
 +      unsigned long flags;
 +      struct var_t *cursor_timeout;
 +
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      spk_parked &= 0xfe;
 +      if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return;
 +      }
 +      spk_shut_up &= 0xfe;
 +      if (spk_no_intr)
 +              spk_do_flush();
 +/* the key press flushes if !no_inter but we want to flush on cursor
 + * moves regardless of no_inter state
 + */
 +      is_cursor = value + 1;
 +      old_cursor_pos = vc->vc_pos;
-               speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
-               speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
++      old_cursor_x = vc->state.x;
++      old_cursor_y = vc->state.y;
++      speakup_console[vc->vc_num]->ht.cy = vc->state.y;
 +      cursor_con = vc->vc_num;
 +      if (cursor_track == CT_Highlight)
 +              reset_highlight_buffers(vc);
 +      cursor_timeout = spk_get_var(CURSOR_TIME);
 +      mod_timer(&cursor_timer,
 +                jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
 +{
 +      int i, bi, hi;
 +      int vc_num = vc->vc_num;
 +
 +      bi = (vc->vc_attr & 0x70) >> 4;
 +      hi = speakup_console[vc_num]->ht.highsize[bi];
 +
 +      i = 0;
 +      if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
 +              speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
-               d = vc->vc_y - speakup_console[vc_num]->ht.cy;
++              speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
++              speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
 +      }
 +      while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
 +              if (ic[i] > 32) {
 +                      speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
 +                      hi++;
 +              } else if ((ic[i] == 32) && (hi != 0)) {
 +                      if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
 +                          32) {
 +                              speakup_console[vc_num]->ht.highbuf[bi][hi] =
 +                                  ic[i];
 +                              hi++;
 +                      }
 +              }
 +              i++;
 +      }
 +      speakup_console[vc_num]->ht.highsize[bi] = hi;
 +}
 +
 +static void reset_highlight_buffers(struct vc_data *vc)
 +{
 +      int i;
 +      int vc_num = vc->vc_num;
 +
 +      for (i = 0; i < 8; i++)
 +              speakup_console[vc_num]->ht.highsize[i] = 0;
 +}
 +
 +static int count_highlight_color(struct vc_data *vc)
 +{
 +      int i, bg;
 +      int cc;
 +      int vc_num = vc->vc_num;
 +      u16 ch;
 +      u16 *start = (u16 *)vc->vc_origin;
 +
 +      for (i = 0; i < 8; i++)
 +              speakup_console[vc_num]->ht.bgcount[i] = 0;
 +
 +      for (i = 0; i < vc->vc_rows; i++) {
 +              u16 *end = start + vc->vc_cols * 2;
 +              u16 *ptr;
 +
 +              for (ptr = start; ptr < end; ptr++) {
 +                      ch = get_attributes(vc, ptr);
 +                      bg = (ch & 0x70) >> 4;
 +                      speakup_console[vc_num]->ht.bgcount[bg]++;
 +              }
 +              start += vc->vc_size_row;
 +      }
 +
 +      cc = 0;
 +      for (i = 0; i < 8; i++)
 +              if (speakup_console[vc_num]->ht.bgcount[i] > 0)
 +                      cc++;
 +      return cc;
 +}
 +
 +static int get_highlight_color(struct vc_data *vc)
 +{
 +      int i, j;
 +      unsigned int cptr[8];
 +      int vc_num = vc->vc_num;
 +
 +      for (i = 0; i < 8; i++)
 +              cptr[i] = i;
 +
 +      for (i = 0; i < 7; i++)
 +              for (j = i + 1; j < 8; j++)
 +                      if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
 +                          speakup_console[vc_num]->ht.bgcount[cptr[j]])
 +                              swap(cptr[i], cptr[j]);
 +
 +      for (i = 0; i < 8; i++)
 +              if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
 +                      if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
 +                              return cptr[i];
 +      return -1;
 +}
 +
 +static int speak_highlight(struct vc_data *vc)
 +{
 +      int hc, d;
 +      int vc_num = vc->vc_num;
 +
 +      if (count_highlight_color(vc) == 1)
 +              return 0;
 +      hc = get_highlight_color(vc);
 +      if (hc != -1) {
-                       if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
++              d = vc->state.y - speakup_console[vc_num]->ht.cy;
 +              if ((d == 1) || (d == -1))
-               if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
-                   vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
++                      if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
 +                              return 0;
 +              spk_parked |= 0x01;
 +              spk_do_flush();
 +              spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
 +                          speakup_console[vc_num]->ht.highsize[hc]);
 +              spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
 +              spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
 +              spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +static void cursor_done(struct timer_list *unused)
 +{
 +      struct vc_data *vc = vc_cons[cursor_con].d;
 +      unsigned long flags;
 +
 +      del_timer(&cursor_timer);
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      if (cursor_con != fg_console) {
 +              is_cursor = 0;
 +              goto out;
 +      }
 +      speakup_date(vc);
 +      if (win_enabled) {
-       if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
++              if (vc->state.x >= win_left && vc->state.x <= win_right &&
++                  vc->state.y >= win_top && vc->state.y <= win_bottom) {
 +                      spk_keydown = 0;
 +                      is_cursor = 0;
 +                      goto out;
 +              }
 +      }
 +      if (cursor_track == read_all_mode) {
 +              handle_cursor_read_all(vc, read_all_key);
 +              goto out;
 +      }
 +      if (cursor_track == CT_Highlight) {
 +              if (speak_highlight(vc)) {
 +                      spk_keydown = 0;
 +                      is_cursor = 0;
 +                      goto out;
 +              }
 +      }
 +      if (cursor_track == CT_Window)
 +              speakup_win_say(vc);
 +      else if (is_cursor == 1 || is_cursor == 4)
 +              say_line_from_to(vc, 0, vc->vc_cols, 0);
 +      else
 +              say_char(vc);
 +      spk_keydown = 0;
 +      is_cursor = 0;
 +out:
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +/* called by: vt_notifier_call() */
 +static void speakup_bs(struct vc_data *vc)
 +{
 +      unsigned long flags;
 +
 +      if (!speakup_console[vc->vc_num])
 +              return;
 +      if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
 +              /* Speakup output, discard */
 +              return;
 +      if (!spk_parked)
 +              speakup_date(vc);
 +      if (spk_shut_up || !synth) {
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return;
 +      }
 +      if (vc->vc_num == fg_console && spk_keydown) {
 +              spk_keydown = 0;
 +              if (!is_cursor)
 +                      say_char(vc);
 +      }
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +/* called by: vt_notifier_call() */
 +static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
 +{
 +      unsigned long flags;
 +
 +      if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
 +              return;
 +      if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
 +              /* Speakup output, discard */
 +              return;
-               if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
-                   vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
++      if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
 +              bleep(3);
 +      if ((is_cursor) || (cursor_track == read_all_mode)) {
 +              if (cursor_track == CT_Highlight)
 +                      update_color_buffer(vc, str, len);
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return;
 +      }
 +      if (win_enabled) {
++              if (vc->state.x >= win_left && vc->state.x <= win_right &&
++                  vc->state.y >= win_top && vc->state.y <= win_bottom) {
 +                      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +                      return;
 +              }
 +      }
 +
 +      spkup_write(str, len);
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +static void speakup_con_update(struct vc_data *vc)
 +{
 +      unsigned long flags;
 +
 +      if (!speakup_console[vc->vc_num] || spk_parked)
 +              return;
 +      if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
 +              /* Speakup output, discard */
 +              return;
 +      speakup_date(vc);
 +      if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
 +              synth_printf("%s", spk_str_pause);
 +              spk_paused = true;
 +      }
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
 +{
 +      unsigned long flags;
 +      int on_off = 2;
 +      char *label;
 +
 +      if (!synth || up_flag || spk_killed)
 +              return;
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      spk_shut_up &= 0xfe;
 +      if (spk_no_intr)
 +              spk_do_flush();
 +      switch (value) {
 +      case KVAL(K_CAPS):
 +              label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
 +              on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
 +              break;
 +      case KVAL(K_NUM):
 +              label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
 +              on_off = vt_get_leds(fg_console, VC_NUMLOCK);
 +              break;
 +      case KVAL(K_HOLD):
 +              label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
 +              on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
 +              if (speakup_console[vc->vc_num])
 +                      speakup_console[vc->vc_num]->tty_stopped = on_off;
 +              break;
 +      default:
 +              spk_parked &= 0xfe;
 +              spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +              return;
 +      }
 +      if (on_off < 2)
 +              synth_printf("%s %s\n",
 +                           label, spk_msg_get(MSG_STATUS_START + on_off));
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +}
 +
 +static int inc_dec_var(u_char value)
 +{
 +      struct st_var_header *p_header;
 +      struct var_t *var_data;
 +      char num_buf[32];
 +      char *cp = num_buf;
 +      char *pn;
 +      int var_id = (int)value - VAR_START;
 +      int how = (var_id & 1) ? E_INC : E_DEC;
 +
 +      var_id = var_id / 2 + FIRST_SET_VAR;
 +      p_header = spk_get_var_header(var_id);
 +      if (!p_header)
 +              return -1;
 +      if (p_header->var_type != VAR_NUM)
 +              return -1;
 +      var_data = p_header->data;
 +      if (spk_set_num_var(1, p_header, how) != 0)
 +              return -1;
 +      if (!spk_close_press) {
 +              for (pn = p_header->name; *pn; pn++) {
 +                      if (*pn == '_')
 +                              *cp = SPACE;
 +                      else
 +                              *cp++ = *pn;
 +              }
 +      }
 +      snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
 +               var_data->u.n.value);
 +      synth_printf("%s", num_buf);
 +      return 0;
 +}
 +
 +static void speakup_win_set(struct vc_data *vc)
 +{
 +      char info[40];
 +
 +      if (win_start > 1) {
 +              synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
 +              return;
 +      }
 +      if (spk_x < win_left || spk_y < win_top) {
 +              synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
 +              return;
 +      }
 +      if (win_start && spk_x == win_left && spk_y == win_top) {
 +              win_left = 0;
 +              win_right = vc->vc_cols - 1;
 +              win_bottom = spk_y;
 +              snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
 +                       (int)win_top + 1);
 +      } else {
 +              if (!win_start) {
 +                      win_top = spk_y;
 +                      win_left = spk_x;
 +              } else {
 +                      win_bottom = spk_y;
 +                      win_right = spk_x;
 +              }
 +              snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
 +                       (win_start) ?
 +                              spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
 +                       (int)spk_y + 1, (int)spk_x + 1);
 +      }
 +      synth_printf("%s\n", info);
 +      win_start++;
 +}
 +
 +static void speakup_win_clear(struct vc_data *vc)
 +{
 +      win_top = 0;
 +      win_bottom = 0;
 +      win_left = 0;
 +      win_right = 0;
 +      win_start = 0;
 +      synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
 +}
 +
 +static void speakup_win_enable(struct vc_data *vc)
 +{
 +      if (win_start < 2) {
 +              synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
 +              return;
 +      }
 +      win_enabled ^= 1;
 +      if (win_enabled)
 +              synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
 +      else
 +              synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
 +}
 +
 +static void speakup_bits(struct vc_data *vc)
 +{
 +      int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
 +
 +      if (spk_special_handler || val < 1 || val > 6) {
 +              synth_printf("%s\n", spk_msg_get(MSG_ERROR));
 +              return;
 +      }
 +      pb_edit = &spk_punc_info[val];
 +      synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
 +      spk_special_handler = edit_bits;
 +}
 +
 +static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
 +{
 +      static u_char goto_buf[8];
 +      static int num;
 +      int maxlen;
 +      char *cp;
 +      u16 wch;
 +
 +      if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
 +              goto do_goto;
 +      if (type == KT_LATIN && ch == '\n')
 +              goto do_goto;
 +      if (type != 0)
 +              goto oops;
 +      if (ch == 8) {
 +              u16 wch;
 +
 +              if (num == 0)
 +                      return -1;
 +              wch = goto_buf[--num];
 +              goto_buf[num] = '\0';
 +              spkup_write(&wch, 1);
 +              return 1;
 +      }
 +      if (ch < '+' || ch > 'y')
 +              goto oops;
 +      wch = ch;
 +      goto_buf[num++] = ch;
 +      goto_buf[num] = '\0';
 +      spkup_write(&wch, 1);
 +      maxlen = (*goto_buf >= '0') ? 3 : 4;
 +      if ((ch == '+' || ch == '-') && num == 1)
 +              return 1;
 +      if (ch >= '0' && ch <= '9' && num < maxlen)
 +              return 1;
 +      if (num < maxlen - 1 || num > maxlen)
 +              goto oops;
 +      if (ch < 'x' || ch > 'y') {
 +oops:
 +              if (!spk_killed)
 +                      synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
 +              goto_buf[num = 0] = '\0';
 +              spk_special_handler = NULL;
 +              return 1;
 +      }
 +
 +      /* Do not replace with kstrtoul: here we need cp to be updated */
 +      goto_pos = simple_strtoul(goto_buf, &cp, 10);
 +
 +      if (*cp == 'x') {
 +              if (*goto_buf < '0')
 +                      goto_pos += spk_x;
 +              else if (goto_pos > 0)
 +                      goto_pos--;
 +
 +              if (goto_pos >= vc->vc_cols)
 +                      goto_pos = vc->vc_cols - 1;
 +              goto_x = 1;
 +      } else {
 +              if (*goto_buf < '0')
 +                      goto_pos += spk_y;
 +              else if (goto_pos > 0)
 +                      goto_pos--;
 +
 +              if (goto_pos >= vc->vc_rows)
 +                      goto_pos = vc->vc_rows - 1;
 +              goto_x = 0;
 +      }
 +      goto_buf[num = 0] = '\0';
 +do_goto:
 +      spk_special_handler = NULL;
 +      spk_parked |= 0x01;
 +      if (goto_x) {
 +              spk_pos -= spk_x * 2;
 +              spk_x = goto_pos;
 +              spk_pos += goto_pos * 2;
 +              say_word(vc);
 +      } else {
 +              spk_y = goto_pos;
 +              spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
 +              say_line(vc);
 +      }
 +      return 1;
 +}
 +
 +static void speakup_goto(struct vc_data *vc)
 +{
 +      if (spk_special_handler) {
 +              synth_printf("%s\n", spk_msg_get(MSG_ERROR));
 +              return;
 +      }
 +      synth_printf("%s\n", spk_msg_get(MSG_GOTO));
 +      spk_special_handler = handle_goto;
 +}
 +
 +static void speakup_help(struct vc_data *vc)
 +{
 +      spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
 +}
 +
 +static void do_nothing(struct vc_data *vc)
 +{
 +      return;                 /* flush done in do_spkup */
 +}
 +
 +static u_char key_speakup, spk_key_locked;
 +
 +static void speakup_lock(struct vc_data *vc)
 +{
 +      if (!spk_key_locked) {
 +              spk_key_locked = 16;
 +              key_speakup = 16;
 +      } else {
 +              spk_key_locked = 0;
 +              key_speakup = 0;
 +      }
 +}
 +
 +typedef void (*spkup_hand) (struct vc_data *);
 +static spkup_hand spkup_handler[] = {
 +      /* must be ordered same as defines in speakup.h */
 +      do_nothing, speakup_goto, speech_kill, speakup_shut_up,
 +      speakup_cut, speakup_paste, say_first_char, say_last_char,
 +      say_char, say_prev_char, say_next_char,
 +      say_word, say_prev_word, say_next_word,
 +      say_line, say_prev_line, say_next_line,
 +      top_edge, bottom_edge, left_edge, right_edge,
 +      spell_word, spell_word, say_screen,
 +      say_position, say_attributes,
 +      speakup_off, speakup_parked, say_line,  /* this is for indent */
 +      say_from_top, say_to_bottom,
 +      say_from_left, say_to_right,
 +      say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
 +      speakup_bits, speakup_bits, speakup_bits,
 +      speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
 +      speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
 +};
 +
 +static void do_spkup(struct vc_data *vc, u_char value)
 +{
 +      if (spk_killed && value != SPEECH_KILL)
 +              return;
 +      spk_keydown = 0;
 +      spk_lastkey = 0;
 +      spk_shut_up &= 0xfe;
 +      this_speakup_key = value;
 +      if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
 +              spk_do_flush();
 +              (*spkup_handler[value]) (vc);
 +      } else {
 +              if (inc_dec_var(value) < 0)
 +                      bleep(9);
 +      }
 +}
 +
 +static const char *pad_chars = "0123456789+-*/\015,.?()";
 +
 +static int
 +speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
 +          int up_flag)
 +{
 +      unsigned long flags;
 +      int kh;
 +      u_char *key_info;
 +      u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
 +      u_char shift_info, offset;
 +      int ret = 0;
 +
 +      if (!synth)
 +              return 0;
 +
 +      spin_lock_irqsave(&speakup_info.spinlock, flags);
 +      tty = vc->port.tty;
 +      if (type >= 0xf0)
 +              type -= 0xf0;
 +      if (type == KT_PAD &&
 +          (vt_get_leds(fg_console, VC_NUMLOCK))) {
 +              if (up_flag) {
 +                      spk_keydown = 0;
 +                      goto out;
 +              }
 +              value = pad_chars[value];
 +              spk_lastkey = value;
 +              spk_keydown++;
 +              spk_parked &= 0xfe;
 +              goto no_map;
 +      }
 +      if (keycode >= MAX_KEY)
 +              goto no_map;
 +      key_info = spk_our_keys[keycode];
 +      if (!key_info)
 +              goto no_map;
 +      /* Check valid read all mode keys */
 +      if ((cursor_track == read_all_mode) && (!up_flag)) {
 +              switch (value) {
 +              case KVAL(K_DOWN):
 +              case KVAL(K_UP):
 +              case KVAL(K_LEFT):
 +              case KVAL(K_RIGHT):
 +              case KVAL(K_PGUP):
 +              case KVAL(K_PGDN):
 +                      break;
 +              default:
 +                      stop_read_all(vc);
 +                      break;
 +              }
 +      }
 +      shift_info = (shift_state & 0x0f) + key_speakup;
 +      offset = spk_shift_table[shift_info];
 +      if (offset) {
 +              new_key = key_info[offset];
 +              if (new_key) {
 +                      ret = 1;
 +                      if (new_key == SPK_KEY) {
 +                              if (!spk_key_locked)
 +                                      key_speakup = (up_flag) ? 0 : 16;
 +                              if (up_flag || spk_killed)
 +                                      goto out;
 +                              spk_shut_up &= 0xfe;
 +                              spk_do_flush();
 +                              goto out;
 +                      }
 +                      if (up_flag)
 +                              goto out;
 +                      if (last_keycode == keycode &&
 +                          time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
 +                              spk_close_press = 1;
 +                              offset = spk_shift_table[shift_info + 32];
 +                              /* double press? */
 +                              if (offset && key_info[offset])
 +                                      new_key = key_info[offset];
 +                      }
 +                      last_keycode = keycode;
 +                      last_spk_jiffy = jiffies;
 +                      type = KT_SPKUP;
 +                      value = new_key;
 +              }
 +      }
 +no_map:
 +      if (type == KT_SPKUP && !spk_special_handler) {
 +              do_spkup(vc, new_key);
 +              spk_close_press = 0;
 +              ret = 1;
 +              goto out;
 +      }
 +      if (up_flag || spk_killed || type == KT_SHIFT)
 +              goto out;
 +      spk_shut_up &= 0xfe;
 +      kh = (value == KVAL(K_DOWN)) ||
 +          (value == KVAL(K_UP)) ||
 +          (value == KVAL(K_LEFT)) ||
 +          (value == KVAL(K_RIGHT));
 +      if ((cursor_track != read_all_mode) || !kh)
 +              if (!spk_no_intr)
 +                      spk_do_flush();
 +      if (spk_special_handler) {
 +              if (type == KT_SPEC && value == 1) {
 +                      value = '\n';
 +                      type = KT_LATIN;
 +              } else if (type == KT_LETTER) {
 +                      type = KT_LATIN;
 +              } else if (value == 0x7f) {
 +                      value = 8;      /* make del = backspace */
 +              }
 +              ret = (*spk_special_handler) (vc, type, value, keycode);
 +              spk_close_press = 0;
 +              if (ret < 0)
 +                      bleep(9);
 +              goto out;
 +      }
 +      last_keycode = 0;
 +out:
 +      spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 +      return ret;
 +}
 +
 +static int keyboard_notifier_call(struct notifier_block *nb,
 +                                unsigned long code, void *_param)
 +{
 +      struct keyboard_notifier_param *param = _param;
 +      struct vc_data *vc = param->vc;
 +      int up = !param->down;
 +      int ret = NOTIFY_OK;
 +      static int keycode;     /* to hold the current keycode */
 +
 +      in_keyboard_notifier = 1;
 +
 +      if (vc->vc_mode == KD_GRAPHICS)
 +              goto out;
 +
 +      /*
 +       * First, determine whether we are handling a fake keypress on
 +       * the current processor.  If we are, then return NOTIFY_OK,
 +       * to pass the keystroke up the chain.  This prevents us from
 +       * trying to take the Speakup lock while it is held by the
 +       * processor on which the simulated keystroke was generated.
 +       * Also, the simulated keystrokes should be ignored by Speakup.
 +       */
 +
 +      if (speakup_fake_key_pressed())
 +              goto out;
 +
 +      switch (code) {
 +      case KBD_KEYCODE:
 +              /* speakup requires keycode and keysym currently */
 +              keycode = param->value;
 +              break;
 +      case KBD_UNBOUND_KEYCODE:
 +              /* not used yet */
 +              break;
 +      case KBD_UNICODE:
 +              /* not used yet */
 +              break;
 +      case KBD_KEYSYM:
 +              if (speakup_key(vc, param->shift, keycode, param->value, up))
 +                      ret = NOTIFY_STOP;
 +              else if (KTYP(param->value) == KT_CUR)
 +                      ret = pre_handle_cursor(vc, KVAL(param->value), up);
 +              break;
 +      case KBD_POST_KEYSYM:{
 +                      unsigned char type = KTYP(param->value) - 0xf0;
 +                      unsigned char val = KVAL(param->value);
 +
 +                      switch (type) {
 +                      case KT_SHIFT:
 +                              do_handle_shift(vc, val, up);
 +                              break;
 +                      case KT_LATIN:
 +                      case KT_LETTER:
 +                              do_handle_latin(vc, val, up);
 +                              break;
 +                      case KT_CUR:
 +                              do_handle_cursor(vc, val, up);
 +                              break;
 +                      case KT_SPEC:
 +                              do_handle_spec(vc, val, up);
 +                              break;
 +                      }
 +                      break;
 +              }
 +      }
 +out:
 +      in_keyboard_notifier = 0;
 +      return ret;
 +}
 +
 +static int vt_notifier_call(struct notifier_block *nb,
 +                          unsigned long code, void *_param)
 +{
 +      struct vt_notifier_param *param = _param;
 +      struct vc_data *vc = param->vc;
 +
 +      switch (code) {
 +      case VT_ALLOCATE:
 +              if (vc->vc_mode == KD_TEXT)
 +                      speakup_allocate(vc, GFP_ATOMIC);
 +              break;
 +      case VT_DEALLOCATE:
 +              speakup_deallocate(vc);
 +              break;
 +      case VT_WRITE:
 +              if (param->c == '\b') {
 +                      speakup_bs(vc);
 +              } else {
 +                      u16 d = param->c;
 +
 +                      speakup_con_write(vc, &d, 1);
 +              }
 +              break;
 +      case VT_UPDATE:
 +              speakup_con_update(vc);
 +              break;
 +      }
 +      return NOTIFY_OK;
 +}
 +
 +/* called by: module_exit() */
 +static void __exit speakup_exit(void)
 +{
 +      int i;
 +
 +      unregister_keyboard_notifier(&keyboard_notifier_block);
 +      unregister_vt_notifier(&vt_notifier_block);
 +      speakup_unregister_devsynth();
 +      speakup_cancel_selection();
 +      speakup_cancel_paste();
 +      del_timer_sync(&cursor_timer);
 +      kthread_stop(speakup_task);
 +      speakup_task = NULL;
 +      mutex_lock(&spk_mutex);
 +      synth_release();
 +      mutex_unlock(&spk_mutex);
 +      spk_ttyio_unregister_ldisc();
 +
 +      speakup_kobj_exit();
 +
 +      for (i = 0; i < MAX_NR_CONSOLES; i++)
 +              kfree(speakup_console[i]);
 +
 +      speakup_remove_virtual_keyboard();
 +
 +      for (i = 0; i < MAXVARS; i++)
 +              speakup_unregister_var(i);
 +
 +      for (i = 0; i < 256; i++) {
 +              if (spk_characters[i] != spk_default_chars[i])
 +                      kfree(spk_characters[i]);
 +      }
 +
 +      spk_free_user_msgs();
 +}
 +
 +/* call by: module_init() */
 +static int __init speakup_init(void)
 +{
 +      int i;
 +      long err = 0;
 +      struct vc_data *vc = vc_cons[fg_console].d;
 +      struct var_t *var;
 +
 +      /* These first few initializations cannot fail. */
 +      spk_initialize_msgs();  /* Initialize arrays for i18n. */
 +      spk_reset_default_chars();
 +      spk_reset_default_chartab();
 +      spk_strlwr(synth_name);
 +      spk_vars[0].u.n.high = vc->vc_cols;
 +      for (var = spk_vars; var->var_id != MAXVARS; var++)
 +              speakup_register_var(var);
 +      for (var = synth_time_vars;
 +           (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
 +              speakup_register_var(var);
 +      for (i = 1; spk_punc_info[i].mask != 0; i++)
 +              spk_set_mask_bits(NULL, i, 2);
 +
 +      spk_set_key_info(spk_key_defaults, spk_key_buf);
 +
 +      /* From here on out, initializations can fail. */
 +      err = speakup_add_virtual_keyboard();
 +      if (err)
 +              goto error_virtkeyboard;
 +
 +      for (i = 0; i < MAX_NR_CONSOLES; i++)
 +              if (vc_cons[i].d) {
 +                      err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
 +                      if (err)
 +                              goto error_kobjects;
 +              }
 +
 +      if (spk_quiet_boot)
 +              spk_shut_up |= 0x01;
 +
 +      err = speakup_kobj_init();
 +      if (err)
 +              goto error_kobjects;
 +
 +      spk_ttyio_register_ldisc();
 +      synth_init(synth_name);
 +      speakup_register_devsynth();
 +      /*
 +       * register_devsynth might fail, but this error is not fatal.
 +       * /dev/synth is an extra feature; the rest of Speakup
 +       * will work fine without it.
 +       */
 +
 +      err = register_keyboard_notifier(&keyboard_notifier_block);
 +      if (err)
 +              goto error_kbdnotifier;
 +      err = register_vt_notifier(&vt_notifier_block);
 +      if (err)
 +              goto error_vtnotifier;
 +
 +      speakup_task = kthread_create(speakup_thread, NULL, "speakup");
 +
 +      if (IS_ERR(speakup_task)) {
 +              err = PTR_ERR(speakup_task);
 +              goto error_task;
 +      }
 +
 +      set_user_nice(speakup_task, 10);
 +      wake_up_process(speakup_task);
 +
 +      pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
 +      pr_info("synth name on entry is: %s\n", synth_name);
 +      goto out;
 +
 +error_task:
 +      unregister_vt_notifier(&vt_notifier_block);
 +
 +error_vtnotifier:
 +      unregister_keyboard_notifier(&keyboard_notifier_block);
 +      del_timer(&cursor_timer);
 +
 +error_kbdnotifier:
 +      speakup_unregister_devsynth();
 +      mutex_lock(&spk_mutex);
 +      synth_release();
 +      mutex_unlock(&spk_mutex);
 +      speakup_kobj_exit();
 +
 +error_kobjects:
 +      for (i = 0; i < MAX_NR_CONSOLES; i++)
 +              kfree(speakup_console[i]);
 +
 +      speakup_remove_virtual_keyboard();
 +
 +error_virtkeyboard:
 +      for (i = 0; i < MAXVARS; i++)
 +              speakup_unregister_var(i);
 +
 +      for (i = 0; i < 256; i++) {
 +              if (spk_characters[i] != spk_default_chars[i])
 +                      kfree(spk_characters[i]);
 +      }
 +
 +      spk_free_user_msgs();
 +
 +out:
 +      return err;
 +}
 +
 +module_init(speakup_init);
 +module_exit(speakup_exit);
index 07b7b6b05b8b2dcfc511729475b5c1ea0b35f61b,1ed3d354e16dec83ef1fbf5573b5b48c9794ad61..3aa29d201f54d38e1d24f63b883679d4a50ffa9a
@@@ -9,7 -9,6 +9,7 @@@
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/of_device.h>
 +#include <linux/pm_opp.h>
  #include <linux/platform_device.h>
  #include <linux/pm_runtime.h>
  #include <linux/pm_wakeirq.h>
  #define DEFAULT_IO_MACRO_IO2_IO3_MASK         GENMASK(15, 4)
  #define IO_MACRO_IO2_IO3_SWAP         0x4640
  
 -#ifdef CONFIG_CONSOLE_POLL
 -#define CONSOLE_RX_BYTES_PW 1
 -#else
 -#define CONSOLE_RX_BYTES_PW 4
 -#endif
 +/* We always configure 4 bytes per FIFO word */
 +#define BYTES_PER_FIFO_WORD           4
 +
 +struct qcom_geni_private_data {
 +      /* NOTE: earlycon port will have NULL here */
 +      struct uart_driver *drv;
 +
 +      u32 poll_cached_bytes;
 +      unsigned int poll_cached_bytes_cnt;
 +
 +      u32 write_cached_bytes;
 +      unsigned int write_cached_bytes_cnt;
 +};
  
  struct qcom_geni_serial_port {
        struct uart_port uport;
        bool setup;
        int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
        unsigned int baud;
 -      unsigned int tx_bytes_pw;
 -      unsigned int rx_bytes_pw;
        void *rx_fifo;
        u32 loopback;
        bool brk;
        int wakeup_irq;
        bool rx_tx_swap;
        bool cts_rts_swap;
 +
 +      struct qcom_geni_private_data private_data;
  };
  
  static const struct uart_ops qcom_geni_console_pops;
@@@ -272,9 -263,8 +272,9 @@@ static bool qcom_geni_serial_poll_bit(s
        unsigned int baud;
        unsigned int fifo_bits;
        unsigned long timeout_us = 20000;
 +      struct qcom_geni_private_data *private_data = uport->private_data;
  
 -      if (uport->private_data) {
 +      if (private_data->drv) {
                port = to_dev_port(uport, uport);
                baud = port->baud;
                if (!baud)
@@@ -340,42 -330,23 +340,42 @@@ static void qcom_geni_serial_abort_rx(s
  }
  
  #ifdef CONFIG_CONSOLE_POLL
 +
  static int qcom_geni_serial_get_char(struct uart_port *uport)
  {
 -      u32 rx_fifo;
 +      struct qcom_geni_private_data *private_data = uport->private_data;
        u32 status;
 +      u32 word_cnt;
 +      int ret;
 +
 +      if (!private_data->poll_cached_bytes_cnt) {
 +              status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
 +              writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
 +
 +              status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
 +              writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
 +
 +              status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
 +              word_cnt = status & RX_FIFO_WC_MSK;
 +              if (!word_cnt)
 +                      return NO_POLL_CHAR;
  
 -      status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
 -      writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR);
 +              if (word_cnt == 1 && (status & RX_LAST))
 +                      private_data->poll_cached_bytes_cnt =
 +                              (status & RX_LAST_BYTE_VALID_MSK) >>
 +                              RX_LAST_BYTE_VALID_SHFT;
 +              else
 +                      private_data->poll_cached_bytes_cnt = 4;
  
 -      status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
 -      writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR);
 +              private_data->poll_cached_bytes =
 +                      readl(uport->membase + SE_GENI_RX_FIFOn);
 +      }
  
 -      status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
 -      if (!(status & RX_FIFO_WC_MSK))
 -              return NO_POLL_CHAR;
 +      private_data->poll_cached_bytes_cnt--;
 +      ret = private_data->poll_cached_bytes & 0xff;
 +      private_data->poll_cached_bytes >>= 8;
  
 -      rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn);
 -      return rx_fifo & 0xff;
 +      return ret;
  }
  
  static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
  #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
  static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
  {
 -      writel(ch, uport->membase + SE_GENI_TX_FIFOn);
 +      struct qcom_geni_private_data *private_data = uport->private_data;
 +
 +      private_data->write_cached_bytes =
 +              (private_data->write_cached_bytes >> 8) | (ch << 24);
 +      private_data->write_cached_bytes_cnt++;
 +
 +      if (private_data->write_cached_bytes_cnt == BYTES_PER_FIFO_WORD) {
 +              writel(private_data->write_cached_bytes,
 +                     uport->membase + SE_GENI_TX_FIFOn);
 +              private_data->write_cached_bytes_cnt = 0;
 +      }
  }
  
  static void
  __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
                                 unsigned int count)
  {
 +      struct qcom_geni_private_data *private_data = uport->private_data;
 +
        int i;
        u32 bytes_to_send = count;
  
                                                        SE_GENI_M_IRQ_CLEAR);
                i += chars_to_write;
        }
 +
 +      if (private_data->write_cached_bytes_cnt) {
 +              private_data->write_cached_bytes >>= BITS_PER_BYTE *
 +                      (BYTES_PER_FIFO_WORD - private_data->write_cached_bytes_cnt);
 +              writel(private_data->write_cached_bytes,
 +                     uport->membase + SE_GENI_TX_FIFOn);
 +              private_data->write_cached_bytes_cnt = 0;
 +      }
 +
        qcom_geni_serial_poll_tx_done(uport);
  }
  
@@@ -528,7 -478,7 +528,7 @@@ static int handle_rx_console(struct uar
        tport = &uport->state->port;
        for (i = 0; i < bytes; ) {
                int c;
 -              int chunk = min_t(int, bytes - i, port->rx_bytes_pw);
 +              int chunk = min_t(int, bytes - i, BYTES_PER_FIFO_WORD);
  
                ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1);
                i += chunk;
@@@ -708,11 -658,11 +708,11 @@@ static void qcom_geni_serial_handle_rx(
  
        if (!word_cnt)
                return;
 -      total_bytes = port->rx_bytes_pw * (word_cnt - 1);
 +      total_bytes = BYTES_PER_FIFO_WORD * (word_cnt - 1);
        if (last_word_partial && last_word_byte_cnt)
                total_bytes += last_word_byte_cnt;
        else
 -              total_bytes += port->rx_bytes_pw;
 +              total_bytes += BYTES_PER_FIFO_WORD;
        port->handle_rx(uport, total_bytes, drop);
  }
  
@@@ -745,7 -695,7 +745,7 @@@ static void qcom_geni_serial_handle_tx(
        }
  
        avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
 -      avail *= port->tx_bytes_pw;
 +      avail *= BYTES_PER_FIFO_WORD;
  
        tail = xmit->tail;
        chunk = min(avail, pending);
                u8 buf[sizeof(u32)];
                int c;
  
-               memset(buf, 0, ARRAY_SIZE(buf));
+               memset(buf, 0, sizeof(buf));
 -              tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
 +              tx_bytes = min_t(size_t, remaining, BYTES_PER_FIFO_WORD);
  
                for (c = 0; c < tx_bytes ; c++) {
                        buf[c] = xmit->buf[tail++];
@@@ -886,6 -836,14 +886,6 @@@ static int qcom_geni_serial_port_setup(
        u32 proto;
        u32 pin_swap;
  
 -      if (uart_console(uport)) {
 -              port->tx_bytes_pw = 1;
 -              port->rx_bytes_pw = CONSOLE_RX_BYTES_PW;
 -      } else {
 -              port->tx_bytes_pw = 4;
 -              port->rx_bytes_pw = 4;
 -      }
 -
        proto = geni_se_read_proto(&port->se);
        if (proto != GENI_SE_UART) {
                dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
         */
        if (uart_console(uport))
                qcom_geni_serial_poll_tx_done(uport);
 -      geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw,
 -                                              false, true, false);
 -      geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw,
 -                                              false, false, true);
 +      geni_se_config_packing(&port->se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD,
 +                             false, true, true);
        geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
        geni_se_select_mode(&port->se, GENI_SE_FIFO);
        port->setup = true;
@@@ -985,7 -945,6 +985,7 @@@ static void qcom_geni_serial_set_termio
        struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
        unsigned long clk_rate;
        u32 ver, sampling_rate;
 +      unsigned int avg_bw_core;
  
        qcom_geni_serial_stop_rx(uport);
        /* baud rate */
                goto out_restart_rx;
  
        uport->uartclk = clk_rate;
 -      clk_set_rate(port->se.clk, clk_rate);
 +      dev_pm_opp_set_rate(uport->dev, clk_rate);
        ser_clk_cfg = SER_CLK_EN;
        ser_clk_cfg |= clk_div << CLK_DIV_SHFT;
  
 +      /*
 +       * Bump up BW vote on CPU and CORE path as driver supports FIFO mode
 +       * only.
 +       */
 +      avg_bw_core = (baud > 115200) ? Bps_to_icc(CORE_2X_50_MHZ)
 +                                              : GENI_DEFAULT_BW;
 +      port->se.icc_paths[GENI_TO_CORE].avg_bw = avg_bw_core;
 +      port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud);
 +      geni_icc_set_bw(&port->se);
 +
        /* parity */
        tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG);
        tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG);
@@@ -1172,14 -1121,6 +1172,14 @@@ static inline void qcom_geni_serial_ena
                                                      struct console *con) { }
  #endif
  
 +static int qcom_geni_serial_earlycon_exit(struct console *con)
 +{
 +      geni_remove_earlycon_icc_vote();
 +      return 0;
 +}
 +
 +static struct qcom_geni_private_data earlycon_private_data;
 +
  static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
                                                                const char *opt)
  {
        if (!uport->membase)
                return -EINVAL;
  
 +      uport->private_data = &earlycon_private_data;
 +
        memset(&se, 0, sizeof(se));
        se.base = uport->membase;
        if (geni_se_read_proto(&se) != GENI_SE_UART)
         */
        qcom_geni_serial_poll_tx_done(uport);
        qcom_geni_serial_abort_rx(uport);
 -      geni_se_config_packing(&se, BITS_PER_BYTE, 1, false, true, false);
 +      geni_se_config_packing(&se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD,
 +                             false, true, true);
        geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2);
        geni_se_select_mode(&se, GENI_SE_FIFO);
  
        writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
  
        dev->con->write = qcom_geni_serial_earlycon_write;
 +      dev->con->exit = qcom_geni_serial_earlycon_exit;
        dev->con->setup = NULL;
        qcom_geni_serial_enable_early_read(&se, dev->con);
  
@@@ -1291,14 -1228,11 +1291,14 @@@ static void qcom_geni_serial_pm(struct 
        if (old_state == UART_PM_STATE_UNDEFINED)
                old_state = UART_PM_STATE_OFF;
  
 -      if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
 +      if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) {
 +              geni_icc_enable(&port->se);
                geni_se_resources_on(&port->se);
 -      else if (new_state == UART_PM_STATE_OFF &&
 -                      old_state == UART_PM_STATE_ON)
 +      else if (new_state == UART_PM_STATE_OFF &&
 +                      old_state == UART_PM_STATE_ON) {
                geni_se_resources_off(&port->se);
 +              geni_icc_disable(&port->se);
 +      }
  }
  
  static const struct uart_ops qcom_geni_console_pops = {
@@@ -1396,17 -1330,6 +1396,17 @@@ static int qcom_geni_serial_probe(struc
                        return -ENOMEM;
        }
  
 +      ret = geni_icc_get(&port->se, NULL);
 +      if (ret)
 +              return ret;
 +      port->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
 +      port->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
 +
 +      /* Set BW for register access */
 +      ret = geni_icc_set_bw(&port->se);
 +      if (ret)
 +              return ret;
 +
        port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
                        "qcom_geni_serial_%s%d",
                        uart_console(uport) ? "console" : "uart", uport->line);
        if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
                port->cts_rts_swap = true;
  
 -      uport->private_data = drv;
 +      port->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se");
 +      if (IS_ERR(port->se.opp_table))
 +              return PTR_ERR(port->se.opp_table);
 +      /* OPP table is optional */
 +      ret = dev_pm_opp_of_add_table(&pdev->dev);
 +      if (!ret) {
 +              port->se.has_opp_table = true;
 +      } else if (ret != -ENODEV) {
 +              dev_err(&pdev->dev, "invalid OPP table in device tree\n");
 +              return ret;
 +      }
 +
 +      port->private_data.drv = drv;
 +      uport->private_data = &port->private_data;
        platform_set_drvdata(pdev, port);
        port->handle_rx = console ? handle_rx_console : handle_rx_uart;
  
        ret = uart_add_one_port(drv, uport);
        if (ret)
 -              return ret;
 +              goto err;
  
        irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
        ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
        if (ret) {
                dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
                uart_remove_one_port(drv, uport);
 -              return ret;
 +              goto err;
        }
  
        /*
                if (ret) {
                        device_init_wakeup(&pdev->dev, false);
                        uart_remove_one_port(drv, uport);
 -                      return ret;
 +                      goto err;
                }
        }
  
        return 0;
 +err:
 +      if (port->se.has_opp_table)
 +              dev_pm_opp_of_remove_table(&pdev->dev);
 +      dev_pm_opp_put_clkname(port->se.opp_table);
 +      return ret;
  }
  
  static int qcom_geni_serial_remove(struct platform_device *pdev)
  {
        struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
 -      struct uart_driver *drv = port->uport.private_data;
 +      struct uart_driver *drv = port->private_data.drv;
  
 +      if (port->se.has_opp_table)
 +              dev_pm_opp_of_remove_table(&pdev->dev);
 +      dev_pm_opp_put_clkname(port->se.opp_table);
        dev_pm_clear_wake_irq(&pdev->dev);
        device_init_wakeup(&pdev->dev, false);
        uart_remove_one_port(drv, &port->uport);
@@@ -1503,32 -1405,16 +1503,32 @@@ static int __maybe_unused qcom_geni_ser
  {
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
 +      struct qcom_geni_private_data *private_data = uport->private_data;
  
 -      return uart_suspend_port(uport->private_data, uport);
 +      /*
 +       * This is done so we can hit the lowest possible state in suspend
 +       * even with no_console_suspend
 +       */
 +      if (uart_console(uport)) {
 +              geni_icc_set_tag(&port->se, 0x3);
 +              geni_icc_set_bw(&port->se);
 +      }
 +      return uart_suspend_port(private_data->drv, uport);
  }
  
  static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
  {
 +      int ret;
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
 +      struct qcom_geni_private_data *private_data = uport->private_data;
  
 -      return uart_resume_port(uport->private_data, uport);
 +      ret = uart_resume_port(private_data->drv, uport);
 +      if (uart_console(uport)) {
 +              geni_icc_set_tag(&port->se, 0x7);
 +              geni_icc_set_bw(&port->se);
 +      }
 +      return ret;
  }
  
  static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
index f80199984ee0f666d42a2200a67caf0288fe6f37,a768069b0f9a4b3481ee8f9a80d5200889a4833e..0db53b5b3acf6b7d33338b659c81b586e841804f
@@@ -32,6 -32,7 +32,7 @@@
  #include <linux/tty.h>
  #include <linux/tty_flip.h>
  #include <linux/mm.h>
+ #include <linux/nospec.h>
  #include <linux/string.h>
  #include <linux/init.h>
  #include <linux/slab.h>
@@@ -1236,7 -1237,7 +1237,7 @@@ static void kbd_bh(unsigned long dummy
        }
  }
  
 -DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 +DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh);
  
  #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
      defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
@@@ -2019,7 -2020,7 +2020,7 @@@ int vt_do_kdgkb_ioctl(int cmd, struct k
                goto reterr;
        }
        kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-       i = kbs->kb_func;
+       i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC);
  
        switch (cmd) {
        case KDGKBSENT:
index 15e62a2e9b1b3fcd67b764ac5c736ec52c28af74,1058eaba308414cba45da67d22037900ca7a6368..c63e545fb1051bab5f55bf519a97942a0c1ac904
@@@ -302,14 -302,15 +302,15 @@@ sisusbcon_deinit(struct vc_data *c
  
  /* interface routine */
  static u8
- sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
-                           u8 blink, u8 underline, u8 reverse, u8 unused)
+ sisusbcon_build_attr(struct vc_data *c, u8 color, enum vc_intensity intensity,
+                           bool blink, bool underline, bool reverse,
+                           bool unused)
  {
        u8 attr = color;
  
        if (underline)
                attr = (attr & 0xf0) | c->vc_ulcolor;
-       else if (intensity == 0)
+       else if (intensity == VCI_HALF_BRIGHT)
                attr = (attr & 0xf0) | c->vc_halfcolor;
  
        if (reverse)
        if (blink)
                attr ^= 0x80;
  
-       if (intensity == 2)
+       if (intensity == VCI_BOLD)
                attr ^= 0x08;
  
        return attr;
@@@ -509,7 -510,7 +510,7 @@@ sisusbcon_switch(struct vc_data *c
        /* Restore the screen contents */
        memcpy((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, length);
  
 -      sisusb_copy_memory(sisusb, (char *)c->vc_origin,
 +      sisusb_copy_memory(sisusb, (u8 *)c->vc_origin,
                        sisusb_haddr(sisusb, c, 0, 0), length);
  
        mutex_unlock(&sisusb->lock);
@@@ -615,7 -616,7 +616,7 @@@ sisusbcon_blank(struct vc_data *c, int 
                sisusbcon_memsetw((u16 *)c->vc_origin,
                                c->vc_video_erase_char,
                                c->vc_screenbuf_size);
 -              sisusb_copy_memory(sisusb, (char *)c->vc_origin,
 +              sisusb_copy_memory(sisusb, (u8 *)c->vc_origin,
                                sisusb_haddr(sisusb, c, 0, 0),
                                c->vc_screenbuf_size);
                sisusb->con_blanked = 1;
@@@ -726,7 -727,7 +727,7 @@@ sisusbcon_cursor(struct vc_data *c, in
  
        baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2);
  
-       switch (c->vc_cursor_type & 0x0f) {
+       switch (CUR_SIZE(c->vc_cursor_type)) {
                case CUR_BLOCK:         from = 1;
                                        to   = c->vc_font.height;
                                        break;
@@@ -897,18 -898,18 +898,18 @@@ sisusbcon_scroll(struct vc_data *c, uns
  
        if (copyall)
                sisusb_copy_memory(sisusb,
 -                      (char *)c->vc_origin,
 +                      (u8 *)c->vc_origin,
                        sisusb_haddr(sisusb, c, 0, 0),
                        c->vc_screenbuf_size);
        else if (dir == SM_UP)
                sisusb_copy_memory(sisusb,
 -                      (char *)c->vc_origin + c->vc_screenbuf_size - delta,
 +                      (u8 *)c->vc_origin + c->vc_screenbuf_size - delta,
                        sisusb_haddr(sisusb, c, 0, 0) +
                                        c->vc_screenbuf_size - delta,
                        delta);
        else
                sisusb_copy_memory(sisusb,
 -                      (char *)c->vc_origin,
 +                      (u8 *)c->vc_origin,
                        sisusb_haddr(sisusb, c, 0, 0),
                        delta);
  
@@@ -1226,7 -1227,7 +1227,7 @@@ sisusbcon_font_set(struct vc_data *c, s
                sisusb->font_backup = vmalloc(array_size(charcount, 32));
  
        if (sisusb->font_backup) {
 -              memcpy(sisusb->font_backup, font->data, charcount * 32);
 +              memcpy(sisusb->font_backup, font->data, array_size(charcount, 32));
                sisusb->font_backup_size = charcount;
                sisusb->font_backup_height = font->height;
                sisusb->font_backup_512 = (charcount == 512) ? 1 : 0;
index df3c52d7215970a165d11d8251332de57cb72718,d9fa6b5317ab0c63bb4720f4100d4f41a59977e8..72f146d047d93f62542b941671a924b27f2dc3a8
@@@ -31,8 -31,6 +31,8 @@@
  #include <linux/linux_logo.h>
  #include <linux/font.h>
  
 +#define NEWPORT_LEN   0x10000
 +
  #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
  
  /* borrowed from fbcon.c */
@@@ -44,7 -42,6 +44,7 @@@
  static unsigned char *font_data[MAX_NR_CONSOLES];
  
  static struct newport_regs *npregs;
 +static unsigned long newport_addr;
  
  static int logo_active;
  static int topscan;
@@@ -362,12 -359,12 +362,12 @@@ static void newport_clear(struct vc_dat
  
        if (ystart < yend) {
                newport_clear_screen(sx << 3, ystart, xend, yend,
-                                    (vc->vc_color & 0xf0) >> 4);
+                                    (vc->state.color & 0xf0) >> 4);
        } else {
                newport_clear_screen(sx << 3, ystart, xend, 1023,
-                                    (vc->vc_color & 0xf0) >> 4);
+                                    (vc->state.color & 0xf0) >> 4);
                newport_clear_screen(sx << 3, 0, xend, yend,
-                                    (vc->vc_color & 0xf0) >> 4);
+                                    (vc->state.color & 0xf0) >> 4);
        }
  }
  
@@@ -591,11 -588,11 +591,11 @@@ static bool newport_scroll(struct vc_da
                        topscan = (topscan + (lines << 4)) & 0x3ff;
                        newport_clear_lines(vc->vc_rows - lines,
                                            vc->vc_rows - 1,
-                                           (vc->vc_color & 0xf0) >> 4);
+                                           (vc->state.color & 0xf0) >> 4);
                } else {
                        topscan = (topscan + (-lines << 4)) & 0x3ff;
                        newport_clear_lines(0, lines - 1,
-                                           (vc->vc_color & 0xf0) >> 4);
+                                           (vc->state.color & 0xf0) >> 4);
                }
                npregs->cset.topscan = (topscan - 1) & 0x3ff;
                return false;
@@@ -704,6 -701,7 +704,6 @@@ const struct consw newport_con = 
  static int newport_probe(struct gio_device *dev,
                         const struct gio_device_id *id)
  {
 -      unsigned long newport_addr;
        int err;
  
        if (!dev->resource.start)
                return -EBUSY; /* we only support one Newport as console */
  
        newport_addr = dev->resource.start + 0xF0000;
 -      if (!request_mem_region(newport_addr, 0x10000, "Newport"))
 +      if (!request_mem_region(newport_addr, NEWPORT_LEN, "Newport"))
                return -ENODEV;
  
        npregs = (struct newport_regs *)/* ioremap cannot fail */
        console_lock();
        err = do_take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
        console_unlock();
 +
 +      if (err) {
 +              iounmap((void *)npregs);
 +              release_mem_region(newport_addr, NEWPORT_LEN);
 +      }
        return err;
  }
  
@@@ -733,7 -726,6 +733,7 @@@ static void newport_remove(struct gio_d
  {
        give_up_console(&newport_con);
        iounmap((void *)npregs);
 +      release_mem_region(newport_addr, NEWPORT_LEN);
  }
  
  static struct gio_device_id newport_ids[] = {
index af9f5ab96f74ff8a0838efcbdf90ac2d6a578316,2997b29071721b52bd3580a423d7f38a6acede83..8a31fc2b2258a79c969d1913a7b629daa6983fc7
@@@ -639,7 -639,7 +639,7 @@@ static void fbcon_prepare_logo(struct v
                               GFP_KERNEL);
                if (save) {
                        int i = cols < new_cols ? cols : new_cols;
 -                      scr_memsetw(save, erase, logo_lines * new_cols * 2);
 +                      scr_memsetw(save, erase, array3_size(logo_lines, new_cols, 2));
                        r = q - step;
                        for (cnt = 0; cnt < logo_lines; cnt++, r += i)
                                scr_memcpyw(save + cnt * new_cols, r, 2 * i);
                }
                if (!save) {
                        int lines;
-                       if (vc->vc_y + logo_lines >= rows)
-                               lines = rows - vc->vc_y - 1;
+                       if (vc->state.y + logo_lines >= rows)
+                               lines = rows - vc->state.y - 1;
                        else
                                lines = logo_lines;
-                       vc->vc_y += lines;
+                       vc->state.y += lines;
                        vc->vc_pos += lines * vc->vc_size_row;
                }
        }
                q = (unsigned short *) (vc->vc_origin +
                                        vc->vc_size_row *
                                        rows);
 -              scr_memcpyw(q, save, logo_lines * new_cols * 2);
 +              scr_memcpyw(q, save, array3_size(logo_lines, new_cols, 2));
-               vc->vc_y += logo_lines;
+               vc->state.y += logo_lines;
                vc->vc_pos += logo_lines * vc->vc_size_row;
                kfree(save);
        }
@@@ -1393,7 -1393,7 +1393,7 @@@ static void fbcon_cursor(struct vc_dat
        if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
                return;
  
-       if (vc->vc_cursor_type & 0x10)
+       if (vc->vc_cursor_type & CUR_SW)
                fbcon_del_cursor_timer(info);
        else
                fbcon_add_cursor_timer(info);
This page took 0.275546 seconds and 4 git commands to generate.